Fix modded entities

This commit is contained in:
libraryaddict 2020-06-11 17:12:55 +12:00
parent 8bb9051e59
commit c4717d7453
No known key found for this signature in database
GPG Key ID: 052E4FBCD257AEA4
10 changed files with 278 additions and 86 deletions

@ -1,6 +1,6 @@
package me.libraryaddict.disguise.commands.libsdisguises; 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 me.libraryaddict.disguise.utilities.translations.LibsMsg;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -26,7 +26,7 @@ public class LDMods implements LDCommand {
@Override @Override
public void onCommand(CommandSender sender, String[] args) { 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()); sender.sendMessage(LibsMsg.NO_MODS_LISTENING.get());
return; 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 @EventHandler
public void onJoin(PlayerJoinEvent event) { public void onJoin(PlayerJoinEvent event) {
Player p = event.getPlayer(); 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; package me.libraryaddict.disguise.utilities.modded;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.utility.StreamSerializer; import com.comphenix.protocol.utility.StreamSerializer;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.Getter; import lombok.Getter;
import me.libraryaddict.disguise.LibsDisguises; import me.libraryaddict.disguise.LibsDisguises;
import me.libraryaddict.disguise.disguisetypes.DisguiseType; 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.parser.DisguisePerm;
import me.libraryaddict.disguise.utilities.reflection.ReflectionManager; import me.libraryaddict.disguise.utilities.reflection.ReflectionManager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey; 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.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit;
/** /**
* Created by libraryaddict on 14/04/2020. * Created by libraryaddict on 14/04/2020.
*/ */
public class ModdedManager implements PluginMessageListener { public class ModdedManager {
@Getter @Getter
private static final HashMap<NamespacedKey, ModdedEntity> entities = new HashMap<>(); private static final HashMap<NamespacedKey, ModdedEntity> entities = new HashMap<>();
@Getter @Getter
private static byte[] fmlHandshake; 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) { public ModdedManager(ArrayList<String> channels) {
if (getEntities().isEmpty()) { if (getEntities().isEmpty()) {
return; return;
} }
if (getEntities().values().stream().noneMatch(e -> e.getMod() != null)) { if (fmlRegistries == null) {
return; 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(); ByteArrayOutputStream stream = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(stream); DataOutputStream output = new DataOutputStream(stream);
@ -57,14 +65,58 @@ public class ModdedManager implements PluginMessageListener {
s.serializeString(output, channel.substring(channel.indexOf("|") + 1)); s.serializeString(output, channel.substring(channel.indexOf("|") + 1));
} }
// We have no resources to declare // We want to declare some entities
s.serializeVarInt(output, 0); s.serializeVarInt(output, 0);
// Only this one thx
// s.serializeString(output, "minecraft:entity_type");
} }
catch (IOException e) { catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
fmlHandshake = stream.toByteArray(); 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) { 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"); throw new IllegalArgumentException("Modded entity " + entity.getName() + " has already been registered");
} }
Object entityType;
if (register) { if (register) {
Object entityType = ReflectionManager.registerEntityType(name); entityType = ReflectionManager.registerEntityType(name);
int entityId = ReflectionManager.getEntityTypeId(entityType); int entityId = ReflectionManager.getEntityTypeId(entityType);
entity.setTypeId(entityId); entity.setTypeId(entityId);
entity.setEntityType(entityType);
} else { } else {
Object entityType = ReflectionManager.getEntityType(name); entityType = ReflectionManager.getEntityType(name);
int entityId = ReflectionManager.getEntityTypeId(entityType); int entityId = ReflectionManager.getEntityTypeId(entityType);
entity.setTypeId(entityId); entity.setTypeId(entityId);
entity.setEntityType(entityType);
} }
entity.setEntityType(entityType);
entities.put(name, entity); entities.put(name, entity);
} }
@ -120,54 +174,4 @@ public class ModdedManager implements PluginMessageListener {
return perms; 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.base.*;
import me.libraryaddict.disguise.utilities.params.types.custom.*; import me.libraryaddict.disguise.utilities.params.types.custom.*;
import me.libraryaddict.disguise.utilities.reflection.NmsVersion; import me.libraryaddict.disguise.utilities.reflection.NmsVersion;
import me.libraryaddict.disguise.utilities.sounds.SoundGroup;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;

@ -6,7 +6,6 @@ import me.libraryaddict.disguise.utilities.sounds.SoundGroup;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map;
/** /**
* Created by libraryaddict on 23/05/2020. * 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.apache.commons.lang.math.RandomUtils;
import org.bukkit.Sound; import org.bukkit.Sound;
import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Random;
/** /**
* Created by libraryaddict on 23/05/2020. * 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.LibsDisguises;
import me.libraryaddict.disguise.utilities.DisguiseUtilities; import me.libraryaddict.disguise.utilities.DisguiseUtilities;
import me.libraryaddict.disguise.utilities.params.ParamInfoManager; import me.libraryaddict.disguise.utilities.params.ParamInfoManager;
import me.libraryaddict.disguise.utilities.params.ParamInfoTypes;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;

@ -55,4 +55,5 @@ Custom-Entities:
# Mod: LibAttacks # The mod they need installed # Mod: LibAttacks # The mod they need installed
# If exists, will prevent anyone without the mod from joining with this error # If exists, will prevent anyone without the mod from joining with this error
# Required: 'Install LibAttacks! Download it from our site!' # 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