Implement hostname support for PlayerLoginEvent, as well as connection throttling support.

Tried to support BungeeCord.
This commit is contained in:
IzzelAliz 2020-06-09 14:22:17 +08:00
parent 96d2f9eb7b
commit 34376b5143
9 changed files with 324 additions and 32 deletions

View File

@ -0,0 +1,19 @@
package io.izzel.arclight.common.bridge.network;
import com.mojang.authlib.properties.Property;
import java.net.SocketAddress;
import java.util.UUID;
public interface NetworkManagerBridge {
UUID bridge$getSpoofedUUID();
void bridge$setSpoofedUUID(UUID spoofedUUID);
Property[] bridge$getSpoofedProfile();
void bridge$setSpoofedProfile(Property[] spoofedProfile);
SocketAddress bridge$getRawAddress();
}

View File

@ -0,0 +1,8 @@
package io.izzel.arclight.common.bridge.network.login;
public interface ServerLoginNetHandlerBridge {
String bridge$getHostname();
void bridge$setHostname(String hostname);
}

View File

@ -1,8 +1,11 @@
package io.izzel.arclight.common.bridge.server.management; package io.izzel.arclight.common.bridge.server.management;
import com.mojang.authlib.GameProfile;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.network.login.ServerLoginNetHandler;
import org.bukkit.craftbukkit.v.CraftServer; import org.bukkit.craftbukkit.v.CraftServer;
import java.net.SocketAddress;
import java.util.List; import java.util.List;
public interface PlayerListBridge { public interface PlayerListBridge {
@ -12,4 +15,6 @@ public interface PlayerListBridge {
List<ServerPlayerEntity> bridge$getPlayers(); List<ServerPlayerEntity> bridge$getPlayers();
CraftServer bridge$getCraftServer(); CraftServer bridge$getCraftServer();
ServerPlayerEntity bridge$canPlayerLogin(SocketAddress socketAddress, GameProfile gameProfile, ServerLoginNetHandler handler);
} }

View File

@ -0,0 +1,48 @@
package io.izzel.arclight.common.mixin.core.network;
import com.mojang.authlib.properties.Property;
import io.izzel.arclight.common.bridge.network.NetworkManagerBridge;
import io.netty.channel.Channel;
import net.minecraft.network.NetworkManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.net.SocketAddress;
import java.util.UUID;
@Mixin(NetworkManager.class)
public class NetworkManagerMixin implements NetworkManagerBridge {
@Shadow public Channel channel;
public java.util.UUID spoofedUUID;
public com.mojang.authlib.properties.Property[] spoofedProfile;
@Override
public UUID bridge$getSpoofedUUID() {
return spoofedUUID;
}
@Override
public void bridge$setSpoofedUUID(UUID spoofedUUID) {
this.spoofedUUID = spoofedUUID;
}
@Override
public Property[] bridge$getSpoofedProfile() {
return spoofedProfile;
}
@Override
public void bridge$setSpoofedProfile(Property[] spoofedProfile) {
this.spoofedProfile = spoofedProfile;
}
public SocketAddress getRawAddress() {
return this.channel.remoteAddress();
}
@Override
public SocketAddress bridge$getRawAddress() {
return getRawAddress();
}
}

View File

@ -0,0 +1,124 @@
package io.izzel.arclight.common.mixin.core.network.handshake;
import com.google.gson.Gson;
import com.mojang.authlib.properties.Property;
import com.mojang.util.UUIDTypeAdapter;
import io.izzel.arclight.common.bridge.network.NetworkManagerBridge;
import io.izzel.arclight.common.bridge.network.login.ServerLoginNetHandlerBridge;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.ProtocolType;
import net.minecraft.network.handshake.ServerHandshakeNetHandler;
import net.minecraft.network.handshake.client.CHandshakePacket;
import net.minecraft.network.login.ServerLoginNetHandler;
import net.minecraft.network.login.server.SDisconnectLoginPacket;
import net.minecraft.network.status.ServerStatusNetHandler;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.SharedConstants;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.spigotmc.SpigotConfig;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.text.MessageFormat;
import java.util.HashMap;
@Mixin(ServerHandshakeNetHandler.class)
public class ServerHandshakeNetHandlerMixin {
private static final Gson gson = new Gson();
private static final HashMap<InetAddress, Long> throttleTracker = new HashMap<>();
private static int throttleCounter = 0;
@Shadow @Final private NetworkManager networkManager;
@Shadow @Final private MinecraftServer server;
/**
* @author IzzelAliz
* @reason
*/
@Overwrite
public void processHandshake(CHandshakePacket packetIn) {
if (!ServerLifecycleHooks.handleServerLogin(packetIn, this.networkManager)) return;
switch (packetIn.getRequestedState()) {
case LOGIN: {
this.networkManager.setConnectionState(ProtocolType.LOGIN);
try {
long currentTime = System.currentTimeMillis();
long connectionThrottle = Bukkit.getServer().getConnectionThrottle();
InetAddress address = ((InetSocketAddress) this.networkManager.getRemoteAddress()).getAddress();
synchronized (throttleTracker) {
if (throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - throttleTracker.get(address) < connectionThrottle) {
throttleTracker.put(address, currentTime);
TranslationTextComponent component = new TranslationTextComponent("Connection throttled! Please wait before reconnecting.");
this.networkManager.sendPacket(new SDisconnectLoginPacket(component));
this.networkManager.closeChannel(component);
return;
}
throttleTracker.put(address, currentTime);
++throttleCounter;
if (throttleCounter > 200) {
throttleCounter = 0;
throttleTracker.entrySet().removeIf(entry -> entry.getValue() > connectionThrottle);
}
}
} catch (Throwable t) {
LogManager.getLogger().debug("Failed to check connection throttle", t);
}
if (packetIn.getProtocolVersion() > SharedConstants.getVersion().getProtocolVersion()) {
TranslationTextComponent component = new TranslationTextComponent(MessageFormat.format(SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getVersion().getName()));
this.networkManager.sendPacket(new SDisconnectLoginPacket(component));
this.networkManager.closeChannel(component);
break;
}
if (packetIn.getProtocolVersion() < SharedConstants.getVersion().getProtocolVersion()) {
TranslationTextComponent component = new TranslationTextComponent(MessageFormat.format(SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), SharedConstants.getVersion().getName()));
this.networkManager.sendPacket(new SDisconnectLoginPacket(component));
this.networkManager.closeChannel(component);
break;
}
this.networkManager.setNetHandler(new ServerLoginNetHandler(this.server, this.networkManager));
if (SpigotConfig.bungee) {
String[] split = packetIn.ip.split("\00");
if (split.length == 3 || split.length == 4) {
packetIn.ip = split[0];
this.networkManager.socketAddress = new InetSocketAddress(split[1], ((InetSocketAddress) this.networkManager.getRemoteAddress()).getPort());
((NetworkManagerBridge) this.networkManager).bridge$setSpoofedUUID(UUIDTypeAdapter.fromString(split[2]));
} else {
TranslationTextComponent component = new TranslationTextComponent("If you wish to use IP forwarding, please enable it in your BungeeCord config as well!");
this.networkManager.sendPacket(new SDisconnectLoginPacket(component));
this.networkManager.closeChannel(component);
return;
}
if (split.length == 4) {
((NetworkManagerBridge) this.networkManager).bridge$setSpoofedProfile(gson.fromJson(split[3], Property[].class));
}
}
((ServerLoginNetHandlerBridge) this.networkManager.getNetHandler()).bridge$setHostname(packetIn.ip + ":" + packetIn.port);
break;
}
case STATUS: {
this.networkManager.setConnectionState(ProtocolType.STATUS);
this.networkManager.setNetHandler(new ServerStatusNetHandler(this.server, this.networkManager));
break;
}
default: {
throw new UnsupportedOperationException("Invalid intention " + packetIn.getRequestedState());
}
}
}
}

