Fix modded entities
This commit is contained in:
		| @@ -1,6 +1,6 @@ | ||||
| package me.libraryaddict.disguise.commands.libsdisguises; | ||||
|  | ||||
| import me.libraryaddict.disguise.LibsDisguises; | ||||
| import me.libraryaddict.disguise.utilities.modded.ModdedManager; | ||||
| import me.libraryaddict.disguise.utilities.translations.LibsMsg; | ||||
| import org.apache.commons.lang.StringUtils; | ||||
| import org.bukkit.Bukkit; | ||||
| @@ -26,7 +26,7 @@ public class LDMods implements LDCommand { | ||||
|  | ||||
|     @Override | ||||
|     public void onCommand(CommandSender sender, String[] args) { | ||||
|         if (!Bukkit.getMessenger().isOutgoingChannelRegistered(LibsDisguises.getInstance(), "fml:handshake")) { | ||||
|         if (ModdedManager.getEntities().isEmpty()) { | ||||
|             sender.sendMessage(LibsMsg.NO_MODS_LISTENING.get()); | ||||
|             return; | ||||
|         } | ||||
|   | ||||
| @@ -316,19 +316,6 @@ public class DisguiseListener implements Listener { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @EventHandler | ||||
|     public void onLogin(PlayerRegisterChannelEvent event) { | ||||
|         Player player = event.getPlayer(); | ||||
|  | ||||
|         // If it's not a forge handshake, or we didn't register it | ||||
|         if (!event.getChannel().equals("fml:handshake") || | ||||
|                 !Bukkit.getMessenger().isOutgoingChannelRegistered(LibsDisguises.getInstance(), "fml:handshake")) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         player.sendPluginMessage(LibsDisguises.getInstance(), "fml:handshake", ModdedManager.getFmlHandshake()); | ||||
|     } | ||||
|  | ||||
|     @EventHandler | ||||
|     public void onJoin(PlayerJoinEvent event) { | ||||
|         Player p = event.getPlayer(); | ||||
|   | ||||
| @@ -0,0 +1,44 @@ | ||||
| package me.libraryaddict.disguise.utilities.listeners; | ||||
|  | ||||
| import me.libraryaddict.disguise.LibsDisguises; | ||||
| import me.libraryaddict.disguise.utilities.modded.ModdedEntity; | ||||
| import me.libraryaddict.disguise.utilities.modded.ModdedManager; | ||||
| import org.bukkit.entity.Player; | ||||
| import org.bukkit.event.EventHandler; | ||||
| import org.bukkit.event.EventPriority; | ||||
| import org.bukkit.event.Listener; | ||||
| import org.bukkit.event.player.PlayerLoginEvent; | ||||
| import org.bukkit.metadata.FixedMetadataValue; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| /** | ||||
|  * Created by libraryaddict on 11/06/2020. | ||||
|  */ | ||||
| public class ModdedListener implements Listener { | ||||
|     @EventHandler(priority = EventPriority.LOWEST) | ||||
|     public void onLogin(PlayerLoginEvent event) { | ||||
|         Player player = event.getPlayer(); | ||||
|  | ||||
|         ArrayList<String> mods = ModdedManager.getForgeMods().getIfPresent(player.getName()); | ||||
|  | ||||
|         player.setMetadata("forge_mods", new FixedMetadataValue(LibsDisguises.getInstance(), mods)); | ||||
|  | ||||
|         for (ModdedEntity e : ModdedManager.getEntities().values()) { | ||||
|             if (e.getMod() == null) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (mods.contains(e.getMod().toLowerCase())) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (e.getRequired() == null) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             player.kickPlayer(e.getRequired()); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,43 +1,51 @@ | ||||
| package me.libraryaddict.disguise.utilities.modded; | ||||
|  | ||||
| import com.comphenix.protocol.ProtocolLibrary; | ||||
| import com.comphenix.protocol.utility.StreamSerializer; | ||||
| import com.google.common.cache.Cache; | ||||
| import com.google.common.cache.CacheBuilder; | ||||
| import lombok.Getter; | ||||
| import me.libraryaddict.disguise.LibsDisguises; | ||||
| import me.libraryaddict.disguise.disguisetypes.DisguiseType; | ||||
| import me.libraryaddict.disguise.utilities.listeners.ModdedListener; | ||||
| import me.libraryaddict.disguise.utilities.packets.packetlisteners.PacketListenerModdedClient; | ||||
| import me.libraryaddict.disguise.utilities.parser.DisguisePerm; | ||||
| import me.libraryaddict.disguise.utilities.reflection.ReflectionManager; | ||||
| import org.bukkit.Bukkit; | ||||
| import org.bukkit.NamespacedKey; | ||||
| import org.bukkit.entity.Player; | ||||
| import org.bukkit.metadata.FixedMetadataValue; | ||||
| import org.bukkit.plugin.messaging.PluginMessageListener; | ||||
|  | ||||
| import java.io.*; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.DataOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| /** | ||||
|  * Created by libraryaddict on 14/04/2020. | ||||
|  */ | ||||
| public class ModdedManager implements PluginMessageListener { | ||||
| public class ModdedManager { | ||||
|     @Getter | ||||
|     private static final HashMap<NamespacedKey, ModdedEntity> entities = new HashMap<>(); | ||||
|     @Getter | ||||
|     private static byte[] fmlHandshake; | ||||
|     @Getter | ||||
|     private static byte[] fmlRegistries; | ||||
|     @Getter | ||||
|     private static final Cache<String, ArrayList<String>> forgeMods = CacheBuilder.newBuilder() | ||||
|             .expireAfterWrite(1, TimeUnit.MINUTES).build(); | ||||
|  | ||||
|     public ModdedManager(ArrayList<String> channels) { | ||||
|         if (getEntities().isEmpty()) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (getEntities().values().stream().noneMatch(e -> e.getMod() != null)) { | ||||
|             return; | ||||
|         if (fmlRegistries == null) { | ||||
|             ProtocolLibrary.getProtocolManager().addPacketListener(new PacketListenerModdedClient()); | ||||
|             Bukkit.getPluginManager().registerEvents(new ModdedListener(), LibsDisguises.getInstance()); | ||||
|         } | ||||
|  | ||||
|         Bukkit.getMessenger().registerOutgoingPluginChannel(LibsDisguises.getInstance(), "fml:handshake"); | ||||
|         Bukkit.getMessenger().registerIncomingPluginChannel(LibsDisguises.getInstance(), "fml:handshake", this); | ||||
|  | ||||
|         ByteArrayOutputStream stream = new ByteArrayOutputStream(); | ||||
|         DataOutputStream output = new DataOutputStream(stream); | ||||
|  | ||||
| @@ -57,14 +65,58 @@ public class ModdedManager implements PluginMessageListener { | ||||
|                 s.serializeString(output, channel.substring(channel.indexOf("|") + 1)); | ||||
|             } | ||||
|  | ||||
|             // We have no resources to declare | ||||
|             // We want to declare some entities | ||||
|             s.serializeVarInt(output, 0); | ||||
|  | ||||
|             // Only this one thx | ||||
|             // s.serializeString(output, "minecraft:entity_type"); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|  | ||||
|         fmlHandshake = stream.toByteArray(); | ||||
|  | ||||
|         stream = new ByteArrayOutputStream(); | ||||
|         output = new DataOutputStream(stream); | ||||
|  | ||||
|         s = StreamSerializer.getDefault(); | ||||
|  | ||||
|         try { | ||||
|             // Packet id 3 | ||||
|             s.serializeVarInt(output, 3); | ||||
|  | ||||
|             // What registry we're modifying | ||||
|             s.serializeString(output, "minecraft:entity_type"); | ||||
|             // Yes... We're doing custom data | ||||
|             s.serializeVarInt(output, 1); | ||||
|  | ||||
|             // We have this many entities | ||||
|             s.serializeVarInt(output, entities.size()); | ||||
|  | ||||
|             // Write the entity names and ids | ||||
|             for (Map.Entry<NamespacedKey, ModdedEntity> entry : entities.entrySet()) { | ||||
|                 s.serializeString(output, entry.getKey().toString()); | ||||
|                 s.serializeVarInt(output, entry.getValue().getTypeId()); | ||||
|             } | ||||
|  | ||||
|             // Sir, we do not want to declare aliases | ||||
|             s.serializeVarInt(output, 0); | ||||
|  | ||||
|             // Or overrides | ||||
|             s.serializeVarInt(output, 0); | ||||
|  | ||||
|             // No.. Not even blocked | ||||
|             s.serializeVarInt(output, 0); | ||||
|  | ||||
|             // Or dummied | ||||
|             s.serializeVarInt(output, 0); | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|  | ||||
|         fmlRegistries = stream.toByteArray(); | ||||
|     } | ||||
|  | ||||
|     public static void registerModdedEntity(NamespacedKey name, ModdedEntity entity, boolean register) { | ||||
| @@ -76,20 +128,22 @@ public class ModdedManager implements PluginMessageListener { | ||||
|             throw new IllegalArgumentException("Modded entity " + entity.getName() + " has already been registered"); | ||||
|         } | ||||
|  | ||||
|         Object entityType; | ||||
|  | ||||
|         if (register) { | ||||
|             Object entityType = ReflectionManager.registerEntityType(name); | ||||
|             entityType = ReflectionManager.registerEntityType(name); | ||||
|             int entityId = ReflectionManager.getEntityTypeId(entityType); | ||||
|  | ||||
|             entity.setTypeId(entityId); | ||||
|             entity.setEntityType(entityType); | ||||
|         } else { | ||||
|             Object entityType = ReflectionManager.getEntityType(name); | ||||
|             entityType = ReflectionManager.getEntityType(name); | ||||
|             int entityId = ReflectionManager.getEntityTypeId(entityType); | ||||
|  | ||||
|             entity.setTypeId(entityId); | ||||
|             entity.setEntityType(entityType); | ||||
|         } | ||||
|  | ||||
|         entity.setEntityType(entityType); | ||||
|  | ||||
|         entities.put(name, entity); | ||||
|     } | ||||
|  | ||||
| @@ -120,54 +174,4 @@ public class ModdedManager implements PluginMessageListener { | ||||
|  | ||||
|         return perms; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onPluginMessageReceived(String channel, Player player, byte[] bytes) { | ||||
|         if (player.hasMetadata("forge_mods")) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         DataInputStream stream = new DataInputStream(new ByteArrayInputStream(bytes)); | ||||
|  | ||||
|         try { | ||||
|             StreamSerializer s = StreamSerializer.getDefault(); | ||||
|             int packetId = s.deserializeVarInt(stream); | ||||
|  | ||||
|             if (packetId != 2) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             int count = s.deserializeVarInt(stream); | ||||
|  | ||||
|             ArrayList<String> mods = new ArrayList<>(); | ||||
|  | ||||
|             for (int i = 0; i < count; i++) { | ||||
|                 mods.add(s.deserializeString(stream, 256)); | ||||
|             } | ||||
|  | ||||
|             player.setMetadata("forge_mods", new FixedMetadataValue(LibsDisguises.getInstance(), mods)); | ||||
|  | ||||
|             for (ModdedEntity e : getEntities().values()) { | ||||
|                 if (e.getMod() == null) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 if (mods.contains(e.getMod().toLowerCase())) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 // TODO Idk, something because they don't have a mod? | ||||
|  | ||||
|                 if (e.getRequired() == null) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 player.kickPlayer(e.getRequired()); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,161 @@ | ||||
| package me.libraryaddict.disguise.utilities.packets.packetlisteners; | ||||
|  | ||||
| import com.comphenix.protocol.PacketType; | ||||
| import com.comphenix.protocol.ProtocolLibrary; | ||||
| import com.comphenix.protocol.events.PacketAdapter; | ||||
| import com.comphenix.protocol.events.PacketContainer; | ||||
| import com.comphenix.protocol.events.PacketEvent; | ||||
| import com.comphenix.protocol.wrappers.MinecraftKey; | ||||
| import com.google.common.cache.Cache; | ||||
| import com.google.common.cache.CacheBuilder; | ||||
| import com.mojang.authlib.GameProfile; | ||||
| import io.netty.buffer.ByteBuf; | ||||
| import io.netty.buffer.Unpooled; | ||||
| import io.netty.handler.codec.DecoderException; | ||||
| import me.libraryaddict.disguise.LibsDisguises; | ||||
| import me.libraryaddict.disguise.utilities.modded.ModdedManager; | ||||
| import net.minecraft.server.v1_15_R1.PacketDataSerializer; | ||||
| import org.bukkit.entity.Player; | ||||
|  | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.util.ArrayList; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| /** | ||||
|  * Created by libraryaddict on 11/06/2020. | ||||
|  */ | ||||
| public class PacketListenerModdedClient extends PacketAdapter { | ||||
|     private final Cache<String, String> loginAttempts = CacheBuilder.newBuilder().expireAfterWrite(15, TimeUnit.SECONDS) | ||||
|             .build(); | ||||
|     private final int packetId1 = 5555554, packetId2 = 5555555; | ||||
|  | ||||
|     public PacketListenerModdedClient() { | ||||
|         super(LibsDisguises.getInstance(), PacketType.Login.Client.START, PacketType.Login.Client.CUSTOM_PAYLOAD); | ||||
|     } | ||||
|  | ||||
|     private int getInt(ByteBuf buf) { | ||||
|         int i = 0; | ||||
|         int j = 0; | ||||
|  | ||||
|         byte b0; | ||||
|         do { | ||||
|             b0 = buf.readByte(); | ||||
|             i |= (b0 & 127) << j++ * 7; | ||||
|             if (j > 5) { | ||||
|                 throw new RuntimeException("VarInt too big"); | ||||
|             } | ||||
|         } while ((b0 & 128) == 128); | ||||
|  | ||||
|         return i; | ||||
|     } | ||||
|  | ||||
|     private void handleModlist(Player player, String name, byte[] data) { | ||||
|         ByteBuf buf = Unpooled.copiedBuffer(data); | ||||
|  | ||||
|         int packetId = getInt(buf); | ||||
|  | ||||
|         if (packetId != 2) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         int count = getInt(buf); | ||||
|         ArrayList<String> mods = new ArrayList<>(); | ||||
|  | ||||
|         for (int i = 0; i < count; i++) { | ||||
|             mods.add(getString(buf)); | ||||
|         } | ||||
|  | ||||
|         ModdedManager.getForgeMods().put(name, mods); | ||||
|     } | ||||
|  | ||||
|     public String getString(ByteBuf buf) { | ||||
|         int j = getInt(buf); | ||||
|         int size = 256; | ||||
|  | ||||
|         if (j > size * 4) { | ||||
|             throw new DecoderException( | ||||
|                     "The received encoded string buffer length is longer than maximum allowed (" + j + " > " + | ||||
|                             size * 4 + ")"); | ||||
|         } else if (j < 0) { | ||||
|             throw new DecoderException("The received encoded string buffer length is less than zero! Weird string!"); | ||||
|         } else { | ||||
|             String s = buf.toString(buf.readerIndex(), j, StandardCharsets.UTF_8); | ||||
|             buf.readerIndex(buf.readerIndex() + j); | ||||
|             if (s.length() > size) { | ||||
|                 throw new DecoderException( | ||||
|                         "The received string length is longer than maximum allowed (" + j + " > " + size + ")"); | ||||
|             } else { | ||||
|                 return s; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void handleDataReceived(Player player, String name) { | ||||
|         // Continue | ||||
|         PacketContainer packet = new PacketContainer(PacketType.Login.Client.START); | ||||
|         packet.getModifier().write(0, new GameProfile(null, name)); | ||||
|  | ||||
|         try { | ||||
|             ProtocolLibrary.getProtocolManager().recieveClientPacket(player, packet, false); | ||||
|         } | ||||
|         catch (IllegalAccessException | InvocationTargetException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onPacketReceiving(PacketEvent event) { | ||||
|         event.setCancelled(true); | ||||
|  | ||||
|         if (event.getPacketType() != PacketType.Login.Client.START) { | ||||
|             String address = event.getPlayer().getAddress().toString(); | ||||
|  | ||||
|             String name = loginAttempts.getIfPresent(address); | ||||
|  | ||||
|             if (name == null) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             if (event.getPacket().getIntegers().read(0) == packetId2) { | ||||
|                 loginAttempts.invalidate(address); | ||||
|                 handleDataReceived(event.getPlayer(), name); | ||||
|                 return; | ||||
|             } else if (event.getPacket().getIntegers().read(0) == packetId1) { | ||||
|                 ByteBuf buf = (ByteBuf) event.getPacket().getModifier().read(1); | ||||
|  | ||||
|                 if (buf != null) { | ||||
|                     byte[] bytes = new byte[buf.readableBytes()]; | ||||
|                     buf.readBytes(bytes); | ||||
|  | ||||
|                     handleModlist(event.getPlayer(), name, bytes); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         loginAttempts | ||||
|                 .put(event.getPlayer().getAddress().toString(), event.getPacket().getGameProfiles().read(0).getName()); | ||||
|  | ||||
|         PacketContainer packet1 = new PacketContainer(PacketType.Login.Server.CUSTOM_PAYLOAD); | ||||
|         packet1.getIntegers().write(0, packetId1); | ||||
|         packet1.getMinecraftKeys().write(0, new com.comphenix.protocol.wrappers.MinecraftKey("fml", "handshake")); | ||||
|         packet1.getModifier() | ||||
|                 .write(2, new PacketDataSerializer(Unpooled.wrappedBuffer(ModdedManager.getFmlHandshake()))); | ||||
|  | ||||
|         PacketContainer packet2 = new PacketContainer(PacketType.Login.Server.CUSTOM_PAYLOAD); | ||||
|         packet2.getIntegers().write(0, packetId2); | ||||
|         packet2.getMinecraftKeys().write(0, new MinecraftKey("fml", "handshake")); | ||||
|         packet2.getModifier() | ||||
|                 .write(2, new PacketDataSerializer(Unpooled.wrappedBuffer(ModdedManager.getFmlRegistries()))); | ||||
|  | ||||
|         try { | ||||
|             ProtocolLibrary.getProtocolManager().sendServerPacket(event.getPlayer(), packet1); | ||||
|             ProtocolLibrary.getProtocolManager().sendServerPacket(event.getPlayer(), packet2); | ||||
|         } | ||||
|         catch (InvocationTargetException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -10,7 +10,6 @@ import me.libraryaddict.disguise.utilities.params.types.ParamInfoEnum; | ||||
| import me.libraryaddict.disguise.utilities.params.types.base.*; | ||||
| import me.libraryaddict.disguise.utilities.params.types.custom.*; | ||||
| import me.libraryaddict.disguise.utilities.reflection.NmsVersion; | ||||
| import me.libraryaddict.disguise.utilities.sounds.SoundGroup; | ||||
| import org.apache.commons.lang.StringUtils; | ||||
| import org.bukkit.*; | ||||
| import org.bukkit.block.BlockFace; | ||||
|   | ||||
| @@ -6,7 +6,6 @@ import me.libraryaddict.disguise.utilities.sounds.SoundGroup; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * Created by libraryaddict on 23/05/2020. | ||||
|   | ||||
| @@ -7,10 +7,8 @@ import me.libraryaddict.disguise.utilities.reflection.ReflectionManager; | ||||
| import org.apache.commons.lang.math.RandomUtils; | ||||
| import org.bukkit.Sound; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.Map; | ||||
| import java.util.Random; | ||||
|  | ||||
| /** | ||||
|  * Created by libraryaddict on 23/05/2020. | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package me.libraryaddict.disguise.utilities.sounds; | ||||
| import me.libraryaddict.disguise.LibsDisguises; | ||||
| import me.libraryaddict.disguise.utilities.DisguiseUtilities; | ||||
| import me.libraryaddict.disguise.utilities.params.ParamInfoManager; | ||||
| import me.libraryaddict.disguise.utilities.params.ParamInfoTypes; | ||||
| import org.bukkit.Sound; | ||||
| import org.bukkit.configuration.ConfigurationSection; | ||||
| import org.bukkit.configuration.file.YamlConfiguration; | ||||
|   | ||||
| @@ -55,4 +55,5 @@ Custom-Entities: | ||||
| #    Mod: LibAttacks # The mod they need installed | ||||
| # If exists, will prevent anyone without the mod from joining with this error | ||||
| #    Required: 'Install LibAttacks! Download it from our site!' | ||||
| #    Channels: librarian:channel|1 # Sometimes a mod needs a channel enabled.. Seperate each channel with a comma | ||||
| #    Channels: librarian:channel|1 # Sometimes a mod needs a channel enabled.. Seperate each channel with a comma. | ||||
| #    The channels also want a protocol version, which is normally 1 or 1.0 | ||||
		Reference in New Issue
	
	Block a user