Удаление игрока из Tab-листа.

Версия Minecraft
1.7.10
API
Forge
22
1
2
Доброго времени суток, форумчане!
Стоит такая задача: необходимо удалить игрока из Tab-листа для всех, кроме него самого.
Собственно удаление я реализую так:
Java:
List<EntityPlayerMP> allPlayers = (List<EntityPlayerMP>)MinecraftServer.getServer().getConfigurationManager().playerEntityList;
for (EntityPlayerMP otherPlayer : allPlayers) {
otherPlayer.playerNetServerHandler.sendPacket(new S38PacketPlayerListItem(player.getCommandSenderName(), false, -1));
}
И он действительно удаляется, однако потом появляется снова, спустя 10-20 секунд. Я пробовал ставить cancellable миксины в NetHandlerPlayServer#sendPacket и NetHandlerPlayClient#handlePlayerListItem. Однако это не дало никакого результата. Я также пробовал отправлять этот же S38PacketPlayerListItem пакет в событии PlayerTickEvent:
Java:
@SubscribeEvent
    public void onPlayerTick(PlayerTickEvent e) {
        if (e.phase == TickEvent.Phase.START && e.player instanceof EntityPlayerMP) {
            for (EntityPlayerMP otherPlayer : PlayerHelper.getPlayerList()) {
                otherPlayer.playerNetServerHandler.sendPacket(new S38PacketPlayerListItem(e.player.getCommandSenderName(), false, -1));
            }
        }
    }
Это дало половинчатый эффект: игрок удаляется из таба вновь, однако на доли секунды виден появляющийся в табе никнейм. Вместе с тем хотелось бы найти способ, который, по возможности, не задействует Tick-события, чтобы лишний раз не грузить систему.
Могли бы вы, пожалуйста, направить меня, на какой метод/событие/пакет обратить внимание, чтобы достичь цели?
 
Решение
Бредом занимаешься. Всё можно сделать на сервере.
Да, вы правы. Я сейчас попробовал вырезать кусок из перехватчика пакетов, оставив только сервер. Всё ещё работает. Таков итоговый код:

Java:
@Inject(method = "sendPacketToAllPlayers", at = @At("HEAD"), cancellable = true)
    private void onPacketSend(Packet packet, CallbackInfo ci) {
        if (packet instanceof S38PacketPlayerListItem) {
            S38PacketPlayerListItem s38 = (S38PacketPlayerListItem)packet;
            if (VanishManager.isVanished(s38.func_149122_c())) {
                ci.cancel();
            }
        }
    }
На миксинах легко делается:
MixinServerConfigurationManager.java:
package ru.mts2200.example.server.mixin;

import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.Packet;
import net.minecraft.network.play.server.S38PacketPlayerListItem;
import net.minecraft.server.management.ServerConfigurationManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(ServerConfigurationManager.class)
public abstract class MixinServerConfigurationManager {
    @WrapWithCondition(method = {"playerLoggedOut", "playerLoggedIn"}, at = {@At(value = "INVOKE", target = "Lnet/minecraft/server/management/ServerConfigurationManager;sendPacketToAllPlayers(Lnet/minecraft/network/Packet;)V"), @At(value = "INVOKE", target = "Lnet/minecraft/network/NetHandlerPlayServer;sendPacket(Lnet/minecraft/network/Packet;)V")})
    private boolean cancelTabNotifies(ServerConfigurationManager instance, Packet packet) {
        return !(packet instanceof S38PacketPlayerListItem);
    }

    @Inject(method = "playerLoggedIn", at = @At("TAIL"))
    private void sendTabNotify(EntityPlayerMP player, CallbackInfo ci) {
        player.playerNetServerHandler.sendPacket(new S38PacketPlayerListItem(player.getDisplayName(), true, player.ping));
    }

    @WrapWithCondition(method = "sendPlayerInfoToAllPlayers", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/management/ServerConfigurationManager;sendPacketToAllPlayers(Lnet/minecraft/network/Packet;)V"), expect = 0)
    private boolean cancelGlobalTabUpdates(ServerConfigurationManager instance, Packet packet, @Local EntityPlayerMP player) {
        if (packet instanceof S38PacketPlayerListItem) {
            player.playerNetServerHandler.sendPacket(packet);
            return false;
        }

        return true;
    }
}
 
Последнее редактирование:
Этот вопрос я решил, поставив cancellable миксин на ServerConfigurationManager#sendPacketToAllPlayers, а также сделав отлов пакетов, создав класс, наследующийся от SimpleChannelInboundHandler<Packet> и реализующий channelRead0(). Там просто меняю у нужных пакетов поле на false, чтобы не отображалось в списке игроков.
 
Этот вопрос я решил, поставив cancellable миксин на ServerConfigurationManager#sendPacketToAllPlayers, а также сделав отлов пакетов, создав класс, наследующийся от SimpleChannelInboundHandler<Packet> и реализующий channelRead0(). Там просто меняю у нужных пакетов поле на false, чтобы не отображалось в списке игроков.
Бредом занимаешься. Всё можно сделать на сервере.
 
Бредом занимаешься. Всё можно сделать на сервере.
Да, вы правы. Я сейчас попробовал вырезать кусок из перехватчика пакетов, оставив только сервер. Всё ещё работает. Таков итоговый код:

Java:
@Inject(method = "sendPacketToAllPlayers", at = @At("HEAD"), cancellable = true)
    private void onPacketSend(Packet packet, CallbackInfo ci) {
        if (packet instanceof S38PacketPlayerListItem) {
            S38PacketPlayerListItem s38 = (S38PacketPlayerListItem)packet;
            if (VanishManager.isVanished(s38.func_149122_c())) {
                ci.cancel();
            }
        }
    }
 
Назад
Сверху