Fix skeleton disguises appearing invisible

This commit is contained in:
Dan Mulloy 2017-07-28 17:20:04 -04:00
parent ebd9986542
commit c69f67b3e8
7 changed files with 228 additions and 93 deletions

View File

@ -228,6 +228,9 @@ public class DisguiseManager extends MiniPlugin implements IPacketHandler
if (!spawnedIn)
{
refreshTrackers(disguise.getEntity().getBukkitEntity());
} else
{
disguise.markSpawnedIn();
}
disguise.onDisguise(true);

View File

@ -1,7 +1,11 @@
package mineplex.core.disguise.disguises;
import mineplex.core.common.DummyEntity;
import mineplex.core.common.util.UtilPlayer;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.function.Supplier;
import net.minecraft.server.v1_8_R3.*;
@ -10,12 +14,8 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
import mineplex.core.common.DummyEntity;
import mineplex.core.common.util.UtilPlayer;
public abstract class DisguiseBase
{
@ -32,6 +32,8 @@ public abstract class DisguiseBase
*/
private boolean _hideIfNotDisguised = false;
protected boolean _spawnedIn = false;
public DisguiseBase(EntityType entityType, org.bukkit.entity.Entity entity)
{
if (entity == null)
@ -67,7 +69,7 @@ public abstract class DisguiseBase
DataWatcher.watch(1, getEntity().getDataWatcher().getShort(1), net.minecraft.server.v1_8_R3.Entity.META_AIR, (int) getEntity().getDataWatcher().getShort(1));
}
public void sendToWatchers(Supplier<Packet> supplier)
protected void sendToWatchers(Predicate<Integer> protocolPredicate, Supplier<Packet> supplier)
{
if (getEntity() == null || !getEntity().getBukkitEntity().isValid() || !(getEntity().world instanceof WorldServer))
return;
@ -83,12 +85,16 @@ public abstract class DisguiseBase
for (EntityPlayer player : tracker.get(getEntity().getId()).trackedPlayers)
{
int protocol = player.getProtocol();
if (!protocolPredicate.test(protocol))
continue;
if (packet instanceof PacketPlayOutEntityMetadata)
{
player.playerConnection.sendPacket(modifyMetaPacket(player.getProtocol(), packet));
player.playerConnection.sendPacket(modifyMetaPacket(protocol, packet));
} else if (packet instanceof PacketPlayOutSpawnEntityLiving)
{
player.playerConnection.sendPacket(modifySpawnPacket(player.getProtocol(), packet));
player.playerConnection.sendPacket(modifySpawnPacket(protocol, packet));
} else
{
player.playerConnection.sendPacket(packet);
@ -96,6 +102,11 @@ public abstract class DisguiseBase
}
}
protected void sendToWatchers(Supplier<Packet> supplier)
{
sendToWatchers(x -> true, supplier);
}
public abstract Packet getSpawnPacket();
public Packet modifySpawnPacket(int protocol, Packet packet)
@ -203,6 +214,11 @@ public abstract class DisguiseBase
}
public void markSpawnedIn()
{
_spawnedIn = true;
}
public void setHideIfNotDisguised(boolean hideIfNotDisguised)
{
this._hideIfNotDisguised = hideIfNotDisguised;

View File

@ -1,10 +1,10 @@
package mineplex.core.disguise.disguises;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import com.mineplex.MetaWrapper;
import com.mineplex.MetadataRewriter;
import com.mineplex.ProtocolVersion;
import net.minecraft.server.v1_8_R3.*;
@ -78,45 +78,112 @@ public abstract class DisguiseCreature extends DisguiseInsentient
return packet;
}
// ---- Metadata processing
// This WON'T be post-processed by the Spigot metadata processor
@Override
public Packet modifySpawnPacket(int protocol, Packet packet)
{
if (protocol >= ProtocolVersion.v1_10_PRE)
{
PacketPlayOutSpawnEntityLiving newSpawn = (PacketPlayOutSpawnEntityLiving) getSpawnPacket();
newSpawn.m = processSpawnMeta(protocol, DataWatcher.c());
// Allow the entity type to be changed (needed on 1.11+)
newSpawn.b = getTypeId(protocol >= ProtocolVersion.v1_11);
boolean hasArms = false;
List<WatchableObject> meta = DataWatcher.b();
if (meta != null)
{
// Run the meta through our Spigot rewriter
meta = MetadataRewriter.rewrite(getTypeId(false), protocol, meta).objects;
// Remove indexes >= 12 on 1.11+
if (protocol >= ProtocolVersion.v1_11)
{
Iterator<WatchableObject> iter = meta.iterator();
while (iter.hasNext())
{
WatchableObject next = iter.next();
if (next.getIndex().a() == 6)
{
hasArms = true;
} else if (next.getIndex().a() >= 12)
{
iter.remove();
}
}
}
} else
{
meta = new ArrayList<>();
}
if (!hasArms)
{
WatchableObject<Byte> arms = new WatchableObject<>(0, 0, null,
new DataIndex<>(6, DataType.BYTE), (byte) 0);
meta.add(arms);
}
newSpawn.m = meta;
return newSpawn;
}
return packet;
}
private List<WatchableObject> processSpawnMeta(int protocol, List<WatchableObject> list)
protected int getTypeId(boolean separate)
{
List<MetaWrapper> newMeta = new ArrayList<>();
for (WatchableObject meta : list)
return getDisguiseType().getTypeId();
}
// This WILL be post-processed by Spigot's metadata processor
@Override
public Packet modifyMetaPacket(int protocol, Packet packet)
{
if (protocol >= ProtocolVersion.v1_10_PRE)
{
MetaWrapper wrapper = new MetaWrapper(meta);
if (wrapper.getIndex() >= 5) // 1.10
PacketPlayOutEntityMetadata newMeta = new PacketPlayOutEntityMetadata();
newMeta.a = getEntityId();
boolean hasArms = false;
List<WatchableObject> meta = DataWatcher.b();
List<WatchableObject> adjusted = new ArrayList<>();
if (meta != null)
{
wrapper.setIndex(wrapper.getIndex() + 1);
// Process the meta while we know the entity id
adjusted = MetadataRewriter.rewrite(getTypeId(false), protocol, meta).objects;
hasArms = meta.stream().anyMatch(obj -> obj.getIndex().a() == 6);
}
if (protocol < ProtocolVersion.v1_11)
for (int i = 0; i < adjusted.size(); i++)
{
newMeta.add(wrapper);
continue;
WatchableObject object = adjusted.get(i);
int index = object.getIndex().a();
if (index >= 6)
{
index--;
adjusted.set(i, new WatchableObject(0, 0, null,
new DataIndex(index, object.getIndex().b()), object.getValue()));
}
}
if (getEntity() instanceof EntityArmorStand && wrapper.getIndex() >= 12)
if (!hasArms)
{
// Armor stand meta conflicts with a lot of entities on 1.11+
continue;
WatchableObject<Byte> arms = new WatchableObject<>(0, 0, null,
new DataIndex<>(5, DataType.BYTE), (byte) 0);
adjusted.add(arms);
}
newMeta.add(wrapper);
newMeta.b = adjusted;
return newMeta;
}
return newMeta.stream().map(MetaWrapper::toWatchableObject).collect(Collectors.toList());
return packet;
}
}

View File

@ -1,20 +1,14 @@
package mineplex.core.disguise.disguises;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import net.minecraft.server.v1_8_R3.EntityGuardian;
import com.mineplex.MetaWrapper;
import com.mineplex.ProtocolVersion;
import net.minecraft.server.v1_8_R3.*;
import net.minecraft.server.v1_8_R3.DataWatcher.WatchableObject;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.EntityType;
public class DisguiseGuardian extends DisguiseCreature
public class DisguiseGuardian extends DisguiseMutable
{
private static final int GUARDIAN_ID = 68;
private static final int ELDER_GUARDIAN_ID = 4;
private int target = 0;
private boolean elder = false;
@ -41,9 +35,7 @@ public class DisguiseGuardian extends DisguiseCreature
DataWatcher.watch(16, Integer.valueOf(newValue), EntityGuardian.META_ELDER, (byte) newValue);
sendToWatchers(() -> new PacketPlayOutEntityDestroy(new int[]{getEntityId()}));
sendToWatchers(this::getSpawnPacket);
sendToWatchers(this::getMetadataPacket);
mutate();
}
public boolean isElder()
@ -66,49 +58,9 @@ public class DisguiseGuardian extends DisguiseCreature
return "mob.guardian.hit";
}
// ---- Packet modification for 1.11 and up
@Override
public Packet modifySpawnPacket(int protocol, Packet packet)
protected int getTypeId(boolean separate)
{
PacketPlayOutSpawnEntityLiving newSpawn = (PacketPlayOutSpawnEntityLiving) super.modifySpawnPacket(protocol, packet);
if (protocol >= ProtocolVersion.v1_11 && isElder())
{
newSpawn.b = 4;
}
return newSpawn;
}
@Override
public Packet modifyMetaPacket(int protocol, Packet packet)
{
if (protocol >= ProtocolVersion.v1_11)
{
PacketPlayOutEntityMetadata newPacket = (PacketPlayOutEntityMetadata) getMetadataPacket();
newPacket.b = processMeta(newPacket.b);
return newPacket;
}
return packet;
}
private List<WatchableObject> processMeta(List<WatchableObject> list)
{
List<MetaWrapper> newMeta = new ArrayList<>();
for (WatchableObject meta : list)
{
MetaWrapper wrapper = new MetaWrapper(meta);
if (wrapper.getIndex() == 11)
{
byte value = (byte) wrapper.getValue();
newMeta.add(new MetaWrapper(11, DataType.BOOLEAN, (value & 0x02) != 0));
} else
{
newMeta.add(wrapper);
}
}
return newMeta.stream().map(MetaWrapper::toWatchableObject).collect(Collectors.toList());
return separate && isElder() ? ELDER_GUARDIAN_ID : GUARDIAN_ID;
}
}

View File

@ -2,14 +2,24 @@ package mineplex.core.disguise.disguises;
import java.util.UUID;
import net.minecraft.server.v1_8_R3.EntityHorse;
import org.bukkit.entity.*;
import com.google.common.base.Optional;
public class DisguiseHorse extends DisguiseAnimal
import net.minecraft.server.v1_8_R3.EntityAgeable;
import net.minecraft.server.v1_8_R3.EntityHorse;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Horse;
public class DisguiseHorse extends DisguiseMutable
{
private static final int HORSE_ID = 100;
private static final int DONKEY_ID = 31;
private static final int MULE_ID = 32;
private static final int ZOMBIE_HORSE_ID = 29;
private static final int SKELETON_HORSE_ID = 28;
private Horse.Variant variant = Horse.Variant.HORSE;
public DisguiseHorse(org.bukkit.entity.Entity entity)
{
super(EntityType.HORSE, entity);
@ -19,11 +29,25 @@ public class DisguiseHorse extends DisguiseAnimal
DataWatcher.a(20, Integer.valueOf(0), EntityHorse.META_VARIANT, 0);
DataWatcher.a(21, String.valueOf(""), EntityHorse.META_OWNER, Optional.<UUID> absent());
DataWatcher.a(22, Integer.valueOf(0), EntityHorse.META_ARMOR, 0);
DataWatcher.a(12, new Byte((byte)0), EntityAgeable.META_BABY, false);
}
public boolean isBaby()
{
return DataWatcher.getByte(12) < 0;
}
public void setBaby()
{
DataWatcher.watch(12, new Byte((byte) ( -1 )), EntityAgeable.META_BABY, true);
}
public void setType(Horse.Variant horseType)
{
DataWatcher.watch(19, Byte.valueOf((byte) horseType.ordinal()), EntityHorse.META_TYPE, horseType.ordinal());
this.variant = horseType;
mutate();
}
public Horse.Variant getType()
@ -72,4 +96,23 @@ public class DisguiseHorse extends DisguiseAnimal
{
DataWatcher.watch(22, Integer.valueOf(i), EntityHorse.META_ARMOR, i);
}
// 1.11 and up require separate entity ids
@Override
protected int getTypeId(boolean separate)
{
if (separate && variant != Horse.Variant.HORSE)
{
switch (variant)
{
case DONKEY: return DONKEY_ID;
case MULE: return MULE_ID;
case UNDEAD_HORSE: return ZOMBIE_HORSE_ID;
case SKELETON_HORSE: return SKELETON_HORSE_ID;
default: return HORSE_ID;
}
}
return HORSE_ID;
}
}

View File

@ -0,0 +1,40 @@
package mineplex.core.disguise.disguises;
import java.util.function.Predicate;
import com.mineplex.ProtocolVersion;
import net.minecraft.server.v1_8_R3.Packet;
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
/**
* Represents a disguise that can "mutate" from one entity type to another.
*/
public abstract class DisguiseMutable extends DisguiseCreature
{
public DisguiseMutable(EntityType disguiseType, Entity entity)
{
super(disguiseType, entity);
}
protected void mutate()
{
// if (!_spawnedIn)
// return;
Predicate<Integer> pred = v -> v >= ProtocolVersion.v1_11;
sendToWatchers(pred, this::getDestroyPacket);
sendToWatchers(pred, this::getSpawnPacket);
sendToWatchers(pred, this::getMetadataPacket);
}
private Packet getDestroyPacket()
{
return new PacketPlayOutEntityDestroy(new int[] { getEntityId() });
}
protected abstract int getTypeId(boolean separate);
}

View File

@ -2,11 +2,16 @@ package mineplex.core.disguise.disguises;
import net.minecraft.server.v1_8_R3.EntitySkeleton;
import org.bukkit.entity.*;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Skeleton.SkeletonType;
public class DisguiseSkeleton extends DisguiseMonster
public class DisguiseSkeleton extends DisguiseMutable
{
private static final int SKELETON_ID = 51;
private static final int WITHER_SKELETON_ID = 5;
private SkeletonType type = SkeletonType.NORMAL;
public DisguiseSkeleton(org.bukkit.entity.Entity entity)
{
super(EntityType.SKELETON, entity);
@ -17,15 +22,24 @@ public class DisguiseSkeleton extends DisguiseMonster
public void SetSkeletonType(SkeletonType skeletonType)
{
DataWatcher.watch(13, Byte.valueOf((byte) skeletonType.getId()), EntitySkeleton.META_TYPE, skeletonType.getId());
this.type = skeletonType;
mutate();
}
public int GetSkeletonType()
public SkeletonType getSkeletonType()
{
return DataWatcher.getByte(13);
return type;
}
protected String getHurtSound()
{
return "mob.skeleton.hurt";
}
// 1.11 and up require separate entity ids
@Override
protected int getTypeId(boolean separate)
{
return separate && type == SkeletonType.WITHER ? WITHER_SKELETON_ID : SKELETON_ID;
}
}