Fix bugs with rabbit, controllable

This commit is contained in:
fullwall 2015-10-24 17:07:24 +08:00
parent 5e5b2dc8c8
commit 2d5a4593ff
6 changed files with 200 additions and 202 deletions

View File

@ -6,6 +6,40 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityCombustByBlockEvent;
import org.bukkit.event.entity.EntityCombustByEntityEvent;
import org.bukkit.event.entity.EntityCombustEvent;
import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.vehicle.VehicleDestroyEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.scoreboard.Team;
import com.google.common.base.Predicates;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables;
@ -47,47 +81,12 @@ import net.citizensnpcs.trait.Controllable;
import net.citizensnpcs.trait.CurrentLocation;
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.NMS;
import net.minecraft.server.v1_8_R3.Navigation;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityCombustByBlockEvent;
import org.bukkit.event.entity.EntityCombustByEntityEvent;
import org.bukkit.event.entity.EntityCombustEvent;
import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.vehicle.VehicleDestroyEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.scoreboard.Team;
public class EventListen implements Listener {
private final NPCRegistry npcRegistry = CitizensAPI.getNPCRegistry();
private final Map<String, NPCRegistry> registries;
private final ListMultimap<ChunkCoord, NPC> toRespawn = ArrayListMultimap.create();
private final SkinUpdateTracker skinUpdateTracker;
private final ListMultimap<ChunkCoord, NPC> toRespawn = ArrayListMultimap.create();
EventListen(Map<String, NPCRegistry> registries) {
this.registries = registries;
@ -157,6 +156,11 @@ public class EventListen implements Listener {
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onCitizensReload(CitizensReloadEvent event) {
skinUpdateTracker.reset();
}
@EventHandler(ignoreCancelled = true)
public void onCommandSenderCreateNPC(CommandSenderCreateNPCEvent event) {
checkCreationEvent(event);
@ -269,6 +273,9 @@ public class EventListen implements Listener {
String owner = event.getKey().getString("skull.owner", "");
UUID uuid = event.getKey().keyExists("skull.uuid") ? UUID.fromString(event.getKey().getString("skull.uuid"))
: null;
if (owner.isEmpty() && uuid == null) {
return;
}
GameProfile profile = new GameProfile(uuid, owner);
for (DataKey sub : event.getKey().getRelative("skull.properties").getSubKeys()) {
String propertyName = sub.name();
@ -314,6 +321,16 @@ public class EventListen implements Listener {
}
}
@EventHandler
public void onNavigationBegin(NavigationBeginEvent event) {
skinUpdateTracker.onNPCNavigationBegin(event.getNPC());
}
@EventHandler
public void onNavigationComplete(NavigationCompleteEvent event) {
skinUpdateTracker.onNPCNavigationComplete(event.getNPC());
}
@EventHandler
public void onNeedsRespawn(NPCNeedsRespawnEvent event) {
ChunkCoord coord = toCoord(event.getSpawnLocation());
@ -322,11 +339,6 @@ public class EventListen implements Listener {
toRespawn.put(coord, event.getNPC());
}
@EventHandler
public void onNPCSpawn(NPCSpawnEvent event) {
skinUpdateTracker.onNPCSpawn(event.getNPC());
}
@EventHandler
public void onNPCDespawn(NPCDespawnEvent event) {
if (event.getReason() == DespawnReason.PLUGIN || event.getReason() == DespawnReason.REMOVAL) {
@ -338,13 +350,8 @@ public class EventListen implements Listener {
}
@EventHandler
public void onNavigationBegin(NavigationBeginEvent event) {
skinUpdateTracker.onNPCNavigationBegin(event.getNPC());
}
@EventHandler
public void onNavigationComplete(NavigationCompleteEvent event) {
skinUpdateTracker.onNPCNavigationComplete(event.getNPC());
public void onNPCSpawn(NPCSpawnEvent event) {
skinUpdateTracker.onNPCSpawn(event.getNPC());
}
@EventHandler(ignoreCancelled = true)
@ -383,6 +390,13 @@ public class EventListen implements Listener {
skinUpdateTracker.updatePlayer(event.getPlayer(), 20, true);
}
// 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) {
skinUpdateTracker.onPlayerMove(event.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerQuit(PlayerQuitEvent event) {
Editor.leave(event.getPlayer());
@ -453,18 +467,6 @@ 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) {
skinUpdateTracker.onPlayerMove(event.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR)
public void onCitizensReload(CitizensReloadEvent event) {
skinUpdateTracker.reset();
}
private void respawnAllFromCoord(ChunkCoord coord) {
List<NPC> ids = toRespawn.get(coord);
for (int i = 0; i < ids.size(); i++) {

View File

@ -4,6 +4,11 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import net.citizensnpcs.Metrics;
import net.citizensnpcs.Metrics.Graph;
import net.citizensnpcs.api.CitizensAPI;
@ -40,11 +45,6 @@ import net.citizensnpcs.trait.ZombieModifier;
import net.citizensnpcs.trait.text.Text;
import net.citizensnpcs.trait.waypoint.Waypoints;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
public class CitizensTraitFactory implements TraitFactory {
private final List<TraitInfo> defaultTraits = Lists.newArrayList();
private final Map<String, TraitInfo> registered = Maps.newHashMap();
@ -114,6 +114,12 @@ public class CitizensTraitFactory implements TraitFactory {
return info.tryCreateInstance();
}
@Override
public void deregisterTrait(TraitInfo info) {
Preconditions.checkNotNull(info, "info cannot be null");
registered.remove(info.getTraitName());
}
@Override
public <T extends Trait> T getTrait(Class<T> clazz) {
for (TraitInfo entry : registered.values()) {

View File

@ -115,7 +115,7 @@ public class HumanController extends AbstractEntityController {
handle.getNPC().data().set(NPC.SCOREBOARD_FAKE_TEAM_NAME_METADATA, teamName);
}
}
}, 1);
}, 20);
handle.getBukkitEntity().setSleepingIgnored(true);

View File

@ -120,9 +120,9 @@ public class RabbitController extends MobEntityController {
public void E() {
if (npc != null) {
npc.update();
} else {
super.E();
}
super.E();
}
@Override

View File

@ -215,15 +215,9 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
private double updateHorizontalSpeed(net.minecraft.server.v1_8_R3.Entity handle,
net.minecraft.server.v1_8_R3.Entity passenger, double speed, float speedMod) {
double oldSpeed = Math.sqrt(handle.motX * handle.motX + handle.motZ * handle.motZ);
double horizontal = ((EntityLiving) passenger).ba;
if (horizontal > 0.0D) {
double dXcos = -Math.sin(passenger.yaw * Math.PI / 180.0F);
double dXsin = Math.cos(passenger.yaw * Math.PI / 180.0F);
handle.motX += dXcos * speed * speedMod * 0.5;
handle.motZ += dXsin * speed * speedMod * 0.5;
}
handle.motX += passenger.motX * speedMod;
handle.motZ += passenger.motZ * speedMod;
double angle = Math.toRadians(passenger.yaw - ((EntityLiving) passenger).aZ * 45.0F);
handle.motX += speedMod * -Math.sin(angle) * ((EntityLiving) passenger).ba * 0.05;
handle.motZ += speedMod * Math.cos(angle) * ((EntityLiving) passenger).ba * 0.05;
double newSpeed = Math.sqrt(handle.motX * handle.motX + handle.motZ * handle.motZ);
if (newSpeed > oldSpeed && speed < 0.35D) {

View File

@ -12,8 +12,27 @@ import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.WeakHashMap;
import javax.annotation.Nullable;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.craftbukkit.v1_8_R3.CraftServer;
import org.bukkit.craftbukkit.v1_8_R3.CraftSound;
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Horse;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.plugin.PluginLoadOrder;
import com.google.common.base.Preconditions;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.GameProfileRepository;
@ -58,24 +77,6 @@ import net.minecraft.server.v1_8_R3.PathfinderGoalSelector;
import net.minecraft.server.v1_8_R3.World;
import net.minecraft.server.v1_8_R3.WorldServer;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.craftbukkit.v1_8_R3.CraftServer;
import org.bukkit.craftbukkit.v1_8_R3.CraftSound;
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Horse;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.plugin.PluginLoadOrder;
@SuppressWarnings("unchecked")
public class NMS {
@ -83,107 +84,27 @@ public class NMS {
// util class
}
public static GameProfileRepository getGameProfileRepository() {
return ((CraftServer) Bukkit.getServer()).getServer()
.getGameProfileRepository();
public static void addOrRemoveFromPlayerList(org.bukkit.entity.Entity entity, boolean remove) {
if (entity == null)
return;
EntityHuman handle = (EntityHuman) getHandle(entity);
if (handle.world == null)
return;
if (remove) {
handle.world.players.remove(handle);
} else if (!handle.world.players.contains(handle)) {
handle.world.players.add(handle);
}
}
public static boolean addToWorld(org.bukkit.World world,
org.bukkit.entity.Entity entity,
CreatureSpawnEvent.SpawnReason reason) {
public static boolean addToWorld(org.bukkit.World world, org.bukkit.entity.Entity entity,
CreatureSpawnEvent.SpawnReason reason) {
Preconditions.checkNotNull(world);
Preconditions.checkNotNull(entity);
Preconditions.checkNotNull(reason);
Entity nmsEntity = ((CraftEntity)entity).getHandle();
return ((CraftWorld)world).getHandle().addEntity(nmsEntity, reason);
}
public static void removeFromWorld(org.bukkit.entity.Entity entity) {
Preconditions.checkNotNull(entity);
Entity nmsEntity = ((CraftEntity)entity).getHandle();
nmsEntity.world.removeEntity(nmsEntity);
}
@Nullable
public static SkinnableEntity getSkinnable(org.bukkit.entity.Entity entity) {
Preconditions.checkNotNull(entity);
Entity nmsEntity = ((CraftEntity) entity).getHandle();
if (nmsEntity instanceof SkinnableEntity) {
return (SkinnableEntity)nmsEntity;
}
return null;
}
public static void sendTabListAdd(Player recipient, Player listPlayer) {
Preconditions.checkNotNull(recipient);
Preconditions.checkNotNull(listPlayer);
EntityPlayer entity = ((CraftPlayer)listPlayer).getHandle();
sendPacket(recipient, new PacketPlayOutPlayerInfo(
PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, entity));
}
public static void sendTabListRemove(Player recipient, Player listPlayer) {
Preconditions.checkNotNull(recipient);
Preconditions.checkNotNull(listPlayer);
EntityPlayer entity = ((CraftPlayer)listPlayer).getHandle();
sendPacket(recipient, new PacketPlayOutPlayerInfo(
PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, entity));
}
public static void sendTabListRemove(Player recipient,
Collection<? extends SkinnableEntity> skinnableNPCs) {
Preconditions.checkNotNull(recipient);
Preconditions.checkNotNull(skinnableNPCs);
EntityPlayer[] entities = new EntityPlayer[skinnableNPCs.size()];
int i=0;
for (SkinnableEntity skinnable : skinnableNPCs) {
entities[i] = (EntityPlayer)skinnable;
i++;
}
sendPacket(recipient, new PacketPlayOutPlayerInfo(
PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, entities));
}
/*
* Yggdrasil's default implementation of this method silently fails instead of throwing
* an Exception like it should.
*/
public static GameProfile fillProfileProperties(GameProfile profile,
boolean requireSecure) throws Exception {
if (Bukkit.isPrimaryThread())
throw new IllegalStateException("NMS.fillProfileProperties cannot be invoked from the main thread.");
MinecraftSessionService sessionService = ((CraftServer) Bukkit.getServer()).getServer().aD();
YggdrasilAuthenticationService auth = ((YggdrasilMinecraftSessionService) sessionService)
.getAuthenticationService();
URL url = HttpAuthenticationService.constantURL(
"https://sessionserver.mojang.com/session/minecraft/profile/" +
UUIDTypeAdapter.fromUUID(profile.getId()));
url = HttpAuthenticationService.concatenateURL(url, "unsigned=" + !requireSecure);
MinecraftProfilePropertiesResponse response = (MinecraftProfilePropertiesResponse)
MAKE_REQUEST.invoke(auth, url, null, MinecraftProfilePropertiesResponse.class);
if (response == null)
return profile;
GameProfile result = new GameProfile(response.getId(), response.getName());
result.getProperties().putAll(response.getProperties());
profile.getProperties().putAll(response.getProperties());
return result;
return ((CraftWorld) world).getHandle().addEntity(nmsEntity, reason);
}
public static void attack(EntityLiving handle, Entity target) {
@ -242,6 +163,37 @@ public class NMS {
}
}
/*
* Yggdrasil's default implementation of this method silently fails instead of throwing
* an Exception like it should.
*/
public static GameProfile fillProfileProperties(GameProfile profile, boolean requireSecure) throws Exception {
if (Bukkit.isPrimaryThread())
throw new IllegalStateException("NMS.fillProfileProperties cannot be invoked from the main thread.");
MinecraftSessionService sessionService = ((CraftServer) Bukkit.getServer()).getServer().aD();
YggdrasilAuthenticationService auth = ((YggdrasilMinecraftSessionService) sessionService)
.getAuthenticationService();
URL url = HttpAuthenticationService.constantURL("https://sessionserver.mojang.com/session/minecraft/profile/"
+ UUIDTypeAdapter.fromUUID(profile.getId()));
url = HttpAuthenticationService.concatenateURL(url, "unsigned=" + !requireSecure);
MinecraftProfilePropertiesResponse response = (MinecraftProfilePropertiesResponse) MAKE_REQUEST.invoke(auth,
url, null, MinecraftProfilePropertiesResponse.class);
if (response == null)
return profile;
GameProfile result = new GameProfile(response.getId(), response.getName());
result.getProperties().putAll(response.getProperties());
profile.getProperties().putAll(response.getProperties());
return result;
}
public static void flyingMoveLogic(EntityLiving entity, float f, float f1) {
if (entity.bM()) {
if (entity.V()) {
@ -388,6 +340,10 @@ public class NMS {
return f;
}
public static GameProfileRepository getGameProfileRepository() {
return ((CraftServer) Bukkit.getServer()).getServer().getGameProfileRepository();
}
public static EntityLiving getHandle(LivingEntity entity) {
return (EntityLiving) getHandle((org.bukkit.entity.Entity) entity);
}
@ -423,6 +379,17 @@ public class NMS {
}
}
@Nullable
public static SkinnableEntity getSkinnable(org.bukkit.entity.Entity entity) {
Preconditions.checkNotNull(entity);
Entity nmsEntity = ((CraftEntity) entity).getHandle();
if (nmsEntity instanceof SkinnableEntity) {
return (SkinnableEntity) nmsEntity;
}
return null;
}
public static String getSound(String flag) throws CommandException {
try {
String ret = CraftSound.getSound(Sound.valueOf(flag.toUpperCase()));
@ -553,17 +520,11 @@ public class NMS {
((CraftServer) Bukkit.getServer()).getHandle().players.remove(handle);
}
public static void addOrRemoveFromPlayerList(org.bukkit.entity.Entity entity, boolean remove) {
if (entity == null)
return;
EntityHuman handle = (EntityHuman) getHandle(entity);
if (handle.world == null)
return;
if (remove) {
handle.world.players.remove(handle);
} else if (!handle.world.players.contains(handle)) {
handle.world.players.add(handle);
}
public static void removeFromWorld(org.bukkit.entity.Entity entity) {
Preconditions.checkNotNull(entity);
Entity nmsEntity = ((CraftEntity) entity).getHandle();
nmsEntity.world.removeEntity(nmsEntity);
}
@SuppressWarnings("rawtypes")
@ -621,6 +582,41 @@ public class NMS {
NMS.sendPacketsNearby(from, location, Arrays.asList(packets), 64);
}
public static void sendTabListAdd(Player recipient, Player listPlayer) {
Preconditions.checkNotNull(recipient);
Preconditions.checkNotNull(listPlayer);
EntityPlayer entity = ((CraftPlayer) listPlayer).getHandle();
sendPacket(recipient,
new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, entity));
}
public static void sendTabListRemove(Player recipient, Collection<? extends SkinnableEntity> skinnableNPCs) {
Preconditions.checkNotNull(recipient);
Preconditions.checkNotNull(skinnableNPCs);
EntityPlayer[] entities = new EntityPlayer[skinnableNPCs.size()];
int i = 0;
for (SkinnableEntity skinnable : skinnableNPCs) {
entities[i] = (EntityPlayer) skinnable;
i++;
}
sendPacket(recipient,
new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, entities));
}
public static void sendTabListRemove(Player recipient, Player listPlayer) {
Preconditions.checkNotNull(recipient);
Preconditions.checkNotNull(listPlayer);
EntityPlayer entity = ((CraftPlayer) listPlayer).getHandle();
sendPacket(recipient,
new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, entity));
}
public static void sendToOnline(Packet... packets) {
Validate.notNull(packets, "packets cannot be null");
for (Player player : Bukkit.getOnlinePlayers()) {
@ -800,16 +796,16 @@ public class NMS {
private static final Map<Class<?>, Constructor<?>> ENTITY_CONSTRUCTOR_CACHE = new WeakHashMap<Class<?>, Constructor<?>>();
private static Field GOAL_FIELD = getField(PathfinderGoalSelector.class, "b");
private static final Field JUMP_FIELD = getField(EntityLiving.class, "aY");
private static Method MAKE_REQUEST;
private static Field NAVIGATION_WORLD_FIELD = getField(NavigationAbstract.class, "c");
private static Field NETWORK_ADDRESS = getField(NetworkManager.class, "l");
private static Field NETWORK_CHANNEL = getField(NetworkManager.class, "channel");
private static final Location PACKET_CACHE_LOCATION = new Location(null, 0, 0, 0);
private static Field PATHFINDING_RANGE = getField(NavigationAbstract.class, "a");
private static final Random RANDOM = Util.getFastRandom();
private static Field SKULL_PROFILE_FIELD;
private static Field SKULL_PROFILE_FIELD;
private static Field TRACKED_ENTITY_SET = NMS.getField(EntityTracker.class, "c");
private static Method MAKE_REQUEST;
static {
try {