Implement new PlayerFilter method, async-friendly chunk trackers

This commit is contained in:
fullwall 2023-06-25 21:58:09 +08:00
parent a2d7284fbc
commit 46f4444c10
27 changed files with 196 additions and 164 deletions

View File

@ -215,12 +215,7 @@ public class EventListen implements Listener {
void loadNPCs(ChunkEvent event) { void loadNPCs(ChunkEvent event) {
ChunkCoord coord = new ChunkCoord(event.getChunk()); ChunkCoord coord = new ChunkCoord(event.getChunk());
Runnable runnable = new Runnable() { Runnable runnable = () -> respawnAllFromCoord(coord, event);
@Override
public void run() {
respawnAllFromCoord(coord, event);
}
};
if (Messaging.isDebugging() && Setting.DEBUG_CHUNK_LOADS.asBoolean() && toRespawn.containsKey(coord)) { if (Messaging.isDebugging() && Setting.DEBUG_CHUNK_LOADS.asBoolean() && toRespawn.containsKey(coord)) {
new Exception("CITIZENS CHUNK LOAD DEBUG " + coord).printStackTrace(); new Exception("CITIZENS CHUNK LOAD DEBUG " + coord).printStackTrace();
} }

View File

@ -218,6 +218,9 @@ public class Settings {
NPC_COMMAND_ON_GLOBAL_COOLDOWN_MESSAGE("npc.commands.error-messages.on-global-cooldown", NPC_COMMAND_ON_GLOBAL_COOLDOWN_MESSAGE("npc.commands.error-messages.on-global-cooldown",
"Please wait for {minutes} minutes and {seconds_over} seconds."), "Please wait for {minutes} minutes and {seconds_over} seconds."),
NPC_COST("The default cost to create an NPC", "economy.npc.cost", 100D), NPC_COST("The default cost to create an NPC", "economy.npc.cost", 100D),
NPC_SKIN_FETCH_DEFAULT(
"Whether to try and look for the player skin for all new NPCs. If this is set to false and you create an NPC named Dinnerbone, the NPC will have the default (steve/alex/...) skin rather than trying to fetch the Dinnerbone skin.",
"npc.skins.try-fetch-default-skin", true),
NPC_SKIN_RETRY_DELAY("How long before retrying skin requests (typically due to Mojang rate limiting)", NPC_SKIN_RETRY_DELAY("How long before retrying skin requests (typically due to Mojang rate limiting)",
"npc.skins.retry-delay", "5s"), "npc.skins.retry-delay", "5s"),
NPC_SKIN_ROTATION_UPDATE_DEGREES("npc.skins.rotation-update-degrees", 90f), NPC_SKIN_ROTATION_UPDATE_DEGREES("npc.skins.rotation-update-degrees", 90f),

View File

@ -537,9 +537,9 @@ public class NPCCommands {
} }
if (args.argsLength() == 4) { if (args.argsLength() == 4) {
commands.setCost(args.getDouble(2), args.getInteger(3)); commands.setCost(args.getDouble(2), args.getInteger(3));
Messaging.sendTr(sender, Messages.COMMAND_INDIVIDUAL_COST_SET, args.getDouble(2) == -1 ? "-1 (default)" : args.getDouble(2), args.getInteger(3)); Messaging.sendTr(sender, Messages.COMMAND_INDIVIDUAL_COST_SET,
} args.getDouble(2) == -1 ? "-1 (default)" : args.getDouble(2), args.getInteger(3));
else { } else {
commands.setCost(args.getDouble(2)); commands.setCost(args.getDouble(2));
Messaging.sendTr(sender, Messages.COMMAND_COST_SET, args.getDouble(2)); Messaging.sendTr(sender, Messages.COMMAND_COST_SET, args.getDouble(2));
} }
@ -549,9 +549,9 @@ public class NPCCommands {
} }
if (args.argsLength() == 4) { if (args.argsLength() == 4) {
commands.setExperienceCost(args.getInteger(2), args.getInteger(3)); commands.setExperienceCost(args.getInteger(2), args.getInteger(3));
Messaging.sendTr(sender, Messages.COMMAND_INDIVIDUAL_EXPERIENCE_COST_SET, args.getInteger(2) == -1 ? "-1 (default)" : args.getInteger(2), args.getInteger(3)); Messaging.sendTr(sender, Messages.COMMAND_INDIVIDUAL_EXPERIENCE_COST_SET,
} args.getInteger(2) == -1 ? "-1 (default)" : args.getInteger(2), args.getInteger(3));
else { } else {
commands.setExperienceCost(args.getInteger(2)); commands.setExperienceCost(args.getInteger(2));
Messaging.sendTr(sender, Messages.COMMAND_EXPERIENCE_COST_SET, args.getInteger(2)); Messaging.sendTr(sender, Messages.COMMAND_EXPERIENCE_COST_SET, args.getInteger(2));
} }
@ -569,9 +569,9 @@ public class NPCCommands {
throw new CommandException(CommandMessages.MUST_BE_INGAME); throw new CommandException(CommandMessages.MUST_BE_INGAME);
if (args.argsLength() == 2) { if (args.argsLength() == 2) {
InventoryMenu.createSelfRegistered(new ItemRequirementGUI(commands)).present(((Player) sender)); InventoryMenu.createSelfRegistered(new ItemRequirementGUI(commands)).present(((Player) sender));
} } else {
else { InventoryMenu.createSelfRegistered(new ItemRequirementGUI(commands, args.getInteger(2)))
InventoryMenu.createSelfRegistered(new ItemRequirementGUI(commands, args.getInteger(2))).present(((Player) sender)); .present(((Player) sender));
} }
} else if (action.equalsIgnoreCase("errormsg")) { } else if (action.equalsIgnoreCase("errormsg")) {
CommandTraitError which = Util.matchEnum(CommandTraitError.values(), args.getString(2)); CommandTraitError which = Util.matchEnum(CommandTraitError.values(), args.getString(2));
@ -2784,6 +2784,8 @@ public class NPCCommands {
final SkinTrait trait = npc.getOrAddTrait(SkinTrait.class); final SkinTrait trait = npc.getOrAddTrait(SkinTrait.class);
if (args.hasFlag('c')) { if (args.hasFlag('c')) {
trait.clearTexture(); trait.clearTexture();
Messaging.sendTr(sender, Messages.SKIN_CLEARED);
return;
} else if (url != null || file != null) { } else if (url != null || file != null) {
Messaging.sendTr(sender, Messages.FETCHING_SKIN, file); Messaging.sendTr(sender, Messages.FETCHING_SKIN, file);
Bukkit.getScheduler().runTaskAsynchronously(CitizensAPI.getPlugin(), () -> { Bukkit.getScheduler().runTaskAsynchronously(CitizensAPI.getPlugin(), () -> {

View File

@ -236,7 +236,7 @@ public class CitizensNPC extends AbstractNPC {
boolean wasSpawned = entityController == null ? false : isSpawned(); boolean wasSpawned = entityController == null ? false : isSpawned();
Location prev = null; Location prev = null;
if (wasSpawned) { if (wasSpawned) {
prev = getEntity().getLocation(CACHE_LOCATION); prev = getEntity().getLocation();
despawn(DespawnReason.PENDING_RESPAWN); despawn(DespawnReason.PENDING_RESPAWN);
} }
PacketNPC packet = getTraitNullable(PacketNPC.class); PacketNPC packet = getTraitNullable(PacketNPC.class);
@ -446,7 +446,7 @@ public class CitizensNPC extends AbstractNPC {
if (hasTrait(SitTrait.class) && getOrAddTrait(SitTrait.class).isSitting()) { if (hasTrait(SitTrait.class) && getOrAddTrait(SitTrait.class).isSitting()) {
getOrAddTrait(SitTrait.class).setSitting(location); getOrAddTrait(SitTrait.class).setSitting(location);
} }
Location npcLoc = getEntity().getLocation(CACHE_LOCATION); Location npcLoc = getEntity().getLocation();
if (isSpawned() && npcLoc.getWorld() == location.getWorld()) { if (isSpawned() && npcLoc.getWorld() == location.getWorld()) {
if (npcLoc.distance(location) < 1) { if (npcLoc.distance(location) < 1) {
NMS.setHeadYaw(getEntity(), location.getYaw()); NMS.setHeadYaw(getEntity(), location.getYaw());
@ -625,7 +625,6 @@ public class CitizensNPC extends AbstractNPC {
} }
} }
private static final Location CACHE_LOCATION = new Location(null, 0, 0, 0);
private static final SetMultimap<ChunkCoord, NPC> CHUNK_LOADERS = HashMultimap.create(); private static final SetMultimap<ChunkCoord, NPC> CHUNK_LOADERS = HashMultimap.create();
private static boolean SUPPORT_GLOWING = true; private static boolean SUPPORT_GLOWING = true;
private static boolean SUPPORT_NODAMAGE_TICKS = true; private static boolean SUPPORT_NODAMAGE_TICKS = true;

View File

@ -27,6 +27,7 @@ import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.npc.NPCDataStore; import net.citizensnpcs.api.npc.NPCDataStore;
import net.citizensnpcs.api.npc.NPCRegistry; import net.citizensnpcs.api.npc.NPCRegistry;
import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.util.RemoveReason;
import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.trait.ArmorStandTrait; import net.citizensnpcs.trait.ArmorStandTrait;
import net.citizensnpcs.trait.LookClose; import net.citizensnpcs.trait.LookClose;
@ -118,7 +119,7 @@ public class CitizensNPCRegistry implements NPCRegistry {
npc.despawn(DespawnReason.REMOVAL); npc.despawn(DespawnReason.REMOVAL);
for (Trait t : npc.getTraits()) { for (Trait t : npc.getTraits()) {
HandlerList.unregisterAll(t); HandlerList.unregisterAll(t);
t.onRemove(); t.onRemove(RemoveReason.REMOVAL);
} }
itr.remove(); itr.remove();
if (saves != null) { if (saves != null) {

View File

@ -79,7 +79,7 @@ public class AStarNavigationStrategy extends AbstractPathStrategy {
public boolean update() { public boolean update() {
if (plan == null) { if (plan == null) {
if (planner == null) { if (planner == null) {
planner = new AStarPlanner(params, npc.getEntity().getLocation(NPC_LOCATION), destination); planner = new AStarPlanner(params, npc.getEntity().getLocation(), destination);
} }
CancelReason reason = planner.tick(Setting.ASTAR_ITERATIONS_PER_TICK.asInt(), CancelReason reason = planner.tick(Setting.ASTAR_ITERATIONS_PER_TICK.asInt(),
Setting.MAXIMUM_ASTAR_ITERATIONS.asInt()); Setting.MAXIMUM_ASTAR_ITERATIONS.asInt());
@ -97,9 +97,9 @@ public class AStarNavigationStrategy extends AbstractPathStrategy {
if (vector == null) { if (vector == null) {
vector = plan.getCurrentVector(); vector = plan.getCurrentVector();
} }
Location loc = npc.getEntity().getLocation(NPC_LOCATION); Location loc = npc.getEntity().getLocation();
/* Proper door movement - gets stuck on corners at times /* Proper door movement - gets stuck on corners at times
Block block = currLoc.getWorld().getBlockAt(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); Block block = currLoc.getWorld().getBlockAt(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ());
if (MinecraftBlockExaminer.isDoor(block.getType())) { if (MinecraftBlockExaminer.isDoor(block.getType())) {
Door door = (Door) block.getState().getData(); Door door = (Door) block.getState().getData();
@ -131,7 +131,7 @@ public class AStarNavigationStrategy extends AbstractPathStrategy {
NMS.setDestination(npc.getEntity(), dest.getX(), dest.getY(), dest.getZ(), params.speed()); NMS.setDestination(npc.getEntity(), dest.getX(), dest.getY(), dest.getZ(), params.speed());
} else { } else {
Vector dir = dest.toVector().subtract(npc.getEntity().getLocation().toVector()).normalize().multiply(0.2); Vector dir = dest.toVector().subtract(npc.getEntity().getLocation().toVector()).normalize().multiply(0.2);
boolean liquidOrInLiquid = MinecraftBlockExaminer.isLiquidOrInLiquid(NPC_LOCATION.getBlock()); 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)); dir.add(new Vector(0, 0.75, 0));
} }
@ -201,5 +201,4 @@ public class AStarNavigationStrategy extends AbstractPathStrategy {
} }
private static final AStarMachine<VectorNode, Path> ASTAR = AStarMachine.createWithDefaultStorage(); private static final AStarMachine<VectorNode, Path> ASTAR = AStarMachine.createWithDefaultStorage();
private static final Location NPC_LOCATION = new Location(null, 0, 0, 0);
} }

View File

@ -486,7 +486,7 @@ public class CitizensNavigator implements Navigator, Runnable {
private boolean updateStationaryStatus() { private boolean updateStationaryStatus() {
if (localParams.stationaryTicks() < 0) if (localParams.stationaryTicks() < 0)
return false; return false;
Location current = npc.getEntity().getLocation(STATIONARY_LOCATION); Location current = npc.getEntity().getLocation();
if (!SpigotUtil.checkYSafe(current.getY(), current.getWorld())) { if (!SpigotUtil.checkYSafe(current.getY(), current.getWorld())) {
stopNavigating(CancelReason.STUCK); stopNavigating(CancelReason.STUCK);
return true; return true;
@ -534,7 +534,6 @@ public class CitizensNavigator implements Navigator, Runnable {
} }
} }
private static final Location STATIONARY_LOCATION = new Location(null, 0, 0, 0);
private static boolean SUPPORT_CHUNK_TICKETS = true; private static boolean SUPPORT_CHUNK_TICKETS = true;
private static int UNINITIALISED_SPEED = Integer.MIN_VALUE; private static int UNINITIALISED_SPEED = Integer.MIN_VALUE;
} }

View File

@ -136,7 +136,7 @@ public class FlyingAStarNavigationStrategy extends AbstractPathStrategy {
if (getCancelReason() != null || plan == null || plan.isComplete()) { if (getCancelReason() != null || plan == null || plan.isComplete()) {
return true; return true;
} }
Location current = npc.getEntity().getLocation(NPC_LOCATION); Location current = npc.getEntity().getLocation();
if (current.toVector().distance(vector) <= parameters.distanceMargin()) { if (current.toVector().distance(vector) <= parameters.distanceMargin()) {
plan.update(npc); plan.update(npc);
if (plan.isComplete()) { if (plan.isComplete()) {
@ -184,5 +184,4 @@ public class FlyingAStarNavigationStrategy extends AbstractPathStrategy {
} }
private static final AStarMachine<VectorNode, Path> ASTAR = AStarMachine.createWithDefaultStorage(); private static final AStarMachine<VectorNode, Path> ASTAR = AStarMachine.createWithDefaultStorage();
private static final Location NPC_LOCATION = new Location(null, 0, 0, 0);
} }

View File

@ -82,7 +82,7 @@ public class MCNavigationStrategy extends AbstractPathStrategy {
if (getCancelReason() != null) if (getCancelReason() != null)
return true; return true;
boolean wasFinished = navigator.update(); boolean wasFinished = navigator.update();
Location loc = entity.getLocation(HANDLE_LOCATION); Location loc = entity.getLocation();
double dX = target.getX() - loc.getX(); double dX = target.getX() - loc.getX();
double dZ = target.getZ() - loc.getZ(); double dZ = target.getZ() - loc.getZ();
double dY = target.getY() - loc.getY(); double dY = target.getY() - loc.getY();
@ -107,6 +107,4 @@ public class MCNavigationStrategy extends AbstractPathStrategy {
boolean update(); boolean update();
} }
private static final Location HANDLE_LOCATION = new Location(null, 0, 0, 0);
} }

View File

@ -55,7 +55,7 @@ public class MCTargetStrategy implements PathStrategy, EntityTarget {
} }
private double distance() { private double distance() {
return handle.getLocation(HANDLE_LOCATION).distance(target.getLocation(TARGET_LOCATION)); return handle.getLocation().distance(target.getLocation());
} }
@Override @Override
@ -292,6 +292,4 @@ public class MCTargetStrategy implements PathStrategy, EntityTarget {
return false; return false;
} }
}; };
private static final Location HANDLE_LOCATION = new Location(null, 0, 0, 0);
private static final Location TARGET_LOCATION = new Location(null, 0, 0, 0);
} }

View File

@ -61,7 +61,7 @@ public class StraightLineNavigationStrategy extends AbstractPathStrategy {
if (getCancelReason() != null || npc.getStoredLocation().getWorld() != destination.getWorld()) { if (getCancelReason() != null || npc.getStoredLocation().getWorld() != destination.getWorld()) {
return true; return true;
} }
Location currLoc = npc.getEntity().getLocation(NPC_LOCATION); Location currLoc = npc.getEntity().getLocation();
if (currLoc.distance(destination) <= params.distanceMargin()) { if (currLoc.distance(destination) <= params.distanceMargin()) {
return true; return true;
} }
@ -127,6 +127,4 @@ public class StraightLineNavigationStrategy extends AbstractPathStrategy {
} }
return false; return false;
} }
private static final Location NPC_LOCATION = new Location(null, 0, 0, 0);
} }

View File

@ -6,7 +6,6 @@ import java.util.Map;
import java.util.UUID; import java.util.UUID;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -165,7 +164,7 @@ public class SkinPacketTracker {
public void updateNearbyViewers(double radius) { public void updateNearbyViewers(double radius) {
Player from = entity.getBukkitEntity(); Player from = entity.getBukkitEntity();
CitizensAPI.getLocationLookup().getNearbyPlayers(from.getLocation(CACHE_LOCATION), radius).forEach(player -> { CitizensAPI.getLocationLookup().getNearbyPlayers(from.getLocation(), radius).forEach(player -> {
if (!player.canSee(from) || player.hasMetadata("NPC")) if (!player.canSee(from) || player.hasMetadata("NPC"))
return; return;
updateViewer(player); updateViewer(player);
@ -228,7 +227,6 @@ public class SkinPacketTracker {
} }
} }
private static final Location CACHE_LOCATION = new Location(null, 0, 0, 0);
private static PlayerListener LISTENER; private static PlayerListener LISTENER;
private static final int PACKET_DELAY_REMOVE = 2; private static final int PACKET_DELAY_REMOVE = 2;
private static final TabListRemover TAB_LIST_REMOVER = new TabListRemover(); private static final TabListRemover TAB_LIST_REMOVER = new TabListRemover();

View File

@ -72,8 +72,8 @@ public class SkinUpdateTracker {
if (!player.getWorld().equals(entity.getWorld())) if (!player.getWorld().equals(entity.getWorld()))
return false; return false;
Location playerLoc = player.getLocation(CACHE_LOCATION); Location playerLoc = player.getLocation();
Location skinLoc = entity.getLocation(NPC_LOCATION); Location skinLoc = entity.getLocation();
if (playerLoc.distance(skinLoc) > Setting.NPC_SKIN_VIEW_DISTANCE.asDouble()) if (playerLoc.distance(skinLoc) > Setting.NPC_SKIN_VIEW_DISTANCE.asDouble())
return false; return false;
@ -281,12 +281,12 @@ public class SkinUpdateTracker {
return; return;
double viewDistance = Setting.NPC_SKIN_VIEW_DISTANCE.asDouble(); double viewDistance = Setting.NPC_SKIN_VIEW_DISTANCE.asDouble();
Location location = entity.getLocation(NPC_LOCATION); Location location = entity.getLocation();
List<Player> players = entity.getWorld().getPlayers(); List<Player> players = entity.getWorld().getPlayers();
for (Player player : players) { for (Player player : players) {
if (player.hasMetadata("NPC")) if (player.hasMetadata("NPC"))
continue; continue;
Location ploc = player.getLocation(CACHE_LOCATION); Location ploc = player.getLocation();
if (ploc.getWorld() != location.getWorld()) if (ploc.getWorld() != location.getWorld())
continue; continue;
if (ploc.distance(location) > viewDistance) if (ploc.distance(location) > viewDistance)
@ -410,7 +410,7 @@ public class SkinUpdateTracker {
} }
boolean shouldUpdate(Player player) { boolean shouldUpdate(Player player) {
Location currentLoc = player.getLocation(CACHE_LOCATION); Location currentLoc = player.getLocation();
// make sure player is in same world // make sure player is in same world
if (!currentLoc.getWorld().equals(this.location.getWorld())) { if (!currentLoc.getWorld().equals(this.location.getWorld())) {
@ -461,8 +461,6 @@ public class SkinUpdateTracker {
} }
} }
private static final Location CACHE_LOCATION = new Location(null, 0, 0, 0);
private static final float FIELD_OF_VIEW = 70F; private static final float FIELD_OF_VIEW = 70F;
private static final int MOVEMENT_SKIN_UPDATE_DISTANCE = 25; private static final int MOVEMENT_SKIN_UPDATE_DISTANCE = 25;
private static final Location NPC_LOCATION = new Location(null, 0, 0, 0);
} }

View File

@ -2,10 +2,14 @@ package net.citizensnpcs.trait;
import java.util.UUID; import java.util.UUID;
import org.bukkit.event.EventHandler;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.NPCAddTraitEvent;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName; import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.trait.trait.PlayerFilter;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
/** /**
@ -33,6 +37,13 @@ public class ClickRedirectTrait extends Trait {
redirectNPC = CitizensAPI.getNPCRegistry().getByUniqueIdGlobal(UUID.fromString(key.getString("uuid"))); redirectNPC = CitizensAPI.getNPCRegistry().getByUniqueIdGlobal(UUID.fromString(key.getString("uuid")));
} }
@EventHandler
public void onTraitAdd(NPCAddTraitEvent event) {
if (event.getNPC() == redirectNPC && event.getTrait() instanceof PlayerFilter) {
((PlayerFilter) event.getTrait()).addChildNPC(npc);
}
}
@Override @Override
public void save(DataKey key) { public void save(DataKey key) {
key.removeKey("uuid"); key.removeKey("uuid");

View File

@ -202,7 +202,8 @@ public class HologramTrait extends Trait {
public void load(DataKey root) { public void load(DataKey root) {
clear(); clear();
for (DataKey key : root.getRelative("lines").getIntegerSubKeys()) { for (DataKey key : root.getRelative("lines").getIntegerSubKeys()) {
HologramLine line = new HologramLine(key.keyExists("text") ? key.getString("text") : key.getString(""), true); HologramLine line = new HologramLine(key.keyExists("text") ? key.getString("text") : key.getString(""),
true);
line.mt = key.keyExists("margin.top") ? key.getDouble("margin.top") : 0.0; line.mt = key.keyExists("margin.top") ? key.getDouble("margin.top") : 0.0;
line.mb = key.keyExists("margin.bottom") ? key.getDouble("margin.bottom") : 0.0; line.mb = key.keyExists("margin.bottom") ? key.getDouble("margin.bottom") : 0.0;
lines.add(line); lines.add(line);
@ -420,8 +421,7 @@ public class HologramTrait extends Trait {
public void setMargin(int idx, String type, double margin) { public void setMargin(int idx, String type, double margin) {
if (type.equalsIgnoreCase("top")) { if (type.equalsIgnoreCase("top")) {
lines.get(idx).mt = margin; lines.get(idx).mt = margin;
} } else if (type.equalsIgnoreCase("bottom")) {
else if (type.equalsIgnoreCase("bottom")) {
lines.get(idx).mb = margin; lines.get(idx).mb = margin;
} }
reloadLineHolograms(); reloadLineHolograms();

View File

@ -147,8 +147,9 @@ public class LookClose extends Trait implements Toggleable {
} }
} else { } else {
double min = range; double min = range;
Location npcLoc = npc.getStoredLocation();
for (Player player : getNearbyPlayers()) { for (Player player : getNearbyPlayers()) {
double dist = player.getLocation(CACHE_LOCATION).distance(NPC_LOCATION); double dist = player.getLocation().distance(npcLoc);
if (dist > min) if (dist > min)
continue; continue;
min = dist; min = dist;
@ -168,15 +169,16 @@ public class LookClose extends Trait implements Toggleable {
private List<Player> getNearbyPlayers() { private List<Player> getNearbyPlayers() {
List<Player> options = Lists.newArrayList(); List<Player> options = Lists.newArrayList();
Location npcLoc = npc.getStoredLocation();
Iterable<Player> nearby = targetNPCs Iterable<Player> nearby = targetNPCs
? npc.getEntity().getNearbyEntities(range, range, range).stream() ? npc.getEntity().getNearbyEntities(range, range, range).stream()
.filter(e -> e.getType() == EntityType.PLAYER && e.getWorld() == NPC_LOCATION.getWorld()) .filter(e -> e.getType() == EntityType.PLAYER && e.getWorld() == npcLoc.getWorld())
.map(e -> (Player) e).collect(Collectors.toList()) .map(e -> (Player) e).collect(Collectors.toList())
: CitizensAPI.getLocationLookup().getNearbyPlayers(NPC_LOCATION, range); : CitizensAPI.getLocationLookup().getNearbyPlayers(npcLoc, range);
for (Player player : nearby) { for (Player player : nearby) {
if (player == lookingAt || (!targetNPCs && CitizensAPI.getNPCRegistry().getNPC(player) != null)) if (player == lookingAt || (!targetNPCs && CitizensAPI.getNPCRegistry().getNPC(player) != null))
continue; continue;
if (player.getLocation().getWorld() != NPC_LOCATION.getWorld() || isInvisible(player)) if (player.getLocation().getWorld() != npcLoc.getWorld() || isInvisible(player))
continue; continue;
options.add(player); options.add(player);
@ -232,8 +234,7 @@ public class LookClose extends Trait implements Toggleable {
private boolean isValid(Player entity) { private boolean isValid(Player entity) {
return entity.isOnline() && entity.isValid() && entity.getWorld() == npc.getEntity().getWorld() return entity.isOnline() && entity.isValid() && entity.getWorld() == npc.getEntity().getWorld()
&& entity.getLocation(PLAYER_LOCATION).distanceSquared(NPC_LOCATION) < range * range && entity.getLocation().distance(npc.getStoredLocation()) <= range && !isInvisible(entity);
&& !isInvisible(entity);
} }
@Override @Override
@ -292,7 +293,6 @@ public class LookClose extends Trait implements Toggleable {
return; return;
} }
npc.getEntity().getLocation(NPC_LOCATION);
findNewTarget(); findNewTarget();
if (npc.getNavigator().isNavigating() || npc.getNavigator().isPaused()) { if (npc.getNavigator().isNavigating() || npc.getNavigator().isPaused()) {
@ -310,8 +310,8 @@ public class LookClose extends Trait implements Toggleable {
if (npc.getEntity().getType().name().equals("SHULKER")) { if (npc.getEntity().getType().name().equals("SHULKER")) {
boolean wasSilent = npc.getEntity().isSilent(); boolean wasSilent = npc.getEntity().isSilent();
npc.getEntity().setSilent(true); npc.getEntity().setSilent(true);
NMS.setPeekShulker(npc.getEntity(), 100 - 4 * (int) Math NMS.setPeekShulker(npc.getEntity(),
.floor(npc.getStoredLocation().distanceSquared(lookingAt.getLocation(PLAYER_LOCATION)))); 100 - 4 * (int) Math.floor(npc.getStoredLocation().distanceSquared(lookingAt.getLocation())));
npc.getEntity().setSilent(wasSilent); npc.getEntity().setSilent(wasSilent);
} }
} }
@ -403,8 +403,4 @@ public class LookClose extends Trait implements Toggleable {
private static boolean isEqual(float[] array) { private static boolean isEqual(float[] array) {
return Math.abs(array[0] - array[1]) < 0.001; return Math.abs(array[0] - array[1]) < 0.001;
} }
private static final Location CACHE_LOCATION = new Location(null, 0, 0, 0);
private static final Location NPC_LOCATION = new Location(null, 0, 0, 0);
private static final Location PLAYER_LOCATION = new Location(null, 0, 0, 0);
} }

View File

@ -12,6 +12,7 @@ import net.citizensnpcs.api.event.SpawnReason;
import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName; import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.util.RemoveReason;
import net.citizensnpcs.npc.EntityController; import net.citizensnpcs.npc.EntityController;
import net.citizensnpcs.util.EntityPacketTracker; import net.citizensnpcs.util.EntityPacketTracker;
import net.citizensnpcs.util.NMS; import net.citizensnpcs.util.NMS;
@ -31,10 +32,15 @@ public class PacketNPC extends Trait {
} }
@Override @Override
public void onRemove() { public void onRemove(RemoveReason reason) {
npc.despawn(DespawnReason.PENDING_RESPAWN); if (reason == RemoveReason.REMOVAL) {
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), npc.despawn(DespawnReason.PENDING_RESPAWN);
() -> npc.spawn(npc.getStoredLocation(), SpawnReason.RESPAWN)); Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
if (npc.getStoredLocation() != null) {
npc.spawn(npc.getStoredLocation(), SpawnReason.RESPAWN);
}
});
}
} }
@Override @Override

View File

@ -1,5 +1,7 @@
package net.citizensnpcs.trait; package net.citizensnpcs.trait;
import org.bukkit.ChatColor;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.io.BaseEncoding; import com.google.common.io.BaseEncoding;
@ -12,12 +14,11 @@ import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.api.util.Placeholders; import net.citizensnpcs.api.util.Placeholders;
import net.citizensnpcs.npc.skin.Skin; import net.citizensnpcs.npc.skin.Skin;
import net.citizensnpcs.npc.skin.SkinnableEntity; import net.citizensnpcs.npc.skin.SkinnableEntity;
import org.bukkit.ChatColor;
@TraitName("skintrait") @TraitName("skintrait")
public class SkinTrait extends Trait { public class SkinTrait extends Trait {
@Persist @Persist
private boolean fetchDefaultSkin = true; private boolean fetchDefaultSkin = Setting.NPC_SKIN_FETCH_DEFAULT.asBoolean();
private String filledPlaceholder; private String filledPlaceholder;
@Persist @Persist
private String signature; private String signature;

View File

@ -9,7 +9,7 @@ import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException; import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Function; import java.util.function.Function;
@ -23,7 +23,6 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemFlag;
@ -60,26 +59,22 @@ public class Util {
} }
} }
public static boolean callEventPossiblySync(Event event, boolean sync) { public static <T> T callPossiblySync(Callable<T> callable, boolean sync) {
if (!sync) { if (!sync) {
try { try {
Bukkit.getPluginManager().callEvent(event); return callable.call();
return false; } catch (Exception e) {
} catch (IllegalStateException ex) { e.printStackTrace();
// sync method called
} }
} }
try { try {
Bukkit.getScheduler().callSyncMethod(CitizensAPI.getPlugin(), () -> { return Bukkit.getScheduler().callSyncMethod(CitizensAPI.getPlugin(), callable).get();
Bukkit.getPluginManager().callEvent(event); } catch (Exception e) {
return null;
}).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace(); e.printStackTrace();
} }
return true;
return null;
} }
public static Vector callPushEvent(NPC npc, double x, double y, double z) { public static Vector callPushEvent(NPC npc, double x, double y, double z) {
@ -152,7 +147,7 @@ public class Util {
double pitchCos = Math.cos(Math.toRadians(pitch)); double pitchCos = Math.cos(Math.toRadians(pitch));
Vector vector = new Vector(Math.sin(Math.toRadians(yaw)) * -pitchCos, -Math.sin(Math.toRadians(pitch)), Vector vector = new Vector(Math.sin(Math.toRadians(yaw)) * -pitchCos, -Math.sin(Math.toRadians(pitch)),
Math.cos(Math.toRadians(yaw)) * pitchCos).normalize(); Math.cos(Math.toRadians(yaw)) * pitchCos).normalize();
faceLocation(entity, entity.getLocation(AT_LOCATION).clone().add(vector)); faceLocation(entity, entity.getLocation().clone().add(vector));
} }
public static void faceEntity(Entity entity, Entity to) { public static void faceEntity(Entity entity, Entity to) {
@ -161,7 +156,7 @@ public class Util {
if (to instanceof LivingEntity) { if (to instanceof LivingEntity) {
NMS.look(entity, to); NMS.look(entity, to);
} else { } else {
faceLocation(entity, to.getLocation(AT_LOCATION)); faceLocation(entity, to.getLocation());
} }
} }
@ -180,7 +175,7 @@ public class Util {
} }
public static Location getCenterLocation(Block block) { public static Location getCenterLocation(Block block) {
Location bloc = block.getLocation(AT_LOCATION); Location bloc = block.getLocation();
Location center = new Location(bloc.getWorld(), bloc.getBlockX() + 0.5, bloc.getBlockY(), Location center = new Location(bloc.getWorld(), bloc.getBlockX() + 0.5, bloc.getBlockY(),
bloc.getBlockZ() + 0.5); bloc.getBlockZ() + 0.5);
BoundingBox bb = NMS.getCollisionBox(block); BoundingBox bb = NMS.getCollisionBox(block);
@ -194,7 +189,7 @@ public class Util {
* Returns the yaw to face along the given velocity (corrected for dragon yaw i.e. facing backwards) * Returns the yaw to face along the given velocity (corrected for dragon yaw i.e. facing backwards)
*/ */
public static float getDragonYaw(Entity entity, double motX, double motZ) { public static float getDragonYaw(Entity entity, double motX, double motZ) {
Location location = entity.getLocation(AT_LOCATION); Location location = entity.getLocation();
double x = location.getX(); double x = location.getX();
double z = location.getZ(); double z = location.getZ();
double tX = x + motX; double tX = x + motX;
@ -240,7 +235,7 @@ public class Util {
public static boolean inBlock(Entity entity) { public static boolean inBlock(Entity entity) {
// TODO: bounding box aware? // TODO: bounding box aware?
Location loc = entity.getLocation(AT_LOCATION); Location loc = entity.getLocation();
if (!Util.isLoaded(loc)) { if (!Util.isLoaded(loc)) {
return false; return false;
} }
@ -557,7 +552,6 @@ public class Util {
+ TimeUnit.MILLISECONDS.convert(delay.getNano(), TimeUnit.NANOSECONDS)) / 50; + TimeUnit.MILLISECONDS.convert(delay.getNano(), TimeUnit.NANOSECONDS)) / 50;
} }
private static final Location AT_LOCATION = new Location(null, 0, 0, 0);
private static final Scoreboard DUMMY_SCOREBOARD = Bukkit.getScoreboardManager().getNewScoreboard(); private static final Scoreboard DUMMY_SCOREBOARD = Bukkit.getScoreboardManager().getNewScoreboard();
private static String MINECRAFT_REVISION; private static String MINECRAFT_REVISION;
private static final DecimalFormat TWO_DIGIT_DECIMAL = new DecimalFormat(); private static final DecimalFormat TWO_DIGIT_DECIMAL = new DecimalFormat();

View File

@ -55,7 +55,7 @@ public class BatController extends MobEntityController {
super(types, level); super(types, level);
this.npc = (CitizensNPC) npc; this.npc = (CitizensNPC) npc;
if (npc != null) { if (npc != null) {
setFlying(false); setResting(false);
} }
} }
@ -165,10 +165,6 @@ public class BatController extends MobEntityController {
return npc == null ? super.save(save) : false; return npc == null ? super.save(save) : false;
} }
public void setFlying(boolean flying) {
setResting(flying);
}
@Override @Override
public boolean updateFluidHeightAndDoFluidPushing(Tag<Fluid> Tag, double d0) { public boolean updateFluidHeightAndDoFluidPushing(Tag<Fluid> Tag, double d0) {
if (npc == null) { if (npc == null) {

View File

@ -54,20 +54,34 @@ public class PlayerlistTracker extends ChunkMap.TrackedEntity {
public void updatePlayer(final ServerPlayer entityplayer) { public void updatePlayer(final ServerPlayer entityplayer) {
if (!tracker.isRemoved() && !seenBy.contains(entityplayer.connection) && tracker instanceof NPCHolder) { if (!tracker.isRemoved() && !seenBy.contains(entityplayer.connection) && tracker instanceof NPCHolder) {
NPC npc = ((NPCHolder) tracker).getNPC(); NPC npc = ((NPCHolder) tracker).getNPC();
NPCSeenByPlayerEvent event = new NPCSeenByPlayerEvent(npc, entityplayer.getBukkitEntity()); if (REQUIRES_SYNC == null) {
REQUIRES_SYNC = Util.callEventPossiblySync(event, REQUIRES_SYNC); REQUIRES_SYNC = !Bukkit.isPrimaryThread();
if (event.isCancelled())
return;
Integer trackingRange = npc.data().<Integer> get(NPC.Metadata.TRACKING_RANGE);
if (TRACKING_RANGE_SETTER != null && trackingRange != null
&& npc.data().get("last-tracking-range", -1) != trackingRange.intValue()) {
try {
TRACKING_RANGE_SETTER.invoke(this, trackingRange);
npc.data().set("last-tracking-range", trackingRange);
} catch (Throwable e) {
e.printStackTrace();
}
} }
boolean cancelled = Util.callPossiblySync(() -> {
NPCSeenByPlayerEvent event = new NPCSeenByPlayerEvent(npc, entityplayer.getBukkitEntity());
try {
Bukkit.getPluginManager().callEvent(event);
} catch (IllegalStateException e) {
REQUIRES_SYNC = true;
throw e;
}
if (event.isCancelled())
return true;
Integer trackingRange = npc.data().<Integer> get(NPC.Metadata.TRACKING_RANGE);
if (TRACKING_RANGE_SETTER != null && trackingRange != null
&& npc.data().get("last-tracking-range", -1) != trackingRange.intValue()) {
try {
TRACKING_RANGE_SETTER.invoke(PlayerlistTracker.this, trackingRange);
npc.data().set("last-tracking-range", trackingRange);
} catch (Throwable e) {
e.printStackTrace();
}
}
return false;
}, REQUIRES_SYNC);
if (cancelled)
return;
} }
if (entityplayer instanceof EntityHumanNPC) if (entityplayer instanceof EntityHumanNPC)
@ -115,7 +129,7 @@ public class PlayerlistTracker extends ChunkMap.TrackedEntity {
private static final MethodHandle E = NMS.getGetter(ServerEntity.class, "e"); private static final MethodHandle E = NMS.getGetter(ServerEntity.class, "e");
private static final MethodHandle F = NMS.getGetter(ServerEntity.class, "f"); private static final MethodHandle F = NMS.getGetter(ServerEntity.class, "f");
private static volatile boolean REQUIRES_SYNC; private static volatile Boolean REQUIRES_SYNC;
private static final MethodHandle TRACKER = NMS.getFirstGetter(TrackedEntity.class, Entity.class); private static final MethodHandle TRACKER = NMS.getFirstGetter(TrackedEntity.class, Entity.class);
private static final MethodHandle TRACKER_ENTRY = NMS.getFirstGetter(TrackedEntity.class, ServerEntity.class); private static final MethodHandle TRACKER_ENTRY = NMS.getFirstGetter(TrackedEntity.class, ServerEntity.class);
private static final MethodHandle TRACKING_RANGE = NMS.getFirstGetter(TrackedEntity.class, int.class); private static final MethodHandle TRACKING_RANGE = NMS.getFirstGetter(TrackedEntity.class, int.class);

View File

@ -57,7 +57,7 @@ public class BatController extends MobEntityController {
super(types, level); super(types, level);
this.npc = (CitizensNPC) npc; this.npc = (CitizensNPC) npc;
if (npc != null) { if (npc != null) {
setFlying(false); setResting(false);
} }
} }
@ -167,10 +167,6 @@ public class BatController extends MobEntityController {
return npc == null ? super.save(save) : false; return npc == null ? super.save(save) : false;
} }
public void setFlying(boolean flying) {
setResting(flying);
}
@Override @Override
public Entity teleportTo(ServerLevel worldserver, BlockPos location) { public Entity teleportTo(ServerLevel worldserver, BlockPos location) {
if (npc == null) if (npc == null)

View File

@ -54,20 +54,34 @@ public class PlayerlistTracker extends ChunkMap.TrackedEntity {
public void updatePlayer(final ServerPlayer entityplayer) { public void updatePlayer(final ServerPlayer entityplayer) {
if (!tracker.isRemoved() && !seenBy.contains(entityplayer.connection) && tracker instanceof NPCHolder) { if (!tracker.isRemoved() && !seenBy.contains(entityplayer.connection) && tracker instanceof NPCHolder) {
NPC npc = ((NPCHolder) tracker).getNPC(); NPC npc = ((NPCHolder) tracker).getNPC();
NPCSeenByPlayerEvent event = new NPCSeenByPlayerEvent(npc, entityplayer.getBukkitEntity()); if (REQUIRES_SYNC == null) {
REQUIRES_SYNC = Util.callEventPossiblySync(event, REQUIRES_SYNC); REQUIRES_SYNC = !Bukkit.isPrimaryThread();
if (event.isCancelled())
return;
Integer trackingRange = npc.data().<Integer> get(NPC.Metadata.TRACKING_RANGE);
if (TRACKING_RANGE_SETTER != null && trackingRange != null
&& npc.data().get("last-tracking-range", -1) != trackingRange.intValue()) {
try {
TRACKING_RANGE_SETTER.invoke(this, trackingRange);
npc.data().set("last-tracking-range", trackingRange);
} catch (Throwable e) {
e.printStackTrace();
}
} }
boolean cancelled = Util.callPossiblySync(() -> {
NPCSeenByPlayerEvent event = new NPCSeenByPlayerEvent(npc, entityplayer.getBukkitEntity());
try {
Bukkit.getPluginManager().callEvent(event);
} catch (IllegalStateException e) {
REQUIRES_SYNC = true;
throw e;
}
if (event.isCancelled())
return true;
Integer trackingRange = npc.data().<Integer> get(NPC.Metadata.TRACKING_RANGE);
if (TRACKING_RANGE_SETTER != null && trackingRange != null
&& npc.data().get("last-tracking-range", -1) != trackingRange.intValue()) {
try {
TRACKING_RANGE_SETTER.invoke(PlayerlistTracker.this, trackingRange);
npc.data().set("last-tracking-range", trackingRange);
} catch (Throwable e) {
e.printStackTrace();
}
}
return false;
}, REQUIRES_SYNC);
if (cancelled)
return;
} }
if (entityplayer instanceof EntityHumanNPC) if (entityplayer instanceof EntityHumanNPC)
@ -115,7 +129,7 @@ public class PlayerlistTracker extends ChunkMap.TrackedEntity {
private static final MethodHandle E = NMS.getGetter(ServerEntity.class, "e"); private static final MethodHandle E = NMS.getGetter(ServerEntity.class, "e");
private static final MethodHandle F = NMS.getGetter(ServerEntity.class, "f"); private static final MethodHandle F = NMS.getGetter(ServerEntity.class, "f");
private static volatile boolean REQUIRES_SYNC; private static volatile Boolean REQUIRES_SYNC;
private static final MethodHandle TRACKER = NMS.getFirstGetter(TrackedEntity.class, Entity.class); private static final MethodHandle TRACKER = NMS.getFirstGetter(TrackedEntity.class, Entity.class);
private static final MethodHandle TRACKER_ENTRY = NMS.getFirstGetter(TrackedEntity.class, ServerEntity.class); private static final MethodHandle TRACKER_ENTRY = NMS.getFirstGetter(TrackedEntity.class, ServerEntity.class);
private static final MethodHandle TRACKING_RANGE = NMS.getFirstGetter(TrackedEntity.class, int.class); private static final MethodHandle TRACKING_RANGE = NMS.getFirstGetter(TrackedEntity.class, int.class);

View File

@ -57,7 +57,7 @@ public class BatController extends MobEntityController {
super(types, level); super(types, level);
this.npc = (CitizensNPC) npc; this.npc = (CitizensNPC) npc;
if (npc != null) { if (npc != null) {
setFlying(false); setResting(false);
} }
} }
@ -167,10 +167,6 @@ public class BatController extends MobEntityController {
return npc == null ? super.save(save) : false; return npc == null ? super.save(save) : false;
} }
public void setFlying(boolean flying) {
setResting(flying);
}
@Override @Override
public Entity teleportTo(ServerLevel worldserver, PositionImpl location) { public Entity teleportTo(ServerLevel worldserver, PositionImpl location) {
if (npc == null) if (npc == null)

View File

@ -81,20 +81,34 @@ public class CitizensEntityTracker extends ChunkMap.TrackedEntity {
if (!tracker.isRemoved() && !seenBy.contains(entityplayer.connection) && tracker instanceof NPCHolder) { if (!tracker.isRemoved() && !seenBy.contains(entityplayer.connection) && tracker instanceof NPCHolder) {
NPC npc = ((NPCHolder) tracker).getNPC(); NPC npc = ((NPCHolder) tracker).getNPC();
NPCSeenByPlayerEvent event = new NPCSeenByPlayerEvent(npc, entityplayer.getBukkitEntity()); if (REQUIRES_SYNC == null) {
REQUIRES_SYNC = Util.callEventPossiblySync(event, REQUIRES_SYNC); REQUIRES_SYNC = !Bukkit.isPrimaryThread();
if (event.isCancelled())
return;
Integer trackingRange = npc.data().<Integer> get(NPC.Metadata.TRACKING_RANGE);
if (TRACKING_RANGE_SETTER != null && trackingRange != null
&& npc.data().get("last-tracking-range", -1) != trackingRange.intValue()) {
try {
TRACKING_RANGE_SETTER.invoke(this, trackingRange);
npc.data().set("last-tracking-range", trackingRange);
} catch (Throwable e) {
e.printStackTrace();
}
} }
boolean cancelled = Util.callPossiblySync(() -> {
NPCSeenByPlayerEvent event = new NPCSeenByPlayerEvent(npc, entityplayer.getBukkitEntity());
try {
Bukkit.getPluginManager().callEvent(event);
} catch (IllegalStateException e) {
REQUIRES_SYNC = true;
throw e;
}
if (event.isCancelled())
return true;
Integer trackingRange = npc.data().<Integer> get(NPC.Metadata.TRACKING_RANGE);
if (TRACKING_RANGE_SETTER != null && trackingRange != null
&& npc.data().get("last-tracking-range", -1) != trackingRange.intValue()) {
try {
TRACKING_RANGE_SETTER.invoke(CitizensEntityTracker.this, trackingRange);
npc.data().set("last-tracking-range", trackingRange);
} catch (Throwable e) {
e.printStackTrace();
}
}
return false;
}, REQUIRES_SYNC);
if (cancelled)
return;
} }
super.updatePlayer(entityplayer); super.updatePlayer(entityplayer);
@ -138,7 +152,7 @@ public class CitizensEntityTracker extends ChunkMap.TrackedEntity {
private static final MethodHandle E = NMS.getGetter(ServerEntity.class, "e"); private static final MethodHandle E = NMS.getGetter(ServerEntity.class, "e");
private static final MethodHandle F = NMS.getGetter(ServerEntity.class, "f"); private static final MethodHandle F = NMS.getGetter(ServerEntity.class, "f");
private static volatile boolean REQUIRES_SYNC = false; private static volatile Boolean REQUIRES_SYNC = false;
private static final MethodHandle TRACKER = NMS.getFirstGetter(TrackedEntity.class, Entity.class); private static final MethodHandle TRACKER = NMS.getFirstGetter(TrackedEntity.class, Entity.class);
private static final MethodHandle TRACKER_ENTRY = NMS.getFirstGetter(TrackedEntity.class, ServerEntity.class); private static final MethodHandle TRACKER_ENTRY = NMS.getFirstGetter(TrackedEntity.class, ServerEntity.class);
private static final MethodHandle TRACKING_RANGE = NMS.getFirstGetter(TrackedEntity.class, int.class); private static final MethodHandle TRACKING_RANGE = NMS.getFirstGetter(TrackedEntity.class, int.class);

View File

@ -57,7 +57,7 @@ public class BatController extends MobEntityController {
super(types, level); super(types, level);
this.npc = (CitizensNPC) npc; this.npc = (CitizensNPC) npc;
if (npc != null) { if (npc != null) {
setFlying(false); setResting(false);
} }
} }
@ -167,10 +167,6 @@ public class BatController extends MobEntityController {
return npc == null ? super.save(save) : false; return npc == null ? super.save(save) : false;
} }
public void setFlying(boolean flying) {
setResting(flying);
}
@Override @Override
public Entity teleportTo(ServerLevel worldserver, PositionImpl location) { public Entity teleportTo(ServerLevel worldserver, PositionImpl location) {
if (npc == null) if (npc == null)

View File

@ -84,20 +84,31 @@ public class CitizensEntityTracker extends ChunkMap.TrackedEntity {
if (REQUIRES_SYNC == null) { if (REQUIRES_SYNC == null) {
REQUIRES_SYNC = !Bukkit.isPrimaryThread(); REQUIRES_SYNC = !Bukkit.isPrimaryThread();
} }
NPCSeenByPlayerEvent event = new NPCSeenByPlayerEvent(npc, entityplayer.getBukkitEntity()); boolean cancelled = Util.callPossiblySync(() -> {
REQUIRES_SYNC = Util.callEventPossiblySync(event, REQUIRES_SYNC); NPCSeenByPlayerEvent event = new NPCSeenByPlayerEvent(npc, entityplayer.getBukkitEntity());
if (event.isCancelled())
return;
Integer trackingRange = npc.data().<Integer> get(NPC.Metadata.TRACKING_RANGE);
if (TRACKING_RANGE_SETTER != null && trackingRange != null
&& npc.data().get("last-tracking-range", -1) != trackingRange.intValue()) {
try { try {
TRACKING_RANGE_SETTER.invoke(this, trackingRange); Bukkit.getPluginManager().callEvent(event);
npc.data().set("last-tracking-range", trackingRange); } catch (IllegalStateException e) {
} catch (Throwable e) { REQUIRES_SYNC = true;
e.printStackTrace(); throw e;
} }
} if (event.isCancelled())
return true;
Integer trackingRange = npc.data().<Integer> get(NPC.Metadata.TRACKING_RANGE);
if (TRACKING_RANGE_SETTER != null && trackingRange != null
&& npc.data().get("last-tracking-range", -1) != trackingRange.intValue()) {
try {
TRACKING_RANGE_SETTER.invoke(CitizensEntityTracker.this, trackingRange);
npc.data().set("last-tracking-range", trackingRange);
} catch (Throwable e) {
e.printStackTrace();
}
}
return false;
}, REQUIRES_SYNC);
if (cancelled)
return;
} }
super.updatePlayer(entityplayer); super.updatePlayer(entityplayer);