Trial fix to paper delaying non-player mob spawns

This commit is contained in:
fullwall 2022-03-16 17:13:05 +08:00
parent 577dc72101
commit cd12fefe73
2 changed files with 75 additions and 51 deletions

View File

@ -14,6 +14,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scoreboard.Team; import org.bukkit.scoreboard.Team;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
@ -69,7 +70,7 @@ public class CitizensNPC extends AbstractNPC {
@Override @Override
public boolean despawn(DespawnReason reason) { public boolean despawn(DespawnReason reason) {
if (!isSpawned() && reason != DespawnReason.DEATH) { if (!isSpawned() && reason != DespawnReason.DEATH) {
Messaging.debug("Tried to despawn", toString(), "while already despawned, DespawnReason." + reason); Messaging.debug("Tried to despawn", this, "while already despawned, DespawnReason." + reason);
if (reason == DespawnReason.RELOAD) { if (reason == DespawnReason.RELOAD) {
unloadEvents(); unloadEvents();
} }
@ -81,7 +82,7 @@ public class CitizensNPC extends AbstractNPC {
} }
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled() && reason != DespawnReason.DEATH) { if (event.isCancelled() && reason != DespawnReason.DEATH) {
Messaging.debug("Couldn't despawn", toString(), "due to despawn event cancellation. Will load chunk.", Messaging.debug("Couldn't despawn", this, "due to despawn event cancellation. Will load chunk.",
getEntity().isValid(), ", DespawnReason." + reason); getEntity().isValid(), ", DespawnReason." + reason);
return false; return false;
} }
@ -99,7 +100,7 @@ public class CitizensNPC extends AbstractNPC {
for (Trait trait : new ArrayList<Trait>(traits.values())) { for (Trait trait : new ArrayList<Trait>(traits.values())) {
trait.onDespawn(); trait.onDespawn();
} }
Messaging.debug("Despawned", toString(), "DespawnReason." + reason); Messaging.debug("Despawned", this, "DespawnReason." + reason);
if (reason == DespawnReason.DEATH) { if (reason == DespawnReason.DEATH) {
entityController.setEntity(null); entityController.setEntity(null);
} else { } else {
@ -161,7 +162,7 @@ public class CitizensNPC extends AbstractNPC {
if (spawnLocation.getLocation() != null) { if (spawnLocation.getLocation() != null) {
spawn(spawnLocation.getLocation(), SpawnReason.RESPAWN); spawn(spawnLocation.getLocation(), SpawnReason.RESPAWN);
} else { } else {
Messaging.debug("Tried to spawn", toString(), "on load but world was null"); Messaging.debug("Tried to spawn", this, "on load but world was null");
} }
} }
@ -240,11 +241,11 @@ public class CitizensNPC extends AbstractNPC {
Preconditions.checkNotNull(at, "location cannot be null"); Preconditions.checkNotNull(at, "location cannot be null");
Preconditions.checkNotNull(reason, "reason cannot be null"); Preconditions.checkNotNull(reason, "reason cannot be null");
if (getEntity() != null) { if (getEntity() != null) {
Messaging.debug("Tried to spawn", toString(), "while already spawned. SpawnReason." + reason); Messaging.debug("Tried to spawn", this, "while already spawned. SpawnReason." + reason);
return false; return false;
} }
if (at.getWorld() == null) { if (at.getWorld() == null) {
Messaging.debug("Tried to spawn", toString(), "but the world was null. SpawnReason." + reason); Messaging.debug("Tried to spawn", this, "but the world was null. SpawnReason." + reason);
return false; return false;
} }
at = at.clone(); at = at.clone();
@ -272,72 +273,95 @@ public class CitizensNPC extends AbstractNPC {
if (!couldSpawn) { if (!couldSpawn) {
if (Messaging.isDebugging()) { if (Messaging.isDebugging()) {
Messaging.debug("Retrying spawn of", toString(), "later, SpawnReason." + reason + ". Was loaded", Messaging.debug("Retrying spawn of", this, "later, SpawnReason." + reason + ". Was loaded", loaded,
loaded, "is loaded", Util.isLoaded(at)); "is loaded", Util.isLoaded(at));
} }
// we need to wait before trying to spawn // we need to wait before trying to spawn
entityController.remove(); entityController.remove();
Bukkit.getPluginManager().callEvent(new NPCNeedsRespawnEvent(this, at)); Bukkit.getPluginManager().callEvent(new NPCNeedsRespawnEvent(this, at));
return false; return false;
} }
// send skin packets, if applicable, before other NMS packets are sent // 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) { if (skinnable != null) {
skinnable.getSkinTracker().onSpawnNPC(); skinnable.getSkinTracker().onSpawnNPC();
} }
getEntity().teleport(at); getEntity().teleport(at);
NMS.setHeadYaw(getEntity(), at.getYaw()); NMS.setHeadYaw(getEntity(), at.getYaw());
NMS.setBodyYaw(getEntity(), at.getYaw()); NMS.setBodyYaw(getEntity(), at.getYaw());
// Set the spawned state final Location to = at;
getOrAddTrait(CurrentLocation.class).setLocation(at); BukkitRunnable postSpawn = new BukkitRunnable() {
getOrAddTrait(Spawned.class).setSpawned(true); private int timer;
NPCSpawnEvent spawnEvent = new NPCSpawnEvent(this, at, reason); @Override
Bukkit.getPluginManager().callEvent(spawnEvent); public void run() {
if (timer++ > 10) {
cancel();
return;
}
if (getEntity() == null || !getEntity().isValid())
return;
if (spawnEvent.isCancelled()) { // Set the spawned state
entityController.remove(); getOrAddTrait(CurrentLocation.class).setLocation(to);
Messaging.debug("Couldn't spawn", toString(), "SpawnReason." + reason + " due to event cancellation."); getOrAddTrait(Spawned.class).setSpawned(true);
return false;
}
navigator.onSpawn(); NPCSpawnEvent spawnEvent = new NPCSpawnEvent(CitizensNPC.this, to, reason);
Bukkit.getPluginManager().callEvent(spawnEvent);
Collection<Trait> onSpawn = traits.values(); if (spawnEvent.isCancelled()) {
for (Trait trait : onSpawn.toArray(new Trait[onSpawn.size()])) { entityController.remove();
try { Messaging.debug("Couldn't spawn", this, "SpawnReason." + reason, "due to event cancellation.");
trait.onSpawn(); cancel();
} catch (Throwable ex) { return;
Messaging.severeTr(Messages.TRAIT_ONSPAWN_FAILED, trait.getName(), getId()); }
ex.printStackTrace();
navigator.onSpawn();
Collection<Trait> onSpawn = traits.values();
for (Trait trait : onSpawn.toArray(new Trait[onSpawn.size()])) {
try {
trait.onSpawn();
} catch (Throwable ex) {
Messaging.severeTr(Messages.TRAIT_ONSPAWN_FAILED, trait.getName(), getId());
ex.printStackTrace();
}
}
if (getEntity() instanceof LivingEntity) {
LivingEntity entity = (LivingEntity) getEntity();
entity.setRemoveWhenFarAway(false);
if (NMS.getStepHeight(entity) < 1) {
NMS.setStepHeight(entity, 1);
}
if (getEntity() instanceof Player) {
NMS.replaceTrackerEntry((Player) getEntity());
PlayerUpdateTask.registerPlayer(getEntity());
}
}
if (requiresNameHologram() && !hasTrait(HologramTrait.class)) {
addTrait(HologramTrait.class);
}
updateFlyableState();
updateCustomNameVisibility();
updateCustomName();
Messaging.debug("Spawned", this, "SpawnReason." + reason);
cancel();
} }
};
if (isSpawned()) {
postSpawn.runTask(CitizensAPI.getPlugin());
} else {
postSpawn.runTaskTimer(CitizensAPI.getPlugin(), 0, 1);
} }
if (getEntity() instanceof LivingEntity) {
LivingEntity entity = (LivingEntity) getEntity();
entity.setRemoveWhenFarAway(false);
if (NMS.getStepHeight(entity) < 1) {
NMS.setStepHeight(entity, 1);
}
if (getEntity() instanceof Player) {
NMS.replaceTrackerEntry((Player) getEntity());
PlayerUpdateTask.registerPlayer(getEntity());
}
}
if (requiresNameHologram() && !hasTrait(HologramTrait.class)) {
addTrait(HologramTrait.class);
}
updateFlyableState();
updateCustomNameVisibility();
updateCustomName();
Messaging.debug("Spawned", toString(), "SpawnReason." + reason);
return true; return true;
} }
@ -357,7 +381,7 @@ public class CitizensNPC extends AbstractNPC {
EntityType mobType = hasTrait(MobType.class) ? getTraitNullable(MobType.class).getType() : null; EntityType mobType = hasTrait(MobType.class) ? getTraitNullable(MobType.class).getType() : null;
return getId() + "{" + getName() + ", " + mobType + "}"; return getId() + "{" + getName() + ", " + mobType + "}";
} }
@Override @Override
public void update() { public void update() {
try { try {

View File

@ -135,7 +135,7 @@ public class SkinPacketTracker {
double viewDistance = Setting.NPC_SKIN_VIEW_DISTANCE.asDouble(); double viewDistance = Setting.NPC_SKIN_VIEW_DISTANCE.asDouble();
updateNearbyViewers(viewDistance); updateNearbyViewers(viewDistance);
} }
}.runTaskLater(CitizensAPI.getPlugin(), 20); }.runTaskLater(CitizensAPI.getPlugin(), 15);
} }
private void scheduleRemovePacket(final PlayerEntry entry) { private void scheduleRemovePacket(final PlayerEntry entry) {