use of com.bergerkiller.bukkit.common.internal.hooks.EntityTrackerHook in project BKCommonLib by bergerhealer.
the class CommonEntity method spawn.
/**
* Creates a new Entity and spawns it at the Location and using the controllers
* specified.
*
* @param entityType to spawn
* @param location to spawn at
* @param controller to assign to the Entity after spawning
* @param networkController to assign to the Entity after spawning
* @return True if spawning occurred, False if not
* @see #spawn(Location)
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static final CommonEntity spawn(EntityType entityType, Location location, EntityController controller, EntityNetworkController networkController) {
CommonEntityType type = CommonEntityType.byEntityType(entityType);
if (type == CommonEntityType.UNKNOWN) {
throw new IllegalArgumentException("The Entity Type '" + entityType + "' is invalid!");
}
// Create the common entity and Entity NMS handle to add to the server
final CommonEntity<org.bukkit.entity.Entity> entity = type.createNMSHookEntity(location);
// Set controller before spawning
controller.bind(entity, false);
// We do this by temporarily hooking the EntityTracker, cancelling track() for the entity we don't want
if (networkController != null && !(networkController instanceof DefaultEntityNetworkController)) {
// Purpur: enable legacy tracking logic when controllers are used
if (EntityHandle.T.setLegacyTrackingEntity.isAvailable()) {
EntityHandle.T.setLegacyTrackingEntity.invoker.invoke(entity.getHandle(), Boolean.TRUE);
}
// Hook the entity tracker to cancel track() on this Entity
Object nmsWorldHandle = HandleConversion.toWorldHandle(location.getWorld());
EntityTrackerHook hook = hookWorldEntityTracker(nmsWorldHandle);
hook.ignoredEntities.add(entity.getHandle());
try {
// Spawn the entity. This will not create an entity tracker entry.
EntityUtil.addEntity(entity.getEntity());
// This is why we use bind(entity, false)!
// Fire onAttached after having added the Entity to the world
entity.getController().onAttached();
// Set the network controller
entity.setNetworkController(networkController);
// entity.getNetworkController().onAttached(); // Not needed, the setNetworkController() above does this
} finally {
// Remove the entity from the ignore list, restore Entity Tracker entry if last entity
hook.ignoredEntities.remove(entity.getHandle());
unhookWorldEntityTracker(nmsWorldHandle, hook);
}
} else {
// Simply spawn. No special things to do here.
EntityUtil.addEntity(entity.getEntity());
// This is why we use bind(entity, false)!
// Fire onAttached after having added the Entity to the world
entity.getController().onAttached();
}
return entity;
}
use of com.bergerkiller.bukkit.common.internal.hooks.EntityTrackerHook in project BKCommonLib by bergerhealer.
the class CommonEntity method hookWorldEntityTracker.
/*
* Hooks the world's EntityTracker temporarily for the sole purpose of blocking calls to track()
*/
private static EntityTrackerHook hookWorldEntityTracker(Object nmsWorldHandle) {
Object nmsEntityTrackerHandle = WorldServerHandle.T.getEntityTrackerHandle.invoke(nmsWorldHandle);
EntityTrackerHook hook = EntityTrackerHook.get(nmsEntityTrackerHandle, EntityTrackerHook.class);
if (hook == null) {
hook = new EntityTrackerHook(nmsEntityTrackerHandle);
WorldServerHandle.T.setEntityTrackerHandle.invoke(nmsWorldHandle, hook.hook(nmsEntityTrackerHandle));
}
return hook;
}
use of com.bergerkiller.bukkit.common.internal.hooks.EntityTrackerHook in project BKCommonLib by bergerhealer.
the class CommonEntity method teleport.
@Override
public boolean teleport(Location location, TeleportCause cause) {
if (isRemoved()) {
return false;
}
// Preparations prior to teleportation
final Location oldLocation = entity.getLocation();
final List<org.bukkit.entity.Entity> passengers = getPassengers();
final WorldHandle newworld = WorldHandle.fromBukkit(location.getWorld());
final boolean isWorldChange = !this.handle.getWorld().equals(newworld);
final EntityNetworkController<?> oldNetworkController = getNetworkController();
final boolean hasNetworkController = !(oldNetworkController instanceof DefaultEntityNetworkController);
WorldUtil.loadChunks(location, 3);
// If in a vehicle, make sure we eject first
if (isInsideVehicle()) {
ExtendedEntity<Entity> extVeh = new ExtendedEntity<Entity>(getVehicle());
if (!extVeh.removePassenger(entity)) {
return false;
}
}
// If vehicle, eject the passenger first
if (hasPassenger()) {
this.setPassengersSilent(Collections.<org.bukkit.entity.Entity>emptyList());
}
// Perform actual teleportation
final boolean succ;
if (entity instanceof Player) {
// No special logic here. Just teleport.
succ = entity.teleport(location, cause);
} else if (!isWorldChange) {
// First: stop tracking the entity
final EntityTracker tracker = WorldUtil.getTracker(getWorld());
tracker.stopTracking(entity);
// Destroy packets are queued: Make sure to send them RIGHT NOW
for (Player bukkitPlayer : WorldUtil.getPlayers(getWorld())) {
CommonPlayer player = get(bukkitPlayer);
if (player != null) {
player.flushEntityRemoveQueue();
}
}
// Teleport the non-player entity
succ = entity.teleport(location, cause);
// Start tracking the entity again
if (!hasNetworkController && !isWorldChange) {
tracker.startTracking(entity);
}
} else {
// Remove from one world and add to the other
this.handle.getWorldServer().removeEntityWithoutDeath(this.handle);
this.handle.setDestroyed(false);
this.handle.setWorld(newworld);
this.handle.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
if (hasNetworkController) {
// Hook the entity tracker to cancel track() on this Entity
Object nmsWorldHandle = HandleConversion.toWorldHandle(location.getWorld());
EntityTrackerHook hook = hookWorldEntityTracker(nmsWorldHandle);
hook.ignoredEntities.add(this.handle.getRaw());
try {
// Spawn the entity. This will not create an entity tracker entry.
EntityUtil.addEntity(entity);
} finally {
// Remove the entity from the ignore list, restore Entity Tracker entry if last entity
hook.ignoredEntities.remove(this.handle.getRaw());
unhookWorldEntityTracker(nmsWorldHandle, hook);
}
} else {
// Simply add the entity, which will register a (default) network controller
EntityUtil.addEntity(entity);
}
succ = true;
}
// If there was a passenger, teleport it and let passenger enter again
if (succ && !passengers.isEmpty()) {
// Teleport the passenger, but ignore the chunk send check so vehicle is properly spawned to all players
List<org.bukkit.entity.Entity> teleportedPassengers = new ArrayList<org.bukkit.entity.Entity>();
this.handle.setIgnoreChunkCheck(true);
float yawChange = location.getYaw() - oldLocation.getYaw();
float pitchChange = location.getPitch() - oldLocation.getPitch();
for (org.bukkit.entity.Entity passenger : passengers) {
// Figure out a suitable location yaw and pitch based on what it was before
// We must make sure that when players are mounted, they still face the same way relatively
Location passengerOld = passenger.getLocation();
Location passengerLoc = location.clone();
passengerLoc.setYaw(passengerOld.getYaw() + yawChange);
passengerLoc.setPitch(passengerOld.getPitch() + pitchChange);
if (get(passenger).teleport(passengerLoc, cause)) {
teleportedPassengers.add(passenger);
}
}
;
this.handle.setIgnoreChunkCheck(false);
if (!teleportedPassengers.isEmpty()) {
if (hasNetworkController) {
// network controller is used; simply set the passengers of the entity handle
List<EntityHandle> passengerHandles = new ArrayList<EntityHandle>(teleportedPassengers.size());
for (org.bukkit.entity.Entity passenger : teleportedPassengers) {
EntityHandle phandle = EntityHandle.fromBukkit(passenger);
passengerHandles.add(phandle);
phandle.setVehicle(this.handle);
}
this.handle.setPassengers(passengerHandles);
} else {
setPassengersSilent(teleportedPassengers);
}
}
}
// Set network controller last, to make sure passenger mounting packets are sent properly
if (hasNetworkController) {
setNetworkController(oldNetworkController);
}
return succ;
}
Aggregations