Fix guardian disguises

This commit fixes guardian disguises (esp. elder guardians) and also provides for disguises to modify packets before they're sent if necessary
This commit is contained in:
Dan Mulloy 2017-07-17 18:54:58 -04:00 committed by cnr
parent 8b39fa4e24
commit 7836e0aaaa
3 changed files with 163 additions and 34 deletions

View File

@ -360,6 +360,7 @@ public class DisguiseManager extends MiniPlugin implements IPacketHandler
final Packet packet = packetInfo.getPacket(); final Packet packet = packetInfo.getPacket();
final Player owner = packetInfo.getPlayer(); final Player owner = packetInfo.getPlayer();
final PacketVerifier packetVerifier = packetInfo.getVerifier(); final PacketVerifier packetVerifier = packetInfo.getVerifier();
final int protocol = ((CraftPlayer) owner).getHandle().getProtocol();
if (packet instanceof PacketPlayOutPlayerInfo) if (packet instanceof PacketPlayOutPlayerInfo)
{ {
@ -406,7 +407,7 @@ public class DisguiseManager extends MiniPlugin implements IPacketHandler
{ {
packetInfo.setCancelled(true); packetInfo.setCancelled(true);
handleSpawnPackets(packetInfo.getVerifier(), latestDisguise); handleSpawnPackets(packetInfo.getVerifier(), latestDisguise, protocol);
} }
else if (latestDisguise.isHideIfNotDisguised()) else if (latestDisguise.isHideIfNotDisguised())
{ {
@ -436,7 +437,7 @@ public class DisguiseManager extends MiniPlugin implements IPacketHandler
if (latestDisguise != null && containsSpawnDisguise(owner, latestDisguise) && owner.getEntityId() != entityId) if (latestDisguise != null && containsSpawnDisguise(owner, latestDisguise) && owner.getEntityId() != entityId)
{ {
packetInfo.setCancelled(true); packetInfo.setCancelled(true);
handlePacket(latestDisguise.getMetadataPacket(), packetVerifier); handlePacket(latestDisguise.modifyMetaPacket(protocol, latestDisguise.getMetadataPacket()), packetVerifier);
} }
} }
else if (packet instanceof PacketPlayOutEntityEquipment) else if (packet instanceof PacketPlayOutEntityEquipment)
@ -475,7 +476,7 @@ public class DisguiseManager extends MiniPlugin implements IPacketHandler
_handlingPacket = false; _handlingPacket = false;
} }
private void handleSpawnPackets(PacketVerifier packetVerifier, DisguiseBase disguise) private void handleSpawnPackets(PacketVerifier packetVerifier, DisguiseBase disguise, int protocol)
{ {
if (disguise instanceof DisguisePlayer) if (disguise instanceof DisguisePlayer)
{ {
@ -493,14 +494,14 @@ public class DisguiseManager extends MiniPlugin implements IPacketHandler
handlePacket(infoPacket, packetVerifier); handlePacket(infoPacket, packetVerifier);
} }
handlePacket(pDisguise.getSpawnPacket(), packetVerifier); handlePacket(pDisguise.modifySpawnPacket(protocol, pDisguise.getSpawnPacket()), packetVerifier);
for (Packet packet : pDisguise.getEquipmentPackets()) for (Packet packet : pDisguise.getEquipmentPackets())
{ {
handlePacket(packet, packetVerifier); handlePacket(packet, packetVerifier);
} }
handlePacket(pDisguise.getMetadataPacket(), packetVerifier); handlePacket(pDisguise.modifyMetaPacket(protocol, pDisguise.getMetadataPacket()), packetVerifier);
if (pDisguise.getSleepingDirection() != null) if (pDisguise.getSleepingDirection() != null)
{ {
@ -556,7 +557,7 @@ public class DisguiseManager extends MiniPlugin implements IPacketHandler
} }
else else
{ {
handlePacket(disguise.getSpawnPacket(), packetVerifier); handlePacket(disguise.modifySpawnPacket(protocol, disguise.getSpawnPacket()), packetVerifier);
if (disguise instanceof DisguiseLiving) if (disguise instanceof DisguiseLiving)
{ {
@ -644,10 +645,12 @@ public class DisguiseManager extends MiniPlugin implements IPacketHandler
{ {
if (tester.test(player)) if (tester.test(player))
{ {
if (disguise.getEntity() == ((CraftPlayer) player).getHandle()) EntityPlayer nmsPlayer = ((CraftPlayer) player).getHandle();
if (disguise.getEntity() == nmsPlayer)
continue; continue;
UtilPlayer.sendPacket(player, disguise.getMetadataPacket()); int protocol = nmsPlayer.getProtocol();
UtilPlayer.sendPacket(player, disguise.modifyMetaPacket(protocol, disguise.getMetadataPacket()));
} }
} }
} }

View File

@ -2,16 +2,9 @@ package mineplex.core.disguise.disguises;
import mineplex.core.common.DummyEntity; import mineplex.core.common.DummyEntity;
import mineplex.core.common.util.UtilPlayer; import mineplex.core.common.util.UtilPlayer;
import net.minecraft.server.v1_8_R3.DataWatcher;
import net.minecraft.server.v1_8_R3.Entity; import net.minecraft.server.v1_8_R3.*;
import net.minecraft.server.v1_8_R3.EntityPlayer;
import net.minecraft.server.v1_8_R3.EntityTrackerEntry;
import net.minecraft.server.v1_8_R3.IntHashMap;
import net.minecraft.server.v1_8_R3.MinecraftServer;
import net.minecraft.server.v1_8_R3.Packet;
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityMetadata;
import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo;
import net.minecraft.server.v1_8_R3.WorldServer;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -21,6 +14,8 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
public abstract class DisguiseBase public abstract class DisguiseBase
{ {
@ -72,15 +67,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)); DataWatcher.watch(1, getEntity().getDataWatcher().getShort(1), net.minecraft.server.v1_8_R3.Entity.META_AIR, (int) getEntity().getDataWatcher().getShort(1));
} }
public abstract Packet getSpawnPacket(); public void sendToWatchers(Supplier<Packet> supplier)
public Packet getMetadataPacket()
{
UpdateDataWatcher();
return new PacketPlayOutEntityMetadata(getEntity().getId(), DataWatcher, true);
}
public void resendMetadata()
{ {
if (getEntity() == null || !getEntity().getBukkitEntity().isValid() || !(getEntity().world instanceof WorldServer)) if (getEntity() == null || !getEntity().getBukkitEntity().isValid() || !(getEntity().world instanceof WorldServer))
return; return;
@ -90,14 +77,48 @@ public abstract class DisguiseBase
if (tracker.get(getEntity().getId()) == null) if (tracker.get(getEntity().getId()) == null)
return; return;
Packet packet = getMetadataPacket(); Packet packet = supplier.get();
if (packet == null)
return;
for (EntityPlayer player : tracker.get(getEntity().getId()).trackedPlayers) for (EntityPlayer player : tracker.get(getEntity().getId()).trackedPlayers)
{ {
UtilPlayer.sendPacket(player.getBukkitEntity(), packet); if (packet instanceof PacketPlayOutEntityMetadata)
{
player.playerConnection.sendPacket(modifyMetaPacket(player.getProtocol(), packet));
} else if (packet instanceof PacketPlayOutSpawnEntityLiving)
{
player.playerConnection.sendPacket(modifySpawnPacket(player.getProtocol(), packet));
} else
{
player.playerConnection.sendPacket(packet);
}
} }
} }
public abstract Packet getSpawnPacket();
public Packet modifySpawnPacket(int protocol, Packet packet)
{
return packet;
}
public Packet getMetadataPacket()
{
UpdateDataWatcher();
return new PacketPlayOutEntityMetadata(getEntity().getId(), DataWatcher, true);
}
public void resendMetadata()
{
sendToWatchers(this::getMetadataPacket);
}
public Packet modifyMetaPacket(int protocol, Packet packet)
{
return packet;
}
public void setSoundDisguise(DisguiseBase soundDisguise) public void setSoundDisguise(DisguiseBase soundDisguise)
{ {
_soundDisguise = soundDisguise; _soundDisguise = soundDisguise;
@ -197,7 +218,7 @@ public abstract class DisguiseBase
return this._disguiseType; return this._disguiseType;
} }
public void setEntity(net.minecraft.server.v1_8_R3.Entity entity) public void setEntity(Entity entity)
{ {
_entity.clear(); _entity.clear();
_entity = new WeakReference<>(entity); _entity = new WeakReference<>(entity);

View File

@ -1,11 +1,23 @@
package mineplex.core.disguise.disguises; package mineplex.core.disguise.disguises;
import org.bukkit.entity.*; 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 DisguiseCreature
{ {
private int target = 0;
private boolean elder = false;
public DisguiseGuardian(org.bukkit.entity.Entity entity) public DisguiseGuardian(org.bukkit.entity.Entity entity)
{ {
super(EntityType.GUARDIAN, entity); super(EntityType.GUARDIAN, entity);
@ -15,17 +27,33 @@ public class DisguiseGuardian extends DisguiseCreature
public void setTarget(int target) public void setTarget(int target)
{ {
this.target = target;
DataWatcher.watch(17, target, EntityGuardian.META_TARGET, target); DataWatcher.watch(17, target, EntityGuardian.META_TARGET, target);
} }
public void setElder(boolean elder) public void setElder(boolean elder)
{ {
DataWatcher.watch(16, Integer.valueOf(DataWatcher.getInt(16) | 4), EntityGuardian.META_ELDER, (byte) (DataWatcher.getInt(16) | 4)); this.elder = elder;
int oldValue = DataWatcher.getInt(16);
int newValue = elder ? oldValue | 4 : oldValue & ~4;
DataWatcher.watch(16, Integer.valueOf(newValue), EntityGuardian.META_ELDER, (byte) newValue);
sendToWatchers(() -> new PacketPlayOutEntityDestroy(new int[]{getEntityId()}));
sendToWatchers(this::getSpawnPacket);
sendToWatchers(this::getMetadataPacket);
} }
public boolean isElder() public boolean isElder()
{ {
return (this.DataWatcher.getInt(16) & 4) != 0; return elder;
}
public int getTarget()
{
return target;
} }
protected String getHurtSound() protected String getHurtSound()
@ -37,4 +65,81 @@ public class DisguiseGuardian extends DisguiseCreature
return "mob.guardian.hit"; return "mob.guardian.hit";
} }
// ---- Packet modification for 1.11 and up
@Override
public Packet modifySpawnPacket(int protocol, Packet packet)
{
if (protocol >= ProtocolVersion.v1_11)
{
PacketPlayOutSpawnEntityLiving newSpawn = (PacketPlayOutSpawnEntityLiving) getSpawnPacket();
if (isElder()) newSpawn.b = 4;
newSpawn.m = processSpawnMeta(DataWatcher.c());
return newSpawn;
}
return packet;
}
@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());
}
private List<WatchableObject> processSpawnMeta(List<WatchableObject> list)
{
List<MetaWrapper> newMeta = new ArrayList<>();
for (WatchableObject meta : list)
{
MetaWrapper wrapper = new MetaWrapper(meta);
if (wrapper.getIndex() >= 5) // 1.10
{
wrapper.setIndex(wrapper.getIndex() + 1);
}
if (getEntity() instanceof EntityArmorStand && (wrapper.getIndex() == 12 || wrapper.getIndex() == 13))
{
continue;
}
if (wrapper.getIndex() < 12) // Skip higher ones in 1.11
{
newMeta.add(wrapper);
} else if (wrapper.getIndex() == 12)
{
byte value = (byte) wrapper.getValue();
newMeta.add(new MetaWrapper(12, DataType.BOOLEAN, (value & 0x02) != 0));
}
}
return newMeta.stream().map(MetaWrapper::toWatchableObject).collect(Collectors.toList());
}
} }