goauth

Fabric plugin for enhanced whitelists
git clone git://git.bain.cz/goauth.git
Log | Files | Refs | README | LICENSE

OnPlayerConnectListener.java (6922B)


      1 package cz.bain.plugins.goauth.events.listeners;
      2 
      3 import cz.bain.plugins.goauth.DummyServerPlayNetworkHandler;
      4 import cz.bain.plugins.goauth.Goauth;
      5 import cz.bain.plugins.goauth.events.callbacks.OnPlayerConnectCallback;
      6 import cz.bain.plugins.goauth.mixin.PlayerManagerAccessor;
      7 import io.netty.buffer.Unpooled;
      8 import net.minecraft.nbt.NbtCompound;
      9 import net.minecraft.nbt.NbtLongArray;
     10 import net.minecraft.network.ClientConnection;
     11 import net.minecraft.network.PacketByteBuf;
     12 import net.minecraft.network.packet.s2c.play.*;
     13 import net.minecraft.recipe.book.RecipeBookOptions;
     14 import net.minecraft.server.MinecraftServer;
     15 import net.minecraft.server.network.ServerPlayNetworkHandler;
     16 import net.minecraft.server.network.ServerPlayerEntity;
     17 import net.minecraft.tag.TagPacketSerializer;
     18 import net.minecraft.text.*;
     19 import net.minecraft.util.ActionResult;
     20 import net.minecraft.util.Formatting;
     21 import net.minecraft.util.collection.PackedIntegerArray;
     22 import net.minecraft.util.math.BlockPos;
     23 import net.minecraft.util.math.GlobalPos;
     24 import net.minecraft.world.Difficulty;
     25 import net.minecraft.world.GameMode;
     26 import net.minecraft.world.World;
     27 import net.minecraft.world.border.WorldBorder;
     28 import net.minecraft.world.dimension.DimensionTypes;
     29 
     30 import java.util.*;
     31 
     32 public class OnPlayerConnectListener implements OnPlayerConnectCallback {
     33 
     34     private final Goauth plugin;
     35 
     36     public OnPlayerConnectListener(Goauth plugin) {
     37         this.plugin = plugin;
     38     }
     39 
     40     /**
     41      * Here we fake everything if the player is not registered or connecting from a new ip.
     42      * Just send him nothing and a link to authenticate.
     43      */
     44     @Override
     45     public ActionResult interact(ServerPlayerEntity player, ClientConnection connection) {
     46         MinecraftServer server = Objects.requireNonNull(player.getServer());
     47 
     48         // the player is in the whitelist, let the server do its things
     49         if (this.plugin.authStore.allowed(player, connection)) return ActionResult.PASS;
     50 
     51         this.plugin.logger.info(player.getGameProfile().getName() + " is connecting from a new ip - putting him into limbo");
     52 
     53         // fake initial connection info, use DummyServerPlayNetworkHandler to override all events and ignore them
     54         ServerPlayNetworkHandler serverPlayNetworkHandler = new DummyServerPlayNetworkHandler(server, connection, player, this.plugin);
     55         serverPlayNetworkHandler.sendPacket(new GameJoinS2CPacket(
     56                 player.getId(),
     57                 false,
     58                 GameMode.SPECTATOR,
     59                 GameMode.SPECTATOR,
     60                 server.getWorldRegistryKeys(),
     61                 ((PlayerManagerAccessor) server.getPlayerManager()).getRegistryManager(),
     62                 DimensionTypes.THE_END,
     63                 World.END,
     64                 420,
     65                 69,
     66                 3,
     67                 3,
     68                 true,
     69                 false,
     70                 false,
     71                 true,
     72                 Optional.of(GlobalPos.create(World.END, new BlockPos(0, 0, 0)))
     73         ));
     74         serverPlayNetworkHandler.sendPacket(new CustomPayloadS2CPacket(CustomPayloadS2CPacket.BRAND, (new PacketByteBuf(Unpooled.buffer())).writeString("limbo")));
     75 //        serverPlayNetworkHandler.sendPacket(new DifficultyS2CPacket(Difficulty.PEACEFUL, true));
     76 //        serverPlayNetworkHandler.sendPacket(new PlayerAbilitiesS2CPacket(player.getAbilities()));
     77 //        serverPlayNetworkHandler.sendPacket(new UpdateSelectedSlotS2CPacket(player.getInventory().selectedSlot));
     78         serverPlayNetworkHandler.sendPacket(new PlayerPositionLookS2CPacket(0, 0, 0, 0, 0, Collections.emptySet(), 1, true));
     79 //        serverPlayNetworkHandler.sendPacket(new GameStateChangeS2CPacket(GameStateChangeS2CPacket.GAME_MODE_CHANGED, GameMode.SPECTATOR.getId()));
     80 //        serverPlayNetworkHandler.sendPacket(new WorldBorderInitializeS2CPacket(new WorldBorder()));
     81 //        serverPlayNetworkHandler.sendPacket(new WorldTimeUpdateS2CPacket(0, 0, false));
     82 
     83         // From 1.19 the client will show a "Loading terrain..." screen until a chunk is sent.
     84         // Unfortunately there is no empty chunk constructor for ChunkDataS2CPacket,
     85         // so we have to create a buffer with the custom empty chunk, and only then create
     86         // the packet from the buffer.
     87         serverPlayNetworkHandler.sendPacket(new ChunkRenderDistanceCenterS2CPacket(0, 0));
     88         for (int i = -1; i < 2; i++) {
     89             for (int j = -1; j < 2; j++) {
     90                 PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer(800));
     91                 writeEmptyChunk(buf, 0, 0);
     92                 serverPlayNetworkHandler.sendPacket(new ChunkDataS2CPacket(buf));
     93             }
     94         }
     95 
     96         serverPlayNetworkHandler.sendPacket(new PlayerSpawnPositionS2CPacket(new BlockPos(0, 0, 0), 0.0f));
     97 
     98         MutableText welcomeMsg = Text.literal(this.plugin.welcomeText + " ").formatted(Formatting.BOLD, Formatting.YELLOW);
     99         MutableText text = Text.literal(this.plugin.authLinkText);
    100         Style urlStyle = Style.EMPTY
    101                 .withBold(false)
    102                 .withColor(TextColor.parse("white"))
    103                 .withUnderline(!this.plugin.authLink.isEmpty())
    104                 .withClickEvent(!this.plugin.authLink.isEmpty() ? new ClickEvent(ClickEvent.Action.OPEN_URL, this.plugin.authLink + "?username=" + player.getGameProfile().getName()) : null)
    105                 .withHoverEvent(!this.plugin.authLink.isEmpty() ? new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.of("Open link")) : null);
    106         text.setStyle(urlStyle);
    107         welcomeMsg.append(text);
    108         player.sendMessage(welcomeMsg);
    109 
    110         this.plugin.playersLimbo.put(player.getGameProfile().getName(), player);
    111 
    112         // return completely
    113         return ActionResult.FAIL;
    114     }
    115 
    116     public void writeEmptyChunk(PacketByteBuf buf, int x, int z) {
    117         // chunk coords
    118         buf.writeInt(x);
    119         buf.writeInt(z);
    120 
    121         // ChunkData
    122         // heightmap
    123         NbtCompound compound = new NbtCompound();
    124         compound.put("WORLD_SURFACE", new NbtLongArray(new PackedIntegerArray(9, 256).getData()));
    125         compound.put("MOTION_BLOCKING", new NbtLongArray(new PackedIntegerArray(9, 256).getData()));
    126         buf.writeNbt(compound);
    127 
    128         // Write 16 empty chunk sections consisting of
    129         //  - 2 bytes of a short (nonEmptyBlockCount)
    130         //  - 3 bytes for an empty blockStateContainer
    131         //  - 4 bytes for an empty biomeContainer
    132         buf.writeVarInt(16 * 9);
    133         buf.writeZero(16 * 9);
    134         buf.writeVarInt(0);
    135 
    136         // LightData
    137         buf.writeBoolean(true); // nonEdge
    138         buf.writeBitSet(new BitSet()); // initedSky
    139         buf.writeBitSet(new BitSet()); // initedBlock
    140         buf.writeBitSet(new BitSet()); // uninitedSky
    141         buf.writeBitSet(new BitSet()); // uninitedBlock
    142         buf.writeVarInt(0); // skyNibbles array length
    143         buf.writeVarInt(0); // blockNibbles array length
    144     }
    145 }