View File

@ -0,0 +1,16 @@
package io.izzel.arclight.common.mixin.core.network.handshake.client;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.handshake.client.CHandshakePacket;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(CHandshakePacket.class)
public class CHandshakePacketMixin {
@Redirect(method = "readPacketData", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/PacketBuffer;readString(I)Ljava/lang/String;"))
private String arclight$bungeeHostname(PacketBuffer packetBuffer, int maxLength) {
return packetBuffer.readString(Short.MAX_VALUE);
}
}

View File

@ -1,14 +1,21 @@
package io.izzel.arclight.common.mixin.core.network.login; package io.izzel.arclight.common.mixin.core.network.login;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import io.izzel.arclight.common.bridge.network.NetworkManagerBridge;
import io.izzel.arclight.common.bridge.network.login.ServerLoginNetHandlerBridge;
import io.izzel.arclight.common.bridge.server.MinecraftServerBridge; import io.izzel.arclight.common.bridge.server.MinecraftServerBridge;
import io.izzel.arclight.common.bridge.server.management.PlayerListBridge;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.network.NetworkManager; import net.minecraft.network.NetworkManager;
import net.minecraft.network.login.ServerLoginNetHandler; import net.minecraft.network.login.ServerLoginNetHandler;
import net.minecraft.network.login.client.CEncryptionResponsePacket; import net.minecraft.network.login.client.CEncryptionResponsePacket;
import net.minecraft.network.login.client.CLoginStartPacket; import net.minecraft.network.login.client.CLoginStartPacket;
import net.minecraft.network.login.server.SDisconnectLoginPacket; import net.minecraft.network.login.server.SDisconnectLoginPacket;
import net.minecraft.network.login.server.SEnableCompressionPacket;
import net.minecraft.network.login.server.SEncryptionRequestPacket; import net.minecraft.network.login.server.SEncryptionRequestPacket;
import net.minecraft.network.login.server.SLoginSuccessPacket;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.util.CryptManager; import net.minecraft.util.CryptManager;
import net.minecraft.util.DefaultUncaughtExceptionHandler; import net.minecraft.util.DefaultUncaughtExceptionHandler;
@ -40,7 +47,7 @@ import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@Mixin(ServerLoginNetHandler.class) @Mixin(ServerLoginNetHandler.class)
public abstract class ServerLoginNetHandler1Mixin { public abstract class ServerLoginNetHandlerMixin implements ServerLoginNetHandlerBridge {
// @formatter:off // @formatter:off
@Shadow private ServerLoginNetHandler.State currentLoginState; @Shadow private ServerLoginNetHandler.State currentLoginState;
@ -56,6 +63,19 @@ public abstract class ServerLoginNetHandler1Mixin {
@Shadow public abstract String getConnectionInfo(); @Shadow public abstract String getConnectionInfo();
// @formatter:on // @formatter:on
@Shadow private ServerPlayerEntity player;
public String hostname;
@Override
public String bridge$getHostname() {
return hostname;
}
@Override
public void bridge$setHostname(String hostname) {
this.hostname = hostname;
}
public void disconnect(final String s) { public void disconnect(final String s) {
try { try {
final ITextComponent ichatbasecomponent = new StringTextComponent(s); final ITextComponent ichatbasecomponent = new StringTextComponent(s);
@ -67,6 +87,40 @@ public abstract class ServerLoginNetHandler1Mixin {
} }
} }
/**
* @author IzzelAliz
* @reason
*/
@Overwrite
public void tryAcceptPlayer() {
/*
if (!this.loginGameProfile.isComplete()) {
this.loginGameProfile = this.getOfflineProfile(this.loginGameProfile);
}
*/
ServerPlayerEntity entity = ((PlayerListBridge) this.server.getPlayerList()).bridge$canPlayerLogin(this.networkManager.getRemoteAddress(), this.loginGameProfile, (ServerLoginNetHandler) (Object) this);
if (entity == null) {
// this.disconnect(itextcomponent);
} else {
this.currentLoginState = ServerLoginNetHandler.State.ACCEPTED;
if (this.server.getNetworkCompressionThreshold() >= 0 && !this.networkManager.isLocalChannel()) {
this.networkManager.sendPacket(new SEnableCompressionPacket(this.server.getNetworkCompressionThreshold()), (p_210149_1_) -> {
this.networkManager.setCompressionThreshold(this.server.getNetworkCompressionThreshold());
});
}
this.networkManager.sendPacket(new SLoginSuccessPacket(this.loginGameProfile));
ServerPlayerEntity serverplayerentity = this.server.getPlayerList().getPlayerByUUID(this.loginGameProfile.getId());
if (serverplayerentity != null) {
this.currentLoginState = ServerLoginNetHandler.State.DELAY_ACCEPT;
this.player = entity;
} else {
this.server.getPlayerList().initializeConnectionToPlayer(this.networkManager, entity);
}
}
}
/** /**
* @author IzzelAliz * @author IzzelAliz
* @reason * @reason
@ -102,8 +156,20 @@ public abstract class ServerLoginNetHandler1Mixin {
} }
public void initUUID() { public void initUUID() {
UUID uuid = PlayerEntity.getOfflineUUID(this.loginGameProfile.getName()); UUID uuid;
if (((NetworkManagerBridge) this.networkManager).bridge$getSpoofedUUID() != null) {
uuid = ((NetworkManagerBridge) this.networkManager).bridge$getSpoofedUUID();
} else {
uuid = PlayerEntity.getOfflineUUID(this.loginGameProfile.getName());
}
this.loginGameProfile = new GameProfile(uuid, this.loginGameProfile.getName()); this.loginGameProfile = new GameProfile(uuid, this.loginGameProfile.getName());
if (((NetworkManagerBridge) this.networkManager).bridge$getSpoofedProfile() != null) {
Property[] spoofedProfile;
for (int length = (spoofedProfile = ((NetworkManagerBridge) this.networkManager).bridge$getSpoofedProfile()).length, i = 0; i < length; ++i) {
final Property property = spoofedProfile[i];
this.loginGameProfile.getProperties().put(property.getName(), property);
}
}
} }
/** /**
@ -131,7 +197,7 @@ public abstract class ServerLoginNetHandler1Mixin {
try { try {
String s = (new BigInteger(CryptManager.getServerIdHash("", server.getKeyPair().getPublic(), secretKey))).toString(16); String s = (new BigInteger(CryptManager.getServerIdHash("", server.getKeyPair().getPublic(), secretKey))).toString(16);
loginGameProfile = server.getMinecraftSessionService().hasJoinedServer(new GameProfile((UUID) null, gameprofile.getName()), s, this.getAddress()); loginGameProfile = server.getMinecraftSessionService().hasJoinedServer(new GameProfile(null, gameprofile.getName()), s, this.getAddress());
if (loginGameProfile != null) { if (loginGameProfile != null) {
if (!networkManager.isChannelOpen()) { if (!networkManager.isChannelOpen()) {
return; return;
@ -143,7 +209,7 @@ public abstract class ServerLoginNetHandler1Mixin {
currentLoginState = ServerLoginNetHandler.State.NEGOTIATING; currentLoginState = ServerLoginNetHandler.State.NEGOTIATING;
} else { } else {
disconnect(new TranslationTextComponent("multiplayer.disconnect.unverified_username")); disconnect(new TranslationTextComponent("multiplayer.disconnect.unverified_username"));
LOGGER.error("Username '{}' tried to join with an invalid session", (Object) gameprofile.getName()); LOGGER.error("Username '{}' tried to join with an invalid session", gameprofile.getName());
} }
} catch (Exception var3) { } catch (Exception var3) {
if (server.isSinglePlayer()) { if (server.isSinglePlayer()) {

View File

@ -4,14 +4,19 @@ import com.google.common.collect.Lists;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import io.izzel.arclight.common.bridge.entity.player.PlayerEntityBridge; import io.izzel.arclight.common.bridge.entity.player.PlayerEntityBridge;
import io.izzel.arclight.common.bridge.entity.player.ServerPlayerEntityBridge; import io.izzel.arclight.common.bridge.entity.player.ServerPlayerEntityBridge;
import io.izzel.arclight.common.bridge.network.NetworkManagerBridge;
import io.izzel.arclight.common.bridge.network.login.ServerLoginNetHandlerBridge;
import io.izzel.arclight.common.bridge.server.MinecraftServerBridge; import io.izzel.arclight.common.bridge.server.MinecraftServerBridge;
import io.izzel.arclight.common.bridge.server.management.PlayerListBridge; import io.izzel.arclight.common.bridge.server.management.PlayerListBridge;
import io.izzel.arclight.common.bridge.world.WorldBridge; import io.izzel.arclight.common.bridge.world.WorldBridge;
import io.izzel.arclight.common.mod.ArclightMod;
import io.izzel.arclight.common.mod.server.BukkitRegistry; import io.izzel.arclight.common.mod.server.BukkitRegistry;
import io.izzel.arclight.common.mod.util.ArclightCaptures;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.network.IPacket; import net.minecraft.network.IPacket;
import net.minecraft.network.NetworkManager; import net.minecraft.network.NetworkManager;
import net.minecraft.network.login.ServerLoginNetHandler;
import net.minecraft.network.play.server.SChangeGameStatePacket; import net.minecraft.network.play.server.SChangeGameStatePacket;
import net.minecraft.network.play.server.SChatPacket; import net.minecraft.network.play.server.SChatPacket;
import net.minecraft.network.play.server.SEntityStatusPacket; import net.minecraft.network.play.server.SEntityStatusPacket;
@ -55,6 +60,7 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerRespawnEvent;
import org.spigotmc.SpigotConfig;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Overwrite;
@ -64,11 +70,9 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import io.izzel.arclight.common.mod.ArclightMod;
import io.izzel.arclight.common.mod.util.ArclightCaptures;
import javax.annotation.Nullable;
import java.io.File; import java.io.File;
import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@ -150,16 +154,11 @@ public abstract class PlayerListMixin implements PlayerListBridge {
} }
} }
/** @Override
* @author IzzelAliz public ServerPlayerEntity bridge$canPlayerLogin(SocketAddress socketAddress, GameProfile gameProfile, ServerLoginNetHandler handler) {
* @reason UUID uuid = PlayerEntity.getUUID(gameProfile);
*/ List<ServerPlayerEntity> list = Lists.newArrayList();
@Overwrite for (ServerPlayerEntity entityplayer : this.players) {
@Nullable
public ITextComponent canPlayerLogin(SocketAddress socketAddress, GameProfile gameProfile) {
final UUID uuid = PlayerEntity.getUUID(gameProfile);
final List<ServerPlayerEntity> list = Lists.newArrayList();
for (final ServerPlayerEntity entityplayer : this.players) {
if (entityplayer.getUniqueID().equals(uuid)) { if (entityplayer.getUniqueID().equals(uuid)) {
list.add(entityplayer); list.add(entityplayer);
} }
@ -168,36 +167,40 @@ public abstract class PlayerListMixin implements PlayerListBridge {
this.writePlayerData(entityplayer); this.writePlayerData(entityplayer);
entityplayer.connection.disconnect(new TranslationTextComponent("multiplayer.disconnect.duplicate_login")); entityplayer.connection.disconnect(new TranslationTextComponent("multiplayer.disconnect.duplicate_login"));
} }
final ServerPlayerEntity entity = new ServerPlayerEntity(this.server, this.server.func_71218_a(DimensionType.OVERWORLD), gameProfile, new PlayerInteractionManager(this.server.func_71218_a(DimensionType.OVERWORLD))); ServerPlayerEntity entity = new ServerPlayerEntity(this.server, this.server.func_71218_a(DimensionType.OVERWORLD), gameProfile, new PlayerInteractionManager(this.server.func_71218_a(DimensionType.OVERWORLD)));
final Player player = ((ServerPlayerEntityBridge) entity).bridge$getBukkitEntity(); Player player = ((ServerPlayerEntityBridge) entity).bridge$getBukkitEntity();
// todo hostname
final PlayerLoginEvent event = new PlayerLoginEvent(player, "", ((InetSocketAddress) socketAddress).getAddress()); String hostname = handler == null ? "" : ((ServerLoginNetHandlerBridge) handler).bridge$getHostname();
InetAddress realAddress = handler == null ? ((InetSocketAddress) socketAddress).getAddress() : ((InetSocketAddress) ((NetworkManagerBridge) handler.networkManager).bridge$getRawAddress()).getAddress();
PlayerLoginEvent event = new PlayerLoginEvent(player, hostname, ((InetSocketAddress) socketAddress).getAddress(), realAddress);
if (this.getBannedPlayers().isBanned(gameProfile) && !this.getBannedPlayers().getEntry(gameProfile).hasBanExpired()) { if (this.getBannedPlayers().isBanned(gameProfile) && !this.getBannedPlayers().getEntry(gameProfile).hasBanExpired()) {
final ProfileBanEntry gameprofilebanentry = this.bannedPlayers.getEntry(gameProfile); ProfileBanEntry gameprofilebanentry = this.bannedPlayers.getEntry(gameProfile);
final TranslationTextComponent chatmessage = new TranslationTextComponent("multiplayer.disconnect.banned.reason", gameprofilebanentry.getBanReason()); TranslationTextComponent chatmessage = new TranslationTextComponent("multiplayer.disconnect.banned.reason", gameprofilebanentry.getBanReason());
if (gameprofilebanentry.getBanEndDate() != null) { if (gameprofilebanentry.getBanEndDate() != null) {
chatmessage.appendSibling(new TranslationTextComponent("multiplayer.disconnect.banned.expiration", DATE_FORMAT.format(gameprofilebanentry.getBanEndDate()))); chatmessage.appendSibling(new TranslationTextComponent("multiplayer.disconnect.banned.expiration", DATE_FORMAT.format(gameprofilebanentry.getBanEndDate())));
} }
event.disallow(PlayerLoginEvent.Result.KICK_BANNED, CraftChatMessage.fromComponent(chatmessage)); event.disallow(PlayerLoginEvent.Result.KICK_BANNED, CraftChatMessage.fromComponent(chatmessage));
} else if (!this.canJoin(gameProfile)) { } else if (!this.canJoin(gameProfile)) {
final TranslationTextComponent chatmessage = new TranslationTextComponent("multiplayer.disconnect.not_whitelisted"); event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, SpigotConfig.whitelistMessage);
event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, CraftChatMessage.fromComponent(chatmessage));
} else if (this.getBannedIPs().isBanned(socketAddress) && !this.getBannedIPs().getBanEntry(socketAddress).hasBanExpired()) { } else if (this.getBannedIPs().isBanned(socketAddress) && !this.getBannedIPs().getBanEntry(socketAddress).hasBanExpired()) {
final IPBanEntry ipbanentry = this.bannedIPs.getBanEntry(socketAddress); IPBanEntry ipbanentry = this.bannedIPs.getBanEntry(socketAddress);
final TranslationTextComponent chatmessage = new TranslationTextComponent("multiplayer.disconnect.banned_ip.reason", ipbanentry.getBanReason()); TranslationTextComponent chatmessage = new TranslationTextComponent("multiplayer.disconnect.banned_ip.reason", ipbanentry.getBanReason());
if (ipbanentry.getBanEndDate() != null) { if (ipbanentry.getBanEndDate() != null) {
chatmessage.appendSibling(new TranslationTextComponent("multiplayer.disconnect.banned_ip.expiration", DATE_FORMAT.format(ipbanentry.getBanEndDate()))); chatmessage.appendSibling(new TranslationTextComponent("multiplayer.disconnect.banned_ip.expiration", DATE_FORMAT.format(ipbanentry.getBanEndDate())));
} }
event.disallow(PlayerLoginEvent.Result.KICK_BANNED, CraftChatMessage.fromComponent(chatmessage)); event.disallow(PlayerLoginEvent.Result.KICK_BANNED, CraftChatMessage.fromComponent(chatmessage));
} else if (this.players.size() >= this.maxPlayers && !this.bypassesPlayerLimit(gameProfile)) { } else if (this.players.size() >= this.maxPlayers && !this.bypassesPlayerLimit(gameProfile)) {
event.disallow(PlayerLoginEvent.Result.KICK_FULL, "The server is full"); event.disallow(PlayerLoginEvent.Result.KICK_FULL, SpigotConfig.serverFullMessage);
} }
this.cserver.getPluginManager().callEvent(event); this.cserver.getPluginManager().callEvent(event);
if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) { if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
return CraftChatMessage.fromStringOrNull(event.getKickMessage()); if (handler != null) {
} else { handler.disconnect(CraftChatMessage.fromStringOrNull(event.getKickMessage()));
}
return null; return null;
} }
return entity;
} }
public ServerPlayerEntity moveToWorld(ServerPlayerEntity playerIn, DimensionType dimension, boolean conqueredEnd, Location location, boolean avoidSuffocation) { public ServerPlayerEntity moveToWorld(ServerPlayerEntity playerIn, DimensionType dimension, boolean conqueredEnd, Location location, boolean avoidSuffocation) {
@ -385,7 +388,7 @@ public abstract class PlayerListMixin implements PlayerListBridge {
@Inject(method = "playerLoggedOut", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/management/PlayerList;writePlayerData(Lnet/minecraft/entity/player/ServerPlayerEntity;)V")) @Inject(method = "playerLoggedOut", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/management/PlayerList;writePlayerData(Lnet/minecraft/entity/player/ServerPlayerEntity;)V"))
public void arclight$playerQuitPre(ServerPlayerEntity playerIn, CallbackInfo ci) { public void arclight$playerQuitPre(ServerPlayerEntity playerIn, CallbackInfo ci) {
CraftEventFactory.handleInventoryCloseEvent(playerIn); CraftEventFactory.handleInventoryCloseEvent(playerIn);
PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(cserver.getPlayer(playerIn), "\u00A7e" + playerIn.getName() + " left the game"); PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(cserver.getPlayer(playerIn), "\u00A7e" + playerIn.getName().getFormattedText() + " left the game");
cserver.getPluginManager().callEvent(playerQuitEvent); cserver.getPluginManager().callEvent(playerQuitEvent);
((ServerPlayerEntityBridge) playerIn).bridge$getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); ((ServerPlayerEntityBridge) playerIn).bridge$getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage());
playerIn.playerTick(); playerIn.playerTick();

View File

@ -308,8 +308,11 @@
"item.crafting.StonecuttingRecipeMixin", "item.crafting.StonecuttingRecipeMixin",
"item.crafting.SuspiciousStewRecipeMixin", "item.crafting.SuspiciousStewRecipeMixin",
"item.crafting.TippedArrowRecipeMixin", "item.crafting.TippedArrowRecipeMixin",
"network.NetworkManagerMixin",
"network.datasync.EntityDataManagerMixin", "network.datasync.EntityDataManagerMixin",
"network.login.ServerLoginNetHandler1Mixin", "network.handshake.ServerHandshakeNetHandlerMixin",
"network.handshake.client.CHandshakePacketMixin",
"network.login.ServerLoginNetHandlerMixin",
"network.play.ServerPlayNetHandlerMixin", "network.play.ServerPlayNetHandlerMixin",
"network.play.client.CCloseWindowPacketMixin", "network.play.client.CCloseWindowPacketMixin",
"network.play.server.SChatPacketMixin", "network.play.server.SChatPacketMixin",