feat: reflection here so save the day
This commit is contained in:
parent
4c2135ac32
commit
c7154510de
4 changed files with 28 additions and 184 deletions
|
@ -36,10 +36,6 @@
|
|||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>dmulloy2-repo</id>
|
||||
<url>https://repo.dmulloy2.net/repository/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>codemc-snapshots</id>
|
||||
<url>https://repo.codemc.io/repository/maven-snapshots/</url>
|
||||
|
@ -115,12 +111,6 @@
|
|||
<artifactId>yamlconfig</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
<!-- ProtocolLib -->
|
||||
<dependency>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -6,17 +6,12 @@ import java.lang.reflect.InvocationTargetException;
|
|||
|
||||
public class InternalsProvider {
|
||||
private static Internals internals;
|
||||
private static boolean protocolLib = true;
|
||||
|
||||
static {
|
||||
try {
|
||||
final String packageName = Internals.class.getPackage().getName();
|
||||
final String bukkitVersion = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
String fullClassName = packageName + "." + bukkitVersion;
|
||||
if (protocolLib) {
|
||||
System.out.println("USING PROTOCOLLIB HACK");
|
||||
fullClassName += "_P";
|
||||
}
|
||||
internals = (Internals) Class.forName(fullClassName).getConstructors()[0].newInstance();
|
||||
} catch (InvocationTargetException | ClassNotFoundException | InstantiationException | IllegalAccessException |
|
||||
ClassCastException exception) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import net.artelnatif.nicko.disguise.NickoProfile;
|
|||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.mojang.MojangAPI;
|
||||
import net.artelnatif.nicko.mojang.MojangSkin;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.game.*;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
|
@ -24,6 +25,9 @@ import org.bukkit.entity.Player;
|
|||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
@ -95,7 +99,7 @@ public class v1_19_R2 implements Internals {
|
|||
|
||||
final ClientboundPlayerInfoRemovePacket remove = new ClientboundPlayerInfoRemovePacket(List.of(player.getUniqueId()));
|
||||
// TODO: 1/20/23 Sets Gamemode to Survival but keeps the flying? Visual effect only?
|
||||
final ClientboundPlayerInfoUpdatePacket init = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(serverPlayer));
|
||||
//final ClientboundPlayerInfoUpdatePacket init = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(serverPlayer));
|
||||
|
||||
if (skinChange || changeOnlyName) {
|
||||
try {
|
||||
|
@ -121,13 +125,17 @@ public class v1_19_R2 implements Internals {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Tried this solution, doesn't work either:
|
||||
final ClientboundPlayerInfoUpdatePacket init = new ClientboundPlayerInfoUpdatePacket(
|
||||
EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER,
|
||||
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY,
|
||||
ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED),
|
||||
Collections.singletonList(serverPlayer));
|
||||
|
||||
final FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER);
|
||||
byteBuf.writeEnumSet(actions, ClientboundPlayerInfoUpdatePacket.Action.class);
|
||||
byteBuf.writeCollection(List.of(new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
Field field;
|
||||
try {
|
||||
field = init.getClass().getDeclaredField("b");
|
||||
field.setAccessible(true);
|
||||
field.set(init, List.of(new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
player.getUniqueId(),
|
||||
newGameProfile,
|
||||
true,
|
||||
|
@ -135,15 +143,13 @@ public class v1_19_R2 implements Internals {
|
|||
serverPlayer.gameMode.getGameModeForPlayer(),
|
||||
Component.literal(profileName),
|
||||
serverPlayer.getChatSession().asData()
|
||||
)), (bb, entry) -> {
|
||||
bb.writeUUID(entry.profileId());
|
||||
Iterator<ClientboundPlayerInfoUpdatePacket.Action> iterator = actions.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
bb.writeUtf(entry.profile().getName(), 16);
|
||||
bb.writeGameProfileProperties(newGameProfile.getProperties());
|
||||
)));
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});*/
|
||||
|
||||
System.out.println("======= AFTER ");
|
||||
System.out.println("init.entries().toString() = " + init.entries().toString());
|
||||
|
||||
serverPlayer.connection.send(remove);
|
||||
serverPlayer.connection.send(init);
|
||||
|
|
|
@ -1,147 +0,0 @@
|
|||
package net.artelnatif.nicko.impl;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.*;
|
||||
import com.google.common.collect.Multimap;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.mojang.MojangAPI;
|
||||
import net.artelnatif.nicko.mojang.MojangSkin;
|
||||
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundRespawnPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class v1_19_R2_P implements InternalsProtocolLib {
|
||||
@Override
|
||||
public void updateSelf(Player player) {
|
||||
final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
|
||||
final ServerLevel level = serverPlayer.getLevel();
|
||||
final ResourceKey<Level> levelResourceKey = serverPlayer.getLevel().dimension();
|
||||
final CraftWorld world = level.getWorld();
|
||||
// last boolean is: "has death location" attribute, if true, the optional contains the death dimension and position.
|
||||
// with the boolean being false, we don't need to provide a value, and thus we return an empty optional.
|
||||
final ClientboundRespawnPacket respawn = new ClientboundRespawnPacket(serverPlayer.level.dimensionTypeId(),
|
||||
levelResourceKey, world.getSeed(),
|
||||
serverPlayer.gameMode.getPreviousGameModeForPlayer(), serverPlayer.gameMode.getGameModeForPlayer(),
|
||||
level.isDebug(),
|
||||
level.isFlat(),
|
||||
(byte) 0x00,
|
||||
Optional.empty());
|
||||
|
||||
final boolean wasFlying = player.isFlying();
|
||||
serverPlayer.connection.send(respawn);
|
||||
player.setFlying(wasFlying);
|
||||
player.teleport(player.getLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN);
|
||||
player.updateInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateOthers(Player player) {
|
||||
final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
|
||||
final ClientboundRemoveEntitiesPacket remove = new ClientboundRemoveEntitiesPacket(serverPlayer.getBukkitEntity().getEntityId());
|
||||
final ClientboundAddEntityPacket add = new ClientboundAddEntityPacket(serverPlayer);
|
||||
|
||||
/*
|
||||
BIT MASKS:
|
||||
0x01 Cape enabled
|
||||
0x02 Jacket enabled
|
||||
0x04 Left sleeve enabled
|
||||
0x08 Right sleeve enabled
|
||||
0x10 Left pants leg enabled
|
||||
0x20 Right pants leg enabled
|
||||
0x40 Hat enabled
|
||||
*/
|
||||
final SynchedEntityData entityData = serverPlayer.getEntityData();
|
||||
final EntityDataAccessor<Byte> skinPartAccessor = new EntityDataAccessor<>(17, EntityDataSerializers.BYTE);
|
||||
entityData.set(skinPartAccessor, (byte) 0x7f); // 127, all masks combined
|
||||
final ClientboundSetEntityDataPacket entityMetadata = new ClientboundSetEntityDataPacket(serverPlayer.getBukkitEntity().getEntityId(), entityData.getNonDefaultValues());
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach(online -> {
|
||||
ServerPlayer onlineServerPlayer = ((CraftPlayer) online).getHandle();
|
||||
if (onlineServerPlayer.getBukkitEntity().getUniqueId() != player.getUniqueId()) {
|
||||
onlineServerPlayer.connection.send(remove);
|
||||
onlineServerPlayer.connection.send(add);
|
||||
}
|
||||
onlineServerPlayer.connection.send(entityMetadata);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset) {
|
||||
final boolean changeOnlyName = profile.getSkin() != null && !profile.getSkin().equalsIgnoreCase(player.getName());
|
||||
final String profileName = profile.getName() == null ? player.getName() : profile.getName();
|
||||
Optional<MojangSkin> skin;
|
||||
|
||||
final WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(player).withName(profileName);
|
||||
if (skinChange || changeOnlyName) {
|
||||
try {
|
||||
final MojangAPI mojang = NickoBukkit.getInstance().getMojangAPI();
|
||||
final Optional<String> uuid = mojang.getUUID(profile.getSkin());
|
||||
if (uuid.isPresent()) {
|
||||
skin = (reset ? mojang.getSkinWithoutCaching(uuid.get()) : mojang.getSkin(uuid.get()));
|
||||
if (skin.isPresent()) {
|
||||
final Multimap<String, WrappedSignedProperty> properties = gameProfile.getProperties();
|
||||
properties.removeAll("textures");
|
||||
properties.put("textures", new WrappedSignedProperty("textures", skin.get().value(), skin.get().signature()));
|
||||
updateSelf(player);
|
||||
} else {
|
||||
return new ActionResult(I18NDict.Error.SKIN_FAIL_MOJANG);
|
||||
}
|
||||
} else {
|
||||
return new ActionResult(I18NDict.Error.NAME_FAIL_MOJANG);
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
return new ActionResult(I18NDict.Error.SKIN_FAIL_CACHE);
|
||||
} catch (IOException e) {
|
||||
return new ActionResult(I18NDict.Error.NAME_FAIL_MOJANG);
|
||||
}
|
||||
}
|
||||
|
||||
// Letting ProtocolLib handle the reflection here.
|
||||
final PacketContainer remove = getProtocolLib().createPacket(PacketType.Play.Server.PLAYER_INFO_REMOVE);
|
||||
remove.getUUIDLists().write(0, Collections.singletonList(player.getUniqueId()));
|
||||
|
||||
final EnumSet<EnumWrappers.PlayerInfoAction> actions = EnumSet.of(
|
||||
EnumWrappers.PlayerInfoAction.ADD_PLAYER,
|
||||
EnumWrappers.PlayerInfoAction.UPDATE_LATENCY,
|
||||
EnumWrappers.PlayerInfoAction.UPDATE_LISTED);
|
||||
final PacketContainer add = getProtocolLib().createPacket(PacketType.Play.Server.PLAYER_INFO);
|
||||
|
||||
add.getPlayerInfoActions().write(0, actions);
|
||||
add.getPlayerInfoDataLists().write(1, Collections.singletonList(new PlayerInfoData(
|
||||
gameProfile,
|
||||
player.getPing(),
|
||||
EnumWrappers.NativeGameMode.fromBukkit(player.getGameMode()),
|
||||
WrappedChatComponent.fromText(profileName)
|
||||
)));
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach(online -> {
|
||||
getProtocolLib().sendServerPacket(online, remove);
|
||||
getProtocolLib().sendServerPacket(online, add);
|
||||
});
|
||||
updateOthers(player);
|
||||
return new ActionResult();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue