Compare commits

..
2 Commits
Author SHA1 Message Date
NotAlexNoyle a63a50f1cf Exclude CODEOWNERS from language statistics 2026-10-26 12:28:35 -04:00
NotAlexNoyle b34161bb49 Add CODEOWNERS (one staff approval) 2026-10-26 05:47:04 -04:00
34 changed files with 81 additions and 232 deletions

No files matched your search

+1
View File
@@ -22,3 +22,4 @@
# Common build-tool wrapper scripts ('.cmd' versions are handled by 'Common.gitattributes')
gradlew text eol=lf
.gitea/CODEOWNERS linguist-detectable=false
+3
View File
@@ -0,0 +1,3 @@
# Pull requests request review from the eligible staff team(s).
# One approval from either an Admin or Developer satisfies branch protection.
* @trueog/Admins @trueog/Developers
+1 -1
View File
@@ -47,7 +47,7 @@ Sonar analyzes a player's behavior before joining the actual server, therefore s
1. Sonar sends the player to a lightweight fake server when they connect for the first time.
2. Sonar verifies that players obey the laws of Minecraft's physics, including gravity and proper block collision.
3. Sonar verifies that players send legitimate packets when interacting with vehicles (e.g. boats).
4. Sonar makes sure that players send legitimate packets according to the [vanilla Minecraft protocol](<https://minecraft.wiki/w/Java_Edition_protocol/>).
4. Sonar makes sure that players send legitimate packets according to the [vanilla Minecraft protocol](<https://wiki.vg/Protocol>).
Sonar also protects against spambot attacks since it queues the incoming connections, therefore making it technically impossible to have a ton of bots join the server at the same time.
@@ -76,9 +76,7 @@ public enum ProtocolVersion {
MINECRAFT_1_21_7(772, "1.21.7"),
MINECRAFT_1_21_9(773, "1.21.9"),
MINECRAFT_1_21_11(774, "1.21.11"),
MINECRAFT_26_1(775, "26.1"),
MINECRAFT_26_2(776, "26.2"),
MINECRAFT_26_3(777, "26.3");
MINECRAFT_26_1(775, "26.1");
private final int protocol;
private final String name;
+3 -6
View File
@@ -75,12 +75,6 @@ allprojects {
compileJava {
options.encoding = "UTF-8"
options.release.set(17)
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
disableAutoTargetJvm()
}
jar {
@@ -99,6 +93,9 @@ allprojects {
attributes["Git-Commit"] = gitCommit
}
}
java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
}
}
@@ -82,9 +82,7 @@ public enum BukkitServerVersion {
MINECRAFT_1_21_9,
MINECRAFT_1_21_10,
MINECRAFT_1_21_11,
MINECRAFT_26_1,
MINECRAFT_26_2,
MINECRAFT_26_3;
MINECRAFT_26_1;
static final BukkitServerVersion[] REVERSED_VALUES;
@@ -73,19 +73,19 @@ class LibraryLoader {
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-text-minimessage")
.version("5.2.0")
.version("4.21.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build(),
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-text-serializer-gson")
.version("5.2.0")
.version("4.21.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build(),
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-nbt")
.version("5.2.0")
.version("4.21.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build()
);
@@ -95,7 +95,7 @@ class LibraryLoader {
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-nbt")
.version("5.2.0")
.version("4.21.0")
.relocate("net{}kyori{}adventure{}nbt", "xyz{}jonesdev{}sonar{}libs{}kyori{}adventure{}nbt")
.build()
);
@@ -21,7 +21,6 @@ import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
@ChannelHandler.Sharable
public final class TailExceptionsHandler extends ChannelDuplexHandler {
@@ -34,20 +33,6 @@ public final class TailExceptionsHandler extends ChannelDuplexHandler {
// Additionally, this will also run after our custom decoder.
@Override
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception {
// If ProtocolUtil#closeWith(...) already queued a graceful write-then-close for
// this channel (e.g. VerificationHandler#fail() calls disconnect() and then
// throws to unwind), don't race it with a second, immediate close() here. Doing
// so can abort the still-in-flight kick/disconnect packet write before it's fully
// flushed, so the client only receives a truncated packet instead of our message.
// The scheduled close from closeWith() will still run once the write completes.
// See: https://github.com/jonesdevelopment/sonar/issues/476
if (Boolean.TRUE.equals(ctx.channel().attr(ProtocolUtil.CLOSING).get())) {
if (LOG_EXCEPTIONS) {
cause.printStackTrace(System.err);
}
return;
}
// Close the channel if we encounter any errors.
ctx.close();
if (LOG_EXCEPTIONS) {
@@ -105,11 +105,7 @@ public class SonarPacketPreparer {
public final SonarPacket[] REGISTRY_SYNC_1_21_5 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_5);
public final SonarPacket[] REGISTRY_SYNC_1_21_11 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_11);
public final SonarPacket[] REGISTRY_SYNC_26_1 = RegistryDataPacket.of(DimensionRegistry.CODEC_26_1);
public final SonarPacket[] REGISTRY_SYNC_26_2 = RegistryDataPacket.of(DimensionRegistry.CODEC_26_2);
public final SonarPacket[] REGISTRY_SYNC_26_3 = RegistryDataPacket.of(DimensionRegistry.CODEC_26_3);
public final SonarPacket TAGS_UPDATE_26_1 = UpdateTagsPacket.of(DimensionRegistry.TAGS_26_1);
public final SonarPacket TAGS_UPDATE_26_2 = UpdateTagsPacket.of(DimensionRegistry.TAGS_26_2);
public final SonarPacket TAGS_UPDATE_26_3 = UpdateTagsPacket.of(DimensionRegistry.TAGS_26_3);
public final SonarPacket START_WRITING_CHUNKS = new GameEventPacket(13, 0);
public final static SonarPacket INVALID_HELD_ITEM_SLOT = new SetHeldItemPacket(-1);
public final SonarPacket RANDOM_KEEP_ALIVE = new SonarPacketSnapshot(new KeepAlivePacket(RANDOM.nextInt()));
@@ -156,7 +152,7 @@ public class SonarPacketPreparer {
if (username.length() > 16) {
username = username.substring(0, 16);
}
loginSuccess = new SonarPacketSnapshot(new LoginSuccessPacket(uuid, username, true, UUID.randomUUID()));
loginSuccess = new SonarPacketSnapshot(new LoginSuccessPacket(uuid, username, true));
// Prepare JoinGame packet
joinGame = new SonarPacketSnapshot(new JoinGamePacket(PLAYER_ENTITY_ID,
@@ -166,7 +162,7 @@ public class SonarPacketPreparer {
new String[]{"minecraft:overworld"}, "minecraft:overworld", "flat",
DimensionType.OVERWORLD, RANDOM.nextLong() & 1337,
false, true, false,
false, false, false, true, false));
false, false, false, true));
// Prepare the gravity check
maxMovementTick = Sonar.get0().getConfig().getVerification().getGravity().getMaxMovementTicks();
@@ -298,22 +294,14 @@ public class SonarPacketPreparer {
}
public static @Nullable SonarPacket getTagsPacket(final @NotNull ProtocolVersion protocolVersion) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
return TAGS_UPDATE_26_3;
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_2)) {
return TAGS_UPDATE_26_2;
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_1)) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_1)) {
return TAGS_UPDATE_26_1;
}
return null; // apparently doesn't crash the client; we're safe... for now.
}
public static SonarPacket[] getRegistryPackets(final @NotNull ProtocolVersion protocolVersion) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
return REGISTRY_SYNC_26_3;
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_2)) {
return REGISTRY_SYNC_26_2;
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_1)) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_1)) {
return REGISTRY_SYNC_26_1;
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_11)) {
return REGISTRY_SYNC_1_21_11;
@@ -77,8 +77,7 @@ public enum SonarPacketRegistry {
map(0x05, MINECRAFT_1_20_2, true),
map(0x07, MINECRAFT_1_20_5, true));
clientbound.register(UpdateTagsPacket.class, UpdateTagsPacket::new,
map(0x0D, MINECRAFT_1_20_5, true),
map(0x0E, MINECRAFT_26_3, true));
map(0x0D, MINECRAFT_1_20_5, true));
serverbound.register(ClientInformationPacket.class, ClientInformationPacket::new,
map(0x00, MINECRAFT_1_20_2, false));
@@ -114,8 +113,7 @@ public enum SonarPacketRegistry {
map(0x2C, MINECRAFT_1_21_2, true),
map(0x2B, MINECRAFT_1_21_5, true),
map(0x30, MINECRAFT_1_21_9, true),
map(0x31, MINECRAFT_26_1, true),
map(0x32, MINECRAFT_26_3, true));
map(0x31, MINECRAFT_26_1, true));
// minecraft:keep_alive
clientbound.register(KeepAlivePacket.class, KeepAlivePacket::new,
map(0x00, MINECRAFT_1_7_2, true),
@@ -135,8 +133,7 @@ public enum SonarPacketRegistry {
map(0x27, MINECRAFT_1_21_2, true),
map(0x26, MINECRAFT_1_21_5, true),
map(0x2B, MINECRAFT_1_21_9, true),
map(0x2C, MINECRAFT_26_1, true),
map(0x2D, MINECRAFT_26_3, true));
map(0x2C, MINECRAFT_26_1, true));
// minecraft:disconnect
clientbound.register(DisconnectPacket.class, DisconnectPacket::new,
map(0x40, MINECRAFT_1_7_2, true),
@@ -175,8 +172,7 @@ public enum SonarPacketRegistry {
map(0x42, MINECRAFT_1_21_2, true),
map(0x41, MINECRAFT_1_21_5, true),
map(0x46, MINECRAFT_1_21_9, true),
map(0x48, MINECRAFT_26_1, true),
map(0x49, MINECRAFT_26_3, true));
map(0x48, MINECRAFT_26_1, true));
// minecraft:player_abilities
clientbound.register(PlayerAbilitiesPacket.class, PlayerAbilitiesPacket::new,
map(0x39, MINECRAFT_1_7_2, true),
@@ -197,8 +193,7 @@ public enum SonarPacketRegistry {
map(0x3A, MINECRAFT_1_21_2, true),
map(0x39, MINECRAFT_1_21_5, true),
map(0x3E, MINECRAFT_1_21_9, true),
map(0x40, MINECRAFT_26_1, true),
map(0x41, MINECRAFT_26_3, true));
map(0x40, MINECRAFT_26_1, true));
// minecraft:level_chunk_with_light
clientbound.register(ChunkDataPacket.class, ChunkDataPacket::new,
map(0x21, MINECRAFT_1_7_2, true),
@@ -218,8 +213,7 @@ public enum SonarPacketRegistry {
map(0x28, MINECRAFT_1_21_2, true),
map(0x27, MINECRAFT_1_21_5, true),
map(0x2C, MINECRAFT_1_21_9, true),
map(0x2D, MINECRAFT_26_1, true),
map(0x2E, MINECRAFT_26_3, true));
map(0x2D, MINECRAFT_26_1, true));
// minecraft:remove_entities
clientbound.register(RemoveEntitiesPacket.class, RemoveEntitiesPacket::new,
map(0x13, MINECRAFT_1_7_2, true),
@@ -242,8 +236,7 @@ public enum SonarPacketRegistry {
map(0x47, MINECRAFT_1_21_2, true),
map(0x46, MINECRAFT_1_21_5, true),
map(0x4B, MINECRAFT_1_21_9, true),
map(0x4D, MINECRAFT_26_1, true),
map(0x4E, MINECRAFT_26_3, true));
map(0x4D, MINECRAFT_26_1, true));
// minecraft:set_passengers
clientbound.register(SetPassengersPacket.class, SetPassengersPacket::new,
map(0x1B, MINECRAFT_1_7_2, true),
@@ -263,8 +256,7 @@ public enum SonarPacketRegistry {
map(0x65, MINECRAFT_1_21_2, true),
map(0x64, MINECRAFT_1_21_5, true),
map(0x69, MINECRAFT_1_21_9, true),
map(0x6B, MINECRAFT_26_1, true),
map(0x6D, MINECRAFT_26_3, true));
map(0x6B, MINECRAFT_26_1, true));
// minecraft:add_entity
clientbound.register(SpawnEntityPacket.class, SpawnEntityPacket::new,
map(0x0E, MINECRAFT_1_7_2, true),
@@ -289,8 +281,7 @@ public enum SonarPacketRegistry {
map(0x4E, MINECRAFT_1_21_2, true),
map(0x4D, MINECRAFT_1_21_5, true),
map(0x52, MINECRAFT_1_21_9, true),
map(0x54, MINECRAFT_26_1, true),
map(0x56, MINECRAFT_26_3, true));
map(0x54, MINECRAFT_26_1, true));
// minecraft:ping
clientbound.register(TransactionPacket.class, TransactionPacket::new,
map(0x32, MINECRAFT_1_7_2, true),
@@ -309,8 +300,7 @@ public enum SonarPacketRegistry {
map(0x37, MINECRAFT_1_21_2, true),
map(0x36, MINECRAFT_1_21_5, true),
map(0x3B, MINECRAFT_1_21_9, true),
map(0x3D, MINECRAFT_26_1, true),
map(0x3E, MINECRAFT_26_3, true));
map(0x3D, MINECRAFT_26_1, true));
// minecraft:set_default_spawn_position
clientbound.register(SetDefaultSpawnPositionPacket.class, SetDefaultSpawnPositionPacket::new,
map(0x05, MINECRAFT_1_7_2, true),
@@ -332,8 +322,7 @@ public enum SonarPacketRegistry {
map(0x5B, MINECRAFT_1_21_2, true),
map(0x5A, MINECRAFT_1_21_5, true),
map(0x5F, MINECRAFT_1_21_9, true),
map(0x61, MINECRAFT_26_1, true),
map(0x63, MINECRAFT_26_3, true));
map(0x61, MINECRAFT_26_1, true));
// minecraft:map_item_data
clientbound.register(MapDataPacket.class, MapDataPacket::new,
map(0x34, MINECRAFT_1_7_2, true),
@@ -352,8 +341,7 @@ public enum SonarPacketRegistry {
map(0x2D, MINECRAFT_1_21_2, true),
map(0x2C, MINECRAFT_1_21_5, true),
map(0x31, MINECRAFT_1_21_9, true),
map(0x33, MINECRAFT_26_1, true),
map(0x34, MINECRAFT_26_3, true));
map(0x33, MINECRAFT_26_1, true));
// minecraft:container_set_slot
clientbound.register(SetContainerSlotPacket.class, SetContainerSlotPacket::new,
map(0x2F, MINECRAFT_1_7_2, true),
@@ -388,8 +376,7 @@ public enum SonarPacketRegistry {
map(0x61, MINECRAFT_1_21_2, true),
map(0x60, MINECRAFT_1_21_5, true),
map(0x65, MINECRAFT_1_21_9, true),
map(0x67, MINECRAFT_26_1, true),
map(0x69, MINECRAFT_26_3, true));
map(0x67, MINECRAFT_26_1, true));
// minecraft:system_chat
clientbound.register(SystemChatPacket.class, SystemChatPacket::new,
map(0x02, MINECRAFT_1_7_2, true),
@@ -408,23 +395,20 @@ public enum SonarPacketRegistry {
map(0x73, MINECRAFT_1_21_2, true),
map(0x72, MINECRAFT_1_21_5, true),
map(0x77, MINECRAFT_1_21_9, true),
map(0x79, MINECRAFT_26_1, true),
map(0x7C, MINECRAFT_26_3, true));
map(0x79, MINECRAFT_26_1, true));
// minecraft:game_event
clientbound.register(GameEventPacket.class, GameEventPacket::new,
map(0x20, MINECRAFT_1_20_3, true),
map(0x22, MINECRAFT_1_20_5, true),
map(0x23, MINECRAFT_1_21_2, true),
map(0x22, MINECRAFT_1_21_5, true),
map(0x26, MINECRAFT_1_21_9, true),
map(0x27, MINECRAFT_26_3, true));
map(0x26, MINECRAFT_1_21_9, true));
// minecraft:transfer
clientbound.register(TransferPacket.class, TransferPacket::new,
map(0x73, MINECRAFT_1_20_5, true),
map(0x7A, MINECRAFT_1_21_2, true),
map(0x7F, MINECRAFT_1_21_9, true),
map(0x81, MINECRAFT_26_1, true),
map(0x84, MINECRAFT_26_3, true));
map(0x81, MINECRAFT_26_1, true));
// minecraft:set_held_slot
clientbound.register(SetHeldItemPacket.class, SetHeldItemPacket::new,
map(0x09, MINECRAFT_1_7_2, true),
@@ -446,8 +430,7 @@ public enum SonarPacketRegistry {
map(0x63, MINECRAFT_1_21_2, true),
map(0x62, MINECRAFT_1_21_5, true),
map(0x67, MINECRAFT_1_21_9, true),
map(0x69, MINECRAFT_26_1, true),
map(0x6B, MINECRAFT_26_3, true));
map(0x69, MINECRAFT_26_1, true));
// minecraft:animate
clientbound.register(EntityAnimationPacket.class, EntityAnimationPacket::new,
map(0x0B, MINECRAFT_1_7_2, true),
@@ -479,8 +462,7 @@ public enum SonarPacketRegistry {
map(0x6B, MINECRAFT_1_21_2, true),
map(0x6A, MINECRAFT_1_21_5, true),
map(0x6F, MINECRAFT_1_21_9, true),
map(0x71, MINECRAFT_26_1, true),
map(0x73, MINECRAFT_26_3, true));
map(0x71, MINECRAFT_26_1, true));
// minecraft:client_tick_end
serverbound.register(ClientTickEndPacket.class, ClientTickEndPacket::new,
@@ -504,8 +486,7 @@ public enum SonarPacketRegistry {
map(0x31, MINECRAFT_1_21_2, false),
map(0x33, MINECRAFT_1_21_4, false),
map(0x34, MINECRAFT_1_21_6, false),
map(0x35, MINECRAFT_26_1, false),
map(0x36, MINECRAFT_26_3, false));
map(0x35, MINECRAFT_26_1, false));
// minecraft:paddle_boat
serverbound.register(PaddleBoatPacket.class, PaddleBoatPacket::new,
map(0x11, MINECRAFT_1_9, false),
@@ -544,8 +525,7 @@ public enum SonarPacketRegistry {
map(0x28, MINECRAFT_1_21_2, false),
map(0x29, MINECRAFT_1_21_4, false),
map(0x2A, MINECRAFT_1_21_6, false),
map(0x26, MINECRAFT_26_1, false),
map(0x2B, MINECRAFT_26_3, false));
map(0x26, MINECRAFT_26_1, false));
// minecraft:move_vehicle
serverbound.register(VehicleMovePacket.class, VehicleMovePacket::new,
map(0x10, MINECRAFT_1_9, false),
@@ -754,8 +734,7 @@ public enum SonarPacketRegistry {
map(0x3A, MINECRAFT_1_21_4, false),
map(0x3B, MINECRAFT_1_21_5, false),
map(0x3C, MINECRAFT_1_21_6, false),
map(0x3F, MINECRAFT_26_1, false),
map(0x2E, MINECRAFT_26_3, false));
map(0x3F, MINECRAFT_26_1, false));
}
};
@@ -80,10 +80,7 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 9250;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 9451;
}
return 11185;
return 9451;
}, protocolVersion -> (double) 0.75f),
TRAPDOOR(protocolVersion -> {
// We have to use wooden trapdoors for 1.7 since 1.7 doesn't have iron trapdoors
@@ -138,10 +135,7 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 12380;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 12582;
}
return 14429;
return 12582;
}, protocolVersion -> 0.1875),
END_PORTAL_FRAME(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -189,10 +183,7 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 9272;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 9473;
}
return 11207;
return 9473;
}, protocolVersion -> 0.8125),
DAYLIGHT_SENSOR(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -243,10 +234,7 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 11093;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 11295;
}
return 13062;
return 11295;
}, protocolVersion -> 0.375),
COBBLESTONE_WALL(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -294,10 +282,7 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 9783;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 9984;
}
return 11726;
return 9984;
}, protocolVersion -> 1.5),
STONE_SLABS(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -348,10 +333,7 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 13197;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 13399;
}
return 15252;
return 13399;
}, protocolVersion -> 0.5),
WHITE_CARPET(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -402,10 +384,7 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 12694;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 12896;
}
return 14743;
return 12896;
}, protocolVersion -> protocolVersion.compareTo(MINECRAFT_1_8) < 0 ? 0 : 0.0625);
private final Function<ProtocolVersion, Integer> id;
@@ -42,11 +42,7 @@ public final class DimensionRegistry {
public final CompoundBinaryTag CODEC_1_21_5;
public final CompoundBinaryTag CODEC_1_21_11;
public final CompoundBinaryTag CODEC_26_1;
public final CompoundBinaryTag CODEC_26_2;
public final CompoundBinaryTag CODEC_26_3;
public final CompoundBinaryTag TAGS_26_1;
public final CompoundBinaryTag TAGS_26_2;
public final CompoundBinaryTag TAGS_26_3;
static {
CODEC_1_16 = getCodec("codec_1_16.nbt");
@@ -63,11 +59,7 @@ public final class DimensionRegistry {
CODEC_1_21_5 = getCodec("codec_1_21_5.nbt");
CODEC_1_21_11 = getCodec("codec_1_21_11.nbt");
CODEC_26_1 = getCodec("codec_26_1.nbt");
CODEC_26_2 = getCodec("codec_26_2.nbt");
CODEC_26_3 = getCodec("codec_26_3.nbt");
TAGS_26_1 = getCodec("tags_26_1.nbt");
TAGS_26_2 = getCodec("tags_26_2.nbt");
TAGS_26_3 = getCodec("tags_26_3.nbt");
}
private @NotNull CompoundBinaryTag getCodec(final @NotNull String fileName) {
@@ -67,10 +67,7 @@ public enum EntityType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_9)) {
return 87;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 89;
}
return 90;
return 89;
}),
MINECART(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_2)) {
@@ -115,10 +112,7 @@ public enum EntityType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_9)) {
return 84;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 85;
}
return 86;
return 85;
});
private final Function<ProtocolVersion, Integer> id;
@@ -85,13 +85,7 @@ public enum ItemType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 1104;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_1)) {
return 1105;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 1133;
}
return 1238;
return 1105;
}, protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
return 26;
@@ -105,10 +99,7 @@ public enum ItemType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 44;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 46;
}
return 48;
return 46;
});
private final Function<ProtocolVersion, Integer> id;
@@ -50,7 +50,7 @@ public final class RegistryDataPacket implements SonarPacket {
for (final RegistryDataPacket.Bundle bundle : bundles) {
ProtocolUtil.writeString(byteBuf, bundle.getName());
// Write the bundle tag
final BinaryTag tag = bundle.getTag();
final CompoundBinaryTag tag = bundle.getTag();
if (tag != null) {
byteBuf.writeBoolean(true);
ProtocolUtil.writeBinaryTag(byteBuf, protocolVersion, tag);
@@ -73,7 +73,8 @@ public final class RegistryDataPacket implements SonarPacket {
final ArrayList<RegistryDataPacket.Bundle> bundles = new ArrayList<>();
for (final BinaryTag binaryTag : rootTag.getCompound(type).getList("value")) {
final CompoundBinaryTag tag = (CompoundBinaryTag) binaryTag;
bundles.add(new Bundle(tag.getString("name"), tag.get("element")));
// CompoundBinaryTag#getCompound(String) will return an empty compound tag when not exist.
bundles.add(new Bundle(tag.getString("name"), tag.get("element") == null ? null : tag.getCompound("element")));
}
packets[index++] = new SonarPacketSnapshot(new RegistryDataPacket(rootTag, type, bundles));
}
@@ -85,6 +86,6 @@ public final class RegistryDataPacket implements SonarPacket {
public static class Bundle {
@NotNull String name;
// In the protocol, it is able to be null
@Nullable BinaryTag tag;
@Nullable CompoundBinaryTag tag;
}
}
@@ -38,7 +38,6 @@ public final class LoginSuccessPacket implements SonarPacket {
private UUID uuid;
private String username;
private boolean strictErrorHandling;
private UUID sessionId;
@Override
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
@@ -62,10 +61,6 @@ public final class LoginSuccessPacket implements SonarPacket {
// Whether the client should disconnect on its own if it receives invalid data from the server
byteBuf.writeBoolean(strictErrorHandling);
}
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_2)) {
ProtocolUtil.writeUUID(byteBuf, sessionId);
}
}
@Override
@@ -46,8 +46,6 @@ public final class AnimationPacket implements SonarPacket {
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_8)) {
entityId = byteBuf.readInt();
type = LegacyAnimationType.getById(byteBuf.readByte());
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
hand = MAIN_HAND;
} else if (protocolVersion.greaterThan(ProtocolVersion.MINECRAFT_1_8)) {
// Only 1.9+ clients have an offhand
hand = ProtocolUtil.readVarInt(byteBuf);
@@ -32,15 +32,6 @@ import xyz.jonesdev.sonar.common.util.ProtocolUtil;
@AllArgsConstructor
public final class ConfirmTeleportationPacket implements SonarPacket {
private int teleportId;
private double x;
private double y;
private double z;
private float yaw;
private float pitch;
public ConfirmTeleportationPacket(final int teleportId) {
this.teleportId = teleportId;
}
@Override
public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
@@ -50,12 +41,5 @@ public final class ConfirmTeleportationPacket implements SonarPacket {
@Override
public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception {
teleportId = ProtocolUtil.readVarInt(byteBuf);
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
x = byteBuf.readDouble();
y = byteBuf.readDouble();
z = byteBuf.readDouble();
yaw = byteBuf.readFloat();
pitch = byteBuf.readFloat();
}
}
}
@@ -58,7 +58,6 @@ public final class JoinGamePacket implements SonarPacket {
private boolean flat;
private boolean limitedCrafting;
private boolean secureProfile;
private boolean onlineMode;
@Override
public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
@@ -148,14 +147,8 @@ public final class JoinGamePacket implements SonarPacket {
ProtocolUtil.writeString(byteBuf, levelName);
byteBuf.writeLong(partialHashedSeed);
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
ProtocolUtil.writeVarInt(byteBuf, gamemode);
// ByteBufCodecs#OPTIONAL_VAR_INT: 0 for empty, (value + 1) if present
ProtocolUtil.writeVarInt(byteBuf, previousGamemode == -1 ? 0 : previousGamemode + 1);
} else {
byteBuf.writeByte(gamemode);
byteBuf.writeByte(previousGamemode);
}
byteBuf.writeByte(gamemode);
byteBuf.writeByte(previousGamemode);
}
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_16)) {
@@ -175,10 +168,7 @@ public final class JoinGamePacket implements SonarPacket {
ProtocolUtil.writeVarInt(byteBuf, seaLevel);
}
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_2)) {
byteBuf.writeBoolean(onlineMode);
byteBuf.writeBoolean(secureProfile);
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_20_5)) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_20_5)) {
byteBuf.writeBoolean(secureProfile);
}
}
@@ -24,7 +24,6 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.EncoderException;
import io.netty.util.AttributeKey;
import io.netty.util.Version;
import lombok.experimental.UtilityClass;
import net.kyori.adventure.nbt.BinaryTag;
@@ -218,20 +217,9 @@ public class ProtocolUtil {
}
}
public static final AttributeKey<Boolean> CLOSING = AttributeKey.valueOf("sonar-graceful-close-in-progress");
public static void closeWith(final @NotNull Channel channel,
final @NotNull ProtocolVersion protocolVersion,
final @NotNull Object msg) {
// Mark this channel as already undergoing a graceful close *before* we queue the
// write. If something downstream (e.g. an exception thrown right after this call,
// such as VerificationHandler#fail()'s QuietDecoderException) reaches
// TailExceptionsHandler while our writeAndFlush(...).addListener(CLOSE) is still
// in flight, that handler must not call ctx.close() a second time - doing so can
// abort the still-pending write and deliver only a truncated packet to the client
// (which then sees a bare disconnect/reset instead of our kick message).
// See: https://github.com/jonesdevelopment/sonar/issues/476
channel.attr(CLOSING).set(true);
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_8)) {
channel.eventLoop().execute(() -> {
channel.config().setAutoRead(false);
@@ -36,9 +36,8 @@ public final class GravityHandler extends VerificationHandler {
super(user);
this.preJoinHandler = preJoinHandler;
// Client can send movement packet without first position-and-rot packet (usually caused by teleport, < 26.3 Java)
// 26.3+ client will no longer send movement packet for teleports. (positions included in teleport confirm)
this.canFall = user.isGeyser() || user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3);
// Bedrock users start falling immediately
this.canFall = user.isGeyser();
// We don't want to check Geyser players for valid gravity, as this might cause issues because of the protocol
this.enableGravityCheck = !user.isGeyser() && AntiBot.shouldPerform(
Sonar.get0().getConfig().getVerification().getGravity().getTiming());
@@ -109,8 +108,6 @@ public final class GravityHandler extends VerificationHandler {
final SetPlayerPositionRotationPacket position = (SetPlayerPositionRotationPacket) packet;
if (teleported) {
handleMovement(position.getX(), position.getY(), position.getZ(), position.isOnGround(), true);
} else if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
return;
} else if (user.getProtocolVersion().equals(ProtocolVersion.MINECRAFT_1_21_2)) {
lastPositionPacket = position;
return;
@@ -125,8 +122,6 @@ public final class GravityHandler extends VerificationHandler {
if (teleported) {
final SetPlayerPositionPacket position = (SetPlayerPositionPacket) packet;
handleMovement(position.getX(), position.getY(), position.getZ(), position.isOnGround(), false);
} else if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
return;
}
checkClientTick();
} else if (packet instanceof ConfirmTeleportationPacket) {
@@ -138,15 +133,11 @@ public final class GravityHandler extends VerificationHandler {
checkState(confirmTeleport.getTeleportId() == expectedTeleportId,
"expected TP ID " + expectedTeleportId + ", but got " + confirmTeleport.getTeleportId());
final boolean v26_3 = user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3);
final boolean sendPosRotBefore = user.getProtocolVersion().equals(ProtocolVersion.MINECRAFT_1_21_2);
if (!v26_3) {
checkState(sendPosRotBefore ? lastPositionPacket != null : !expectTeleportPosRot,
"expected position rotation but got teleport confirm.");
if (!sendPosRotBefore) {
expectTeleportPosRot = true;
}
checkState(sendPosRotBefore ? lastPositionPacket != null : !expectTeleportPosRot,
"expected position rotation but got teleport confirm.");
if (!sendPosRotBefore) {
expectTeleportPosRot = true;
}
// The first teleport ID is not useful for us in this context, skip it
@@ -156,11 +147,7 @@ public final class GravityHandler extends VerificationHandler {
// Enable the movement checks
teleported = true;
if (v26_3) {
handleMovement(
confirmTeleport.getX(), confirmTeleport.getY(), confirmTeleport.getZ(),
false, true);
} else if (sendPosRotBefore) {
if (sendPosRotBefore) {
handleMovement(
lastPositionPacket.getX(), lastPositionPacket.getY(), lastPositionPacket.getZ(),
lastPositionPacket.isOnGround(), true);
@@ -261,8 +248,7 @@ public final class GravityHandler extends VerificationHandler {
// The deltaY is 0 whenever the player sends their first position packet.
// We have to account for this or the player will falsely fail the verification.
if (deltaY == 0) {
checkState(user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3) || rotated,
"illegal movement packet order: " + deltaY);
checkState(rotated, "illegal movement packet order: " + deltaY);
checkState(movementTick == 0, "illegal y motion: " + movementTick);
// 1.7 clients immediately start falling after this packet
if (user.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_8)) {
@@ -71,8 +71,7 @@ public final class ProtocolHandler extends VerificationHandler {
waitingSlotConfirm = false;
expectedSlotId = -1;
// The player did not send duplicate packets, so they pass this check
// 26.3+ removed client-side swing packet echo, so exempt 26.3+ from the arm animation check
if (user.isGeyser() || user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
if (user.isGeyser()) {
markSuccess();
} else {
sendArmAnimation();
@@ -121,7 +121,7 @@ public abstract class VerificationHandler implements SonarPacketListener {
// The user is allowed to disable the blacklist entirely by setting the threshold to 0
final int limit = Sonar.get0().getConfig().getVerification().getBlacklistThreshold();
// The player hasn't been blacklisted yet, so skip this iteration
if (limit <= 0 || newScore < limit) break blacklist;
if (newScore < limit) break blacklist;
GlobalSonarStatistics.totalBlacklistedPlayers++;
+1 -1
View File
@@ -1,3 +1,3 @@
group=xyz.jonesdev
version=2.1.52
version=2.1.47
description=A lightweight, effective, and easy-to-use anti-bot plugin for Velocity, BungeeCord, and Bukkit.
+5 -5
View File
@@ -1,6 +1,6 @@
[versions]
netty = "4.2.18.Final"
adventure = "5.2.0"
netty = "4.2.15.Final"
adventure = "4.24.0"
adventure-platform = "4.4.1"
bstats = "3.2.1"
libby = "2.0.0-SNAPSHOT"
@@ -8,8 +8,8 @@ pluginyml = "0.6.0"
[plugins]
indra-git = "net.kyori.indra.git:3.2.0"
shadow = "com.gradleup.shadow:9.6.1"
spotless = "com.diffplug.spotless:8.10.2"
shadow = "com.gradleup.shadow:9.4.1"
spotless = "com.diffplug.spotless:8.6.0"
pluginyml-bungee = { id = "net.minecrell.plugin-yml.bungee", version.ref = "pluginyml" }
pluginyml-bukkit = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" }
pluginyml-paper = { id = "net.minecrell.plugin-yml.paper", version.ref = "pluginyml" }
@@ -34,7 +34,7 @@ caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.4"
annotations = "org.jetbrains:annotations:26.1.0"
simpleyaml = "com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4"
ormlite = "com.j256.ormlite:ormlite-jdbc:6.1"
lombok = "org.projectlombok:lombok:1.18.48"
lombok = "org.projectlombok:lombok:1.18.46"
bungeecord = "net.md-5:bungeecord-proxy:26.1-R0.1-SNAPSHOT"
velocity = "io.papermc.velocity:velocity-proxy:3.5.0-SNAPSHOT"
paper = "io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT"
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
Vendored
+2 -2
View File
@@ -20,7 +20,7 @@
##############################################################################
#
# gradlew start up script for POSIX generated by Gradle.
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
@@ -29,7 +29,7 @@
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh gradlew
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
Vendored
+2 -2
View File
@@ -19,7 +19,7 @@
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem gradlew startup script for Windows
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@@ -72,7 +72,7 @@ echo location of your Java installation. 1>&2
@rem Execute gradlew
@rem Execute Gradle
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
@rem which allows us to clear the local environment before executing the java command
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
+3
View File
@@ -22,3 +22,6 @@ tasks {
}
}
}
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17