diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f869d20..b1bca69 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,16 +13,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v3.0.0
+ uses: actions/checkout@v4.2.2
- name: Set up JDK
- uses: actions/setup-java@v3.0.0
+ uses: actions/setup-java@v4.7.0
with:
- distribution: adopt
- java-version: 17
+ distribution: temurin
+ java-version: 25
- name: Build LimboFilter
run: ./gradlew build
- name: Upload LimboFilter
- uses: actions/upload-artifact@v3.0.0
+ uses: actions/upload-artifact@v4.6.2
with:
name: LimboFilter
path: "build/libs/limbofilter*.jar"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0676a79..c6e9830 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -9,16 +9,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v3.0.0
+ uses: actions/checkout@v4.2.2
- name: Set up JDK
- uses: actions/setup-java@v3.0.0
+ uses: actions/setup-java@v4.7.0
with:
- distribution: adopt
- java-version: 17
+ distribution: temurin
+ java-version: 25
- name: Build LimboFilter
run: ./gradlew build
- name: Upload LimboFilter
- uses: actions/upload-artifact@v3.0.0
+ uses: actions/upload-artifact@v4.6.2
with:
name: LimboFilter
path: "build/libs/limbofilter*.jar"
diff --git a/HEADER.txt b/HEADER.txt
index 1fde5b4..99a4f73 100644
--- a/HEADER.txt
+++ b/HEADER.txt
@@ -1,4 +1,4 @@
-Copyright (C) 2021 - 2023 Elytrium
+Copyright (C) 2021 - 2025 Elytrium
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
diff --git a/VERSION b/VERSION
index e9bc149..852ed67 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.14
+1.1.18
diff --git a/build.gradle b/build.gradle
index e0430cc..7d0930b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,21 +3,21 @@
plugins {
id("java")
id("checkstyle")
- id("com.github.spotbugs").version("5.0.6")
- id("org.cadixdev.licenser").version("0.6.1")
- id("com.github.johnrengelman.shadow").version("7.1.2")
+ id("com.github.spotbugs").version("6.4.8")
+ id("net.minecraftforge.licenser").version("1.2.0")
+ id("com.gradleup.shadow").version("9.4.0")
}
setGroup("net.elytrium")
-setVersion("1.1.14")
+setVersion("1.1.19")
compileJava {
getOptions().setEncoding("UTF-8")
}
java {
- setSourceCompatibility(JavaVersion.VERSION_17)
- setTargetCompatibility(JavaVersion.VERSION_17)
+ setSourceCompatibility(JavaVersion.VERSION_21)
+ setTargetCompatibility(JavaVersion.VERSION_21)
}
repositories {
@@ -29,11 +29,7 @@ repositories {
}
maven {
setName("papermc-repo")
- setUrl("https://papermc.io/repo/repository/maven-public/")
- }
- maven() {
- setName("sonatype-snapshots-repo")
- setUrl("https://s01.oss.sonatype.org/content/repositories/snapshots/")
+ setUrl("https://repo.papermc.io/repository/maven-public/")
}
}
@@ -70,7 +66,6 @@ license {
}
checkstyle {
- setToolVersion("10.1")
setConfigFile(file("${this.getRootDir()}/config/checkstyle/checkstyle.xml"))
setConfigProperties("configDirectory": "${this.getRootDir()}/config/checkstyle")
@@ -107,16 +102,7 @@ sourceSets.main.getJava().srcDir(
assemble.dependsOn(shadowJar)
String getCurrentShortRevision() {
- OutputStream outputStream = new ByteArrayOutputStream()
- exec {
- if (System.getProperty("os.name").toLowerCase().contains("win")) {
- commandLine("cmd", "/c", "git rev-parse --short HEAD")
- } else {
- commandLine("bash", "-c", "git rev-parse --short HEAD")
- }
-
- setStandardOutput(outputStream)
- }
-
- return outputStream.toString().trim()
+ return System.getProperty("os.name").toLowerCase().contains("win")
+ ? ["cmd", "/c", "git rev-parse --short HEAD"].execute().text.trim()
+ : ["bash", "-c", "git rev-parse --short HEAD"].execute().text.trim()
}
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index ebdad7f..d46c334 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -37,7 +37,7 @@
-
+
diff --git a/config/spotbugs/suppressions.xml b/config/spotbugs/suppressions.xml
index eb21bfb..1e4e2e6 100644
--- a/config/spotbugs/suppressions.xml
+++ b/config/spotbugs/suppressions.xml
@@ -7,4 +7,7 @@
+
+
+
diff --git a/gradle.properties b/gradle.properties
index fee5d72..2a8d17d 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,5 +1,5 @@
-limboapiVersion=1.1.14
-velocityVersion=3.3.0-SNAPSHOT
+limboapiVersion=1.1.27
+velocityVersion=3.5.0-SNAPSHOT
nettyVersion=4.1.86.Final
fastutilVersion=8.5.11
log4jVersion=2.19.0
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 00e33ed..221c4f9 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/src/main/java/net/elytrium/limbofilter/LimboFilter.java b/src/main/java/net/elytrium/limbofilter/LimboFilter.java
index 651c593..d671110 100644
--- a/src/main/java/net/elytrium/limbofilter/LimboFilter.java
+++ b/src/main/java/net/elytrium/limbofilter/LimboFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -30,7 +30,6 @@
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.scheduler.ScheduledTask;
import com.velocitypowered.proxy.console.VelocityConsole;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOError;
@@ -164,7 +163,6 @@ public void onProxyInitialization(ProxyInitializeEvent event) {
Configurator.setLevel(consoleLogger.getName(), consoleLogger.getLevel());
}
- @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "LEGACY_AMPERSAND can't be null in velocity.")
public void reload() {
Settings.IMP.reload(this.configFile, Settings.IMP.PREFIX);
@@ -238,6 +236,23 @@ public void reload() {
(float) captchaCoords.CAPTCHA_YAW, (float) captchaCoords.CAPTCHA_PITCH
);
+ // Make LimboAPI preload parent to captcha chunks to ensure that Sodium can properly render captcha.
+ if (Settings.IMP.MAIN.FRAMED_CAPTCHA.FRAMED_CAPTCHA_ENABLED) {
+ Settings.MAIN.FRAMED_CAPTCHA settings = Settings.IMP.MAIN.FRAMED_CAPTCHA;
+ for (int x = 0; x < settings.WIDTH; x++) {
+ this.filterWorld.getChunkOrNew(settings.COORDS.X + x, settings.COORDS.Z);
+ }
+
+ for (int x = -1; x <= 1; x++) {
+ for (int z = -1; z <= 1; z++) {
+ this.filterWorld.getChunkOrNew(
+ (int) captchaCoords.CAPTCHA_X + (x * 16),
+ (int) captchaCoords.CAPTCHA_Z + (z * 16)
+ );
+ }
+ }
+ }
+
if (Settings.IMP.MAIN.LOAD_WORLD) {
try {
Path path = this.dataDirectory.resolve(Settings.IMP.MAIN.WORLD_FILE_PATH);
@@ -279,8 +294,12 @@ public void reload() {
new PacketMapping(0x10, ProtocolVersion.MINECRAFT_1_19_4, false),
new PacketMapping(0x12, ProtocolVersion.MINECRAFT_1_20_2, false),
new PacketMapping(0x13, ProtocolVersion.MINECRAFT_1_20_3, false),
+ new PacketMapping(0x16, ProtocolVersion.MINECRAFT_1_20_5, false),
+ new PacketMapping(0x18, ProtocolVersion.MINECRAFT_1_21_2, false),
+ new PacketMapping(0x19, ProtocolVersion.MINECRAFT_1_21_6, false),
+ new PacketMapping(0x1A, ProtocolVersion.MINECRAFT_26_1, false),
})
- .registerPacket(PacketDirection.CLIENTBOUND, SetEntityMetadata.class, SetEntityMetadata::new, new PacketMapping[]{
+ .registerPacket(PacketDirection.CLIENTBOUND, SetEntityMetadata.class, null, new PacketMapping[]{
new PacketMapping(0x1C, ProtocolVersion.MINIMUM_VERSION, true),
new PacketMapping(0x39, ProtocolVersion.MINECRAFT_1_9, true),
new PacketMapping(0x3B, ProtocolVersion.MINECRAFT_1_12, true),
@@ -294,8 +313,13 @@ public void reload() {
new PacketMapping(0x52, ProtocolVersion.MINECRAFT_1_19_4, true),
new PacketMapping(0x54, ProtocolVersion.MINECRAFT_1_20_2, true),
new PacketMapping(0x56, ProtocolVersion.MINECRAFT_1_20_3, true),
+ new PacketMapping(0x58, ProtocolVersion.MINECRAFT_1_20_5, true),
+ new PacketMapping(0x5D, ProtocolVersion.MINECRAFT_1_21_2, true),
+ new PacketMapping(0x5C, ProtocolVersion.MINECRAFT_1_21_5, true),
+ new PacketMapping(0x61, ProtocolVersion.MINECRAFT_1_21_9, true),
+ new PacketMapping(0x63, ProtocolVersion.MINECRAFT_26_1, true),
})
- .registerPacket(PacketDirection.CLIENTBOUND, SpawnEntity.class, SpawnEntity::new, new PacketMapping[]{
+ .registerPacket(PacketDirection.CLIENTBOUND, SpawnEntity.class, null, new PacketMapping[]{
new PacketMapping(0x0E, ProtocolVersion.MINIMUM_VERSION, true),
new PacketMapping(0x00, ProtocolVersion.MINECRAFT_1_9, true),
new PacketMapping(0x01, ProtocolVersion.MINECRAFT_1_19_4, true),
@@ -379,6 +403,10 @@ public boolean shouldCheck(Player player) {
return false;
}
+ if (player.getRemoteAddress().getPort() == 0 && !this.checkCpsLimit(Settings.IMP.MAIN.FILTER_AUTO_TOGGLE.GEYSER_BYPASS)) {
+ return false;
+ }
+
return this.shouldCheck(player.getUsername(), player.getRemoteAddress().getAddress());
}
diff --git a/src/main/java/net/elytrium/limbofilter/Settings.java b/src/main/java/net/elytrium/limbofilter/Settings.java
index 987d1bc..16306ab 100644
--- a/src/main/java/net/elytrium/limbofilter/Settings.java
+++ b/src/main/java/net/elytrium/limbofilter/Settings.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -56,7 +56,7 @@ public static class MAIN {
public boolean CHECK_CLIENT_SETTINGS = true;
@Comment("Check if player's Minecraft client has a brand.")
public boolean CHECK_CLIENT_BRAND = true;
- @Comment("If player's Minecraft client brand (e.g. fabric or forge) is set here, then this player will be kicked.")
+ @Comment("If a player's Minecraft client brand (e.g., fabric or forge) is set here, then that player will be kicked.")
public List BLOCKED_CLIENT_BRANDS = List.of("brand1", "brand2");
@Comment("Time in milliseconds, how frequently will the cache list with verified players be reset. Before that time, verified players can join the server without passing antibot checks.")
public long PURGE_CACHE_MILLIS = 3600000;
@@ -98,7 +98,7 @@ public static class MAIN {
public boolean LOAD_WORLD = false;
@Comment({
- "World file type:",
+ "World file types:",
" SCHEMATIC (MCEdit .schematic, 1.12.2 and lower, not recommended)",
" STRUCTURE (structure block .nbt, any Minecraft version is supported, but the latest one is recommended).",
" WORLDEDIT_SCHEM (WorldEdit .schem, any Minecraft version is supported, but the latest one is recommended)."
@@ -118,7 +118,13 @@ public static class MAIN {
@Comment("Available: ADVENTURE, CREATIVE, SURVIVAL, SPECTATOR")
public GameMode GAME_MODE = GameMode.ADVENTURE;
- @Comment("Unit of time in seconds for the Auto Toggles the Statistics.")
+ @Comment({
+ "Should we prevent the player from falling after passing the fall check, or after they join the game when the ONLY_CAPTCHA mode is enabled",
+ "This might be useful when using a world schema to allow players to walk in that world"
+ })
+ public boolean DISABLE_FALLING_ON_CAPTCHA = true;
+
+ @Comment("Unit of time in seconds for the Auto Toggles and Statistics.")
public int UNIT_OF_TIME_CPS = 300;
@Comment("Unit of time in seconds for the Auto Toggles and the Statistics.")
@@ -170,6 +176,9 @@ public static class FILTER_AUTO_TOGGLE {
})
public int ONLINE_MODE_BYPASS = 49;
+ @Comment("Geyser players will bypass all anti-bot checks.")
+ public int GEYSER_BYPASS = 0;
+
@Comment({
"Verify Online Mode connection before AntiBot.",
"If connections per unit of time amount is bigger than the limit: online mode players will need to reconnect.",
@@ -186,7 +195,7 @@ public static class FILTER_AUTO_TOGGLE {
})
public int CHECK_STATE_TOGGLE = 0;
- @Comment("The player will need to reconnect after passing AntiBot check.")
+ @Comment("The player will need to reconnect after passing the AntiBot check.")
public int NEED_TO_RECONNECT = 129;
@Comment("Picture in the MOTD Server Ping packet will be disabled.")
@@ -251,7 +260,7 @@ public static class CAPTCHA_GENERATOR {
public boolean NUMBER_SPELLING = false;
@Comment({
"Set to true if you want to verify the number spelling configuration.",
- "The results will be saved to the number_spelling.txt file."
+ "Results will be saved to the number_spelling.txt file."
})
public boolean SAVE_NUMBER_SPELLING_OUTPUT = false;
public boolean EACH_WORD_ON_SEPARATE_LINE = true;
@@ -424,11 +433,11 @@ public static class STRINGS {
public String CHECKING_SUBTITLE = "&aPlease wait..";
public String CHECKING_CAPTCHA_CHAT = "{PRFX} &aPlease, solve the captcha, you have &6{0} &aattempts.";
- public String CHECKING_WRONG_CAPTCHA_CHAT = "{PRFX} &cYou entered the captcha incorrectly, you have &6{0} &cattempts left.";
+ public String CHECKING_WRONG_CAPTCHA_CHAT = "{PRFX} &cYou have entered the captcha incorrectly, you have &6{0} &cattempts left.";
public String CHECKING_CAPTCHA_TITLE = "&aPlease solve the captcha.";
public String CHECKING_CAPTCHA_SUBTITLE = "&aYou have &6{0} &aattempts.";
- public String SUCCESSFUL_CRACKED = "{PRFX} &aSuccessfully passed Bot-Filter check.";
+ public String SUCCESSFUL_CRACKED = "{PRFX} &aSuccessfully passed the Bot-Filter check.";
public String SUCCESSFUL_PREMIUM_KICK = "{PRFX}{NL}&aSuccessfully passed Bot-Filter check.{NL}&6Please, rejoin the server!";
public String CAPTCHA_FAILED_KICK = "{PRFX}{NL}&cYou've mistaken in captcha check.{NL}&6Please, rejoin the server.";
@@ -436,14 +445,14 @@ public static class STRINGS {
public String TIMES_UP = "{PRFX}{NL}&cYou have exceeded the maximum Bot-Filter check time.{NL}&6Please, rejoin the server.";
public String STATS_FORMAT = "&c&lTotal Blocked: &6&l{0} &c&l| Connections: &6&l{1}s &c&l| Pings: &6&l{2}s &c&l| Total Connections: &6&l{3} &c&l| L7 Ping: &6&l{4} &c&l| L4 Ping: &6&l{5}";
- public String STATS_ENABLED = "{PRFX} &aNow you see statistics in your action bar.";
- public String STATS_DISABLED = "{PRFX} &cYou're no longer see statistics in your action bar.";
+ public String STATS_ENABLED = "{PRFX} &aNow you may see statistics in your action bar.";
+ public String STATS_DISABLED = "{PRFX} &cYou can no longer see statistics in your action bar.";
public String SEND_PLAYER_SUCCESSFUL = "{PRFX} Successfully sent {0} to the filter limbo.";
- public String SEND_SERVER_SUCCESSFUL = "{PRFX} Successfully sent {0} players from {1} to the filter limbo.";
+ public String SEND_SERVER_SUCCESSFUL = "{PRFX} Successfully sent {0} players from {1} to filter limbo.";
public String SEND_FAILED = "{PRFX} There is no registered servers or connected players named {0}.";
- public String CAPTCHA_NOT_READY_YET = "{PRFX} Captcha is not ready yet. Try again in a few seconds";
+ public String CAPTCHA_NOT_READY_YET = "{PRFX} The captcha is not ready yet. Try again in a few seconds.";
}
}
}
diff --git a/src/main/java/net/elytrium/limbofilter/cache/CachedPackets.java b/src/main/java/net/elytrium/limbofilter/cache/CachedPackets.java
index 3d38ad6..20712b7 100644
--- a/src/main/java/net/elytrium/limbofilter/cache/CachedPackets.java
+++ b/src/main/java/net/elytrium/limbofilter/cache/CachedPackets.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -21,11 +21,12 @@
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
-import com.velocitypowered.proxy.protocol.packet.Disconnect;
+import com.velocitypowered.proxy.protocol.StateRegistry;
+import com.velocitypowered.proxy.protocol.packet.DisconnectPacket;
import com.velocitypowered.proxy.protocol.packet.chat.ChatType;
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
-import com.velocitypowered.proxy.protocol.packet.chat.SystemChat;
-import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChat;
+import com.velocitypowered.proxy.protocol.packet.chat.SystemChatPacket;
+import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChatPacket;
import com.velocitypowered.proxy.protocol.packet.title.GenericTitlePacket;
import java.text.MessageFormat;
import java.util.UUID;
@@ -35,6 +36,7 @@
import net.elytrium.limboapi.api.material.Item;
import net.elytrium.limboapi.api.material.VirtualItem;
import net.elytrium.limboapi.api.protocol.PreparedPacket;
+import net.elytrium.limboapi.api.protocol.item.ItemComponentMap;
import net.elytrium.limboapi.api.protocol.packets.PacketFactory;
import net.elytrium.limbofilter.LimboFilter;
import net.elytrium.limbofilter.Settings;
@@ -58,6 +60,7 @@ public class CachedPackets {
private PreparedPacket kickProxyCheck;
private PreparedPacket successfulBotFilterChat;
private PreparedPacket successfulBotFilterDisconnect;
+ private PreparedPacket fallingCheckChunkUnload;
private PreparedPacket noAbilities;
private PreparedPacket[] experience;
private PreparedPacket captchaNotReadyYet;
@@ -97,6 +100,7 @@ public void createPackets(LimboFactory limboFactory, PacketFactory packetFactory
this.successfulBotFilterDisconnect = this.createDisconnectPacket(limboFactory, strings.SUCCESSFUL_PREMIUM_KICK);
+ this.fallingCheckChunkUnload = this.createFallingCheckChunkUnloadPacket(limboFactory, packetFactory);
this.noAbilities = this.createAbilitiesPacket(limboFactory, packetFactory);
this.experience = this.createExpPackets(limboFactory, packetFactory);
@@ -169,7 +173,12 @@ private PreparedPacket[] createCaptchaAttemptsPacket(LimboFactory limboFactory,
this.createSetSlotPacketModern(
packetFactory, limboFactory.getItem(Item.FILLED_MAP), 1,
CompoundBinaryTag.builder().put("map", IntBinaryTag.intBinaryTag(0)).build()
- ), ProtocolVersion.MINECRAFT_1_17
+ ), ProtocolVersion.MINECRAFT_1_17, ProtocolVersion.MINECRAFT_1_20_3
+ ).prepare(
+ this.createSetSlotPacketComponent(
+ packetFactory, limboFactory.getItem(Item.FILLED_MAP), 1,
+ limboFactory.createItemComponentMap().add(ProtocolVersion.MINECRAFT_1_20_5, "minecraft:map_id", 0)
+ ), ProtocolVersion.MINECRAFT_1_20_5
);
}
packets[i] = packet.build();
@@ -190,7 +199,12 @@ private PreparedPacket[] createCaptchaAttemptsPacket(LimboFactory limboFactory,
this.createSetSlotPacketModern(
packetFactory, limboFactory.getItem(Item.FILLED_MAP), 1,
CompoundBinaryTag.builder().put("map", IntBinaryTag.intBinaryTag(0)).build()
- ), ProtocolVersion.MINECRAFT_1_17
+ ), ProtocolVersion.MINECRAFT_1_17, ProtocolVersion.MINECRAFT_1_20_3
+ ).prepare(
+ this.createSetSlotPacketComponent(
+ packetFactory, limboFactory.getItem(Item.FILLED_MAP), 1,
+ limboFactory.createItemComponentMap().add(ProtocolVersion.MINECRAFT_1_20_5, "minecraft:map_id", 0)
+ ), ProtocolVersion.MINECRAFT_1_20_5
);
}
packets[Settings.IMP.MAIN.CAPTCHA_ATTEMPTS].build();
@@ -211,6 +225,7 @@ public void dispose() {
this.singleDispose(this.kickProxyCheck);
this.singleDispose(this.successfulBotFilterChat);
this.singleDispose(this.successfulBotFilterDisconnect);
+ this.singleDispose(this.fallingCheckChunkUnload);
this.singleDispose(this.noAbilities);
this.singleDispose(this.experience);
this.singleDispose(this.captchaNotReadyYet);
@@ -294,6 +309,11 @@ private MinecraftPacket createUpdateViewPosition(PacketFactory factory, int x, i
return (MinecraftPacket) factory.createUpdateViewPositionPacket(x >> 4, z >> 4);
}
+ private PreparedPacket createFallingCheckChunkUnloadPacket(LimboFactory limboFactory, PacketFactory packetFactory) {
+ Settings.MAIN.FALLING_COORDS coords = Settings.IMP.MAIN.FALLING_COORDS;
+ return limboFactory.createPreparedPacket().prepare(packetFactory.createChunkUnloadPacket(coords.X >> 4, coords.Z >> 4), ProtocolVersion.MINECRAFT_1_21_2).build();
+ }
+
private PreparedPacket createAbilitiesPacket(LimboFactory limboFactory, PacketFactory packetFactory) {
return limboFactory.createPreparedPacket().prepare(packetFactory.createPlayerAbilitiesPacket((byte) 6, 0f, 0f)).build();
}
@@ -301,11 +321,9 @@ private PreparedPacket createAbilitiesPacket(LimboFactory limboFactory, PacketFa
private PreparedPacket[] createExpPackets(LimboFactory limboFactory, PacketFactory packetFactory) {
int ticks = Settings.IMP.MAIN.FALLING_CHECK_TICKS;
PreparedPacket[] packets = new PreparedPacket[ticks];
- float expInterval = 0.01F;
+ final int ticksM1 = ticks - 1;
for (int i = 0; i < ticks; ++i) {
- int percentage = i * 100 / ticks;
- packets[i] =
- limboFactory.createPreparedPacket().prepare(packetFactory.createSetExperiencePacket(percentage * expInterval, percentage, 0)).build();
+ packets[i] = limboFactory.createPreparedPacket().prepare(packetFactory.createSetExperiencePacket((float) i / ticksM1, (i * 100) / ticksM1, 0)).build();
}
return packets;
@@ -319,25 +337,30 @@ private MinecraftPacket createSetSlotPacketModern(PacketFactory packetFactory, V
return (MinecraftPacket) packetFactory.createSetSlotPacket(0, Settings.IMP.MAIN.CAPTCHA_LEFT_HAND ? 45 : 36, item, count, 0, nbt);
}
+ private MinecraftPacket createSetSlotPacketComponent(PacketFactory packetFactory, VirtualItem item, int count, ItemComponentMap map) {
+ return (MinecraftPacket) packetFactory.createSetSlotPacket(0, Settings.IMP.MAIN.CAPTCHA_LEFT_HAND ? 45 : 36, item, count, 0, map);
+ }
+
public void createChatPacket(PreparedPacket packet, String text) {
packet
- .prepare(new LegacyChat(
+ .prepare(new LegacyChatPacket(
ProtocolUtils.getJsonChatSerializer(ProtocolVersion.MINIMUM_VERSION).serialize(
LimboFilter.getSerializer().deserialize(text)
- ), LegacyChat.CHAT_TYPE, null
+ ), LegacyChatPacket.CHAT_TYPE, null
), ProtocolVersion.MINIMUM_VERSION, ProtocolVersion.MINECRAFT_1_15_2)
- .prepare(new LegacyChat(
+ .prepare(new LegacyChatPacket(
ProtocolUtils.getJsonChatSerializer(ProtocolVersion.MINECRAFT_1_16).serialize(
LimboFilter.getSerializer().deserialize(text)
- ), LegacyChat.CHAT_TYPE, null
+ ), LegacyChatPacket.CHAT_TYPE, null
), ProtocolVersion.MINECRAFT_1_16, ProtocolVersion.MINECRAFT_1_18_2)
- .prepare(version -> new SystemChat(
+ .prepare(version -> new SystemChatPacket(
new ComponentHolder(version, LimboFilter.getSerializer().deserialize(text)), ChatType.SYSTEM
), ProtocolVersion.MINECRAFT_1_19);
}
private PreparedPacket createDisconnectPacket(LimboFactory factory, String message) {
- return factory.createPreparedPacket().prepare(version -> Disconnect.create(LimboFilter.getSerializer().deserialize(message), version, false)).build();
+ return factory.createPreparedPacket().prepare(version ->
+ DisconnectPacket.create(LimboFilter.getSerializer().deserialize(message), version, StateRegistry.PLAY)).build();
}
public void createTitlePacket(PreparedPacket preparedPacket, String title, String subtitle) {
@@ -402,6 +425,10 @@ public PreparedPacket getSuccessfulBotFilterDisconnect() {
return this.successfulBotFilterDisconnect;
}
+ public PreparedPacket getFallingCheckChunkUnload() {
+ return this.fallingCheckChunkUnload;
+ }
+
public PreparedPacket getNoAbilities() {
return this.noAbilities;
}
diff --git a/src/main/java/net/elytrium/limbofilter/cache/captcha/CachedCaptcha.java b/src/main/java/net/elytrium/limbofilter/cache/captcha/CachedCaptcha.java
index 7b48f40..59663d6 100644
--- a/src/main/java/net/elytrium/limbofilter/cache/captcha/CachedCaptcha.java
+++ b/src/main/java/net/elytrium/limbofilter/cache/captcha/CachedCaptcha.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/captcha/CaptchaGenerator.java b/src/main/java/net/elytrium/limbofilter/captcha/CaptchaGenerator.java
index bfbdfd8..21d1edc 100644
--- a/src/main/java/net/elytrium/limbofilter/captcha/CaptchaGenerator.java
+++ b/src/main/java/net/elytrium/limbofilter/captcha/CaptchaGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/captcha/CaptchaHolder.java b/src/main/java/net/elytrium/limbofilter/captcha/CaptchaHolder.java
index 8ce143d..645f26c 100644
--- a/src/main/java/net/elytrium/limbofilter/captcha/CaptchaHolder.java
+++ b/src/main/java/net/elytrium/limbofilter/captcha/CaptchaHolder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/captcha/map/CraftMapCanvas.java b/src/main/java/net/elytrium/limbofilter/captcha/map/CraftMapCanvas.java
index 6a4201e..71921d4 100644
--- a/src/main/java/net/elytrium/limbofilter/captcha/map/CraftMapCanvas.java
+++ b/src/main/java/net/elytrium/limbofilter/captcha/map/CraftMapCanvas.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/captcha/painter/CaptchaEffect.java b/src/main/java/net/elytrium/limbofilter/captcha/painter/CaptchaEffect.java
index 900e4bc..cd06985 100644
--- a/src/main/java/net/elytrium/limbofilter/captcha/painter/CaptchaEffect.java
+++ b/src/main/java/net/elytrium/limbofilter/captcha/painter/CaptchaEffect.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/captcha/painter/CaptchaPainter.java b/src/main/java/net/elytrium/limbofilter/captcha/painter/CaptchaPainter.java
index f2175ca..7608950 100644
--- a/src/main/java/net/elytrium/limbofilter/captcha/painter/CaptchaPainter.java
+++ b/src/main/java/net/elytrium/limbofilter/captcha/painter/CaptchaPainter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/captcha/painter/OutlineEffect.java b/src/main/java/net/elytrium/limbofilter/captcha/painter/OutlineEffect.java
index 631de97..e151e5d 100644
--- a/src/main/java/net/elytrium/limbofilter/captcha/painter/OutlineEffect.java
+++ b/src/main/java/net/elytrium/limbofilter/captcha/painter/OutlineEffect.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/captcha/painter/RenderedFont.java b/src/main/java/net/elytrium/limbofilter/captcha/painter/RenderedFont.java
index 8c600d1..523e561 100644
--- a/src/main/java/net/elytrium/limbofilter/captcha/painter/RenderedFont.java
+++ b/src/main/java/net/elytrium/limbofilter/captcha/painter/RenderedFont.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/captcha/painter/RippleEffect.java b/src/main/java/net/elytrium/limbofilter/captcha/painter/RippleEffect.java
index 9f8b736..bf8fe4c 100644
--- a/src/main/java/net/elytrium/limbofilter/captcha/painter/RippleEffect.java
+++ b/src/main/java/net/elytrium/limbofilter/captcha/painter/RippleEffect.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/commands/CommandPermissionState.java b/src/main/java/net/elytrium/limbofilter/commands/CommandPermissionState.java
index fe777c4..338c7ed 100644
--- a/src/main/java/net/elytrium/limbofilter/commands/CommandPermissionState.java
+++ b/src/main/java/net/elytrium/limbofilter/commands/CommandPermissionState.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/commands/LimboFilterCommand.java b/src/main/java/net/elytrium/limbofilter/commands/LimboFilterCommand.java
index f77258c..1c693a5 100644
--- a/src/main/java/net/elytrium/limbofilter/commands/LimboFilterCommand.java
+++ b/src/main/java/net/elytrium/limbofilter/commands/LimboFilterCommand.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/commands/SendFilterCommand.java b/src/main/java/net/elytrium/limbofilter/commands/SendFilterCommand.java
index 4fa4e17..c1ad304 100644
--- a/src/main/java/net/elytrium/limbofilter/commands/SendFilterCommand.java
+++ b/src/main/java/net/elytrium/limbofilter/commands/SendFilterCommand.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/handler/BotFilterSessionHandler.java b/src/main/java/net/elytrium/limbofilter/handler/BotFilterSessionHandler.java
index 627c450..917af52 100644
--- a/src/main/java/net/elytrium/limbofilter/handler/BotFilterSessionHandler.java
+++ b/src/main/java/net/elytrium/limbofilter/handler/BotFilterSessionHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -19,8 +19,8 @@
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.Player;
-import com.velocitypowered.proxy.protocol.packet.ClientSettings;
-import com.velocitypowered.proxy.protocol.packet.PluginMessage;
+import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket;
+import com.velocitypowered.proxy.protocol.packet.PluginMessagePacket;
import com.velocitypowered.proxy.protocol.util.PluginMessageUtil;
import java.util.HashMap;
import java.util.Map;
@@ -191,9 +191,9 @@ public void onMove(double x, double y, double z) {
this.fallingCheckFailed("Non-valid X, Z or Velocity");
return;
}
- PreparedPacket expBuf = this.plugin.getPackets().getExperience(this.ticks);
- if (expBuf != null) {
- this.player.writePacketAndFlush(expBuf);
+ PreparedPacket experience = this.plugin.getPackets().getExperience(this.ticks);
+ if (experience != null) {
+ this.player.writePacketAndFlush(experience);
}
++this.ticks;
@@ -272,8 +272,8 @@ private boolean equalsCaptchaAnswer(String message) {
@Override
public void onGeneric(Object packet) {
- if (packet instanceof PluginMessage) {
- PluginMessage pluginMessage = (PluginMessage) packet;
+ if (packet instanceof PluginMessagePacket) {
+ PluginMessagePacket pluginMessage = (PluginMessagePacket) packet;
if (PluginMessageUtil.isMcBrand(pluginMessage) && !this.checkedByBrand) {
String brand = PluginMessageUtil.readBrandMessage(pluginMessage.content());
LimboFilter.getLogger().info("{} has client brand {}", this.proxyPlayer, brand);
@@ -281,7 +281,7 @@ public void onGeneric(Object packet) {
this.checkedByBrand = true;
}
}
- } else if (packet instanceof ClientSettings) {
+ } else if (packet instanceof ClientSettingsPacket) {
if (Settings.IMP.MAIN.CHECK_CLIENT_SETTINGS && !this.checkedBySettings) {
this.checkedBySettings = true;
}
@@ -366,9 +366,15 @@ private boolean checkPing() {
}
private void changeStateToCaptcha() {
+ if (this.state != CheckState.ONLY_CAPTCHA && this.version.noLessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
+ this.player.writePacket(this.plugin.getPackets().getFallingCheckChunkUnload());
+ }
+
this.state = CheckState.ONLY_CAPTCHA;
this.server.respawnPlayer(this.proxyPlayer);
- this.player.writePacketAndFlush(this.plugin.getPackets().getNoAbilities());
+ if (Settings.IMP.MAIN.DISABLE_FALLING_ON_CAPTCHA) {
+ this.player.writePacketAndFlush(this.plugin.getPackets().getNoAbilities());
+ }
this.waitingTeleportId = this.validTeleportId;
if (this.captchaAnswer == null) {
diff --git a/src/main/java/net/elytrium/limbofilter/listener/FilterListener.java b/src/main/java/net/elytrium/limbofilter/listener/FilterListener.java
index 8296e73..bc63279 100644
--- a/src/main/java/net/elytrium/limbofilter/listener/FilterListener.java
+++ b/src/main/java/net/elytrium/limbofilter/listener/FilterListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/listener/TcpListener.java b/src/main/java/net/elytrium/limbofilter/listener/TcpListener.java
index cd0c832..dedc715 100644
--- a/src/main/java/net/elytrium/limbofilter/listener/TcpListener.java
+++ b/src/main/java/net/elytrium/limbofilter/listener/TcpListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/java/net/elytrium/limbofilter/protocol/data/EntityMetadata.java b/src/main/java/net/elytrium/limbofilter/protocol/data/EntityMetadata.java
index 16b24f6..66fead2 100644
--- a/src/main/java/net/elytrium/limbofilter/protocol/data/EntityMetadata.java
+++ b/src/main/java/net/elytrium/limbofilter/protocol/data/EntityMetadata.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -22,6 +22,7 @@
import io.netty.buffer.ByteBuf;
import java.util.Map;
import net.elytrium.limboapi.api.material.VirtualItem;
+import net.elytrium.limboapi.api.protocol.item.ItemComponentMap;
import net.kyori.adventure.nbt.CompoundBinaryTag;
public class EntityMetadata {
@@ -40,25 +41,52 @@ public static class SlotEntry implements Entry {
private final int count;
private final int data;
private final CompoundBinaryTag nbt;
+ private final ItemComponentMap map;
- public SlotEntry(boolean present, VirtualItem item, int count, int data, CompoundBinaryTag nbt) {
+ public SlotEntry(boolean present, VirtualItem item, int count, int data, CompoundBinaryTag nbt, ItemComponentMap map) {
this.present = present;
this.item = item;
this.count = count;
this.data = data;
this.nbt = nbt;
+ this.map = map;
}
- public SlotEntry(VirtualItem item, int count, int data, CompoundBinaryTag nbt) {
- this(true, item, count, data, nbt);
+ public SlotEntry(VirtualItem item, int count, int data, CompoundBinaryTag nbt, ItemComponentMap map) {
+ this(true, item, count, data, nbt, map);
}
public SlotEntry() {
- this(false, null, 0, 0, null);
+ this(false, null, 0, 0, null, null);
}
@Override
public void encode(ByteBuf buf, ProtocolVersion protocolVersion) {
+ if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_20_5) >= 0) {
+ this.encodeModern(buf, protocolVersion);
+ } else {
+ this.encodeLegacy(buf, protocolVersion);
+ }
+ }
+
+ public void encodeModern(ByteBuf buf, ProtocolVersion protocolVersion) {
+ int id = this.item.getID(protocolVersion);
+ if (id == 0) {
+ ProtocolUtils.writeVarInt(buf, 0);
+ } else {
+ ProtocolUtils.writeVarInt(buf, this.count);
+ ProtocolUtils.writeVarInt(buf, id);
+
+ if (this.map != null) {
+ this.map.write(protocolVersion, buf);
+ } else {
+ ProtocolUtils.writeVarInt(buf, 0);
+ ProtocolUtils.writeVarInt(buf, 0);
+ }
+ }
+ }
+
+ public void encodeLegacy(ByteBuf buf, ProtocolVersion protocolVersion) {
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_13_2) >= 0) {
buf.writeBoolean(this.present);
}
diff --git a/src/main/java/net/elytrium/limbofilter/protocol/data/ItemFrame.java b/src/main/java/net/elytrium/limbofilter/protocol/data/ItemFrame.java
index 1bfc4c9..9cd0fb8 100644
--- a/src/main/java/net/elytrium/limbofilter/protocol/data/ItemFrame.java
+++ b/src/main/java/net/elytrium/limbofilter/protocol/data/ItemFrame.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -43,8 +43,20 @@ public static int getID(ProtocolVersion protocolVersion) {
return 46;
} else if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_20_2) <= 0) {
return 56;
- } else {
+ } else if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_20_3) <= 0) {
return 57;
+ } else if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_21) <= 0) {
+ return 60;
+ } else if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_21_2) <= 0) {
+ return 71;
+ } else if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_21_5) <= 0) {
+ return 70;
+ } else if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_21_7) <= 0) {
+ return 71;
+ } else if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_21_9) <= 0) {
+ return 72;
+ } else {
+ return 73;
}
}
@@ -59,20 +71,23 @@ public static byte getMetadataIndex(ProtocolVersion protocolVersion) {
return 6;
} else if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_16_4) <= 0) {
return 7;
- } else {
+ } else if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_21_5) <= 0) {
return 8;
+ } else {
+ return 9;
}
}
public static EntityMetadata createMapMetadata(LimboFactory limboFactory, ProtocolVersion protocolVersion, int mapId) {
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_12_2) <= 0) {
return new EntityMetadata(Map.of(
- getMetadataIndex(protocolVersion), new EntityMetadata.SlotEntry(limboFactory.getItem(Item.FILLED_MAP), 1, mapId, null)
+ getMetadataIndex(protocolVersion), new EntityMetadata.SlotEntry(limboFactory.getItem(Item.FILLED_MAP), 1, mapId, null, null)
));
} else {
return new EntityMetadata(Map.of(
getMetadataIndex(protocolVersion), new EntityMetadata.SlotEntry(limboFactory.getItem(Item.FILLED_MAP), 1, 0,
- CompoundBinaryTag.builder().put("map", IntBinaryTag.intBinaryTag(mapId)).build())
+ CompoundBinaryTag.builder().put("map", IntBinaryTag.intBinaryTag(mapId)).build(),
+ limboFactory.createItemComponentMap().add(ProtocolVersion.MINECRAFT_1_20_5, "minecraft:map_id", mapId))
));
}
}
diff --git a/src/main/java/net/elytrium/limbofilter/protocol/data/PackedVector.java b/src/main/java/net/elytrium/limbofilter/protocol/data/PackedVector.java
new file mode 100644
index 0000000..c44029c
--- /dev/null
+++ b/src/main/java/net/elytrium/limbofilter/protocol/data/PackedVector.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 - 2025 Elytrium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package net.elytrium.limbofilter.protocol.data;
+
+import com.velocitypowered.proxy.protocol.ProtocolUtils;
+import io.netty.buffer.ByteBuf;
+
+public record PackedVector(double x, double y, double z) {
+
+ public static PackedVector read(ByteBuf buffer) {
+ int first = buffer.readUnsignedByte();
+ if (first == 0) {
+ return new PackedVector(0, 0, 0);
+ } else {
+ int second = buffer.readUnsignedByte();
+ long third = buffer.readUnsignedInt();
+ long result = third << 16 | (long) (second << 8) | (long) first;
+ long multiplier = first & 3;
+ if ((first & 4) == 4) {
+ multiplier |= ((long) ProtocolUtils.readVarInt(buffer) & 4094967295L) << 2L;
+ }
+
+ return new PackedVector(unpack(result >> 3) * (double) multiplier,
+ unpack(result >> 18) * (double) multiplier,
+ unpack(result >> 33) * (double) multiplier);
+ }
+ }
+
+ public static void write(ByteBuf buffer, double x, double y, double z) {
+ double sx = sanitize(x);
+ double sy = sanitize(y);
+ double sz = sanitize(z);
+ double maxValue = Math.max(Math.abs(sx), Math.max(Math.abs(sy), Math.abs(sz)));
+ if (maxValue < 3.051944088384301E-5) {
+ buffer.writeByte(0);
+ return;
+ }
+
+ long result = (long) maxValue;
+ long max = maxValue > (double) result ? result + 1L : result;
+
+ boolean continuation = (max & 3) != max;
+ long px = pack(sx / (double) max) << 3;
+ long py = pack(sy / (double) max) << 18;
+ long pz = pack(sz / (double) max) << 33;
+ long packed = (continuation ? max & 3 | 4 : max) | px | py | pz;
+ buffer.writeByte((byte) ((int) packed));
+ buffer.writeByte((byte) ((int) (packed >> 8)));
+ buffer.writeInt((int) (packed >> 16));
+ if (continuation) {
+ ProtocolUtils.writeVarInt(buffer, (int) (max >> 2));
+ }
+ }
+
+ private static long pack(double value) {
+ return Math.round((value * 0.5 + 0.5) * 32766.0);
+ }
+
+ private static double unpack(long value) {
+ return Math.min((double) (value & (long) 32767), 32766.0) * 2.0 / 32766.0 - 1.0;
+ }
+
+ private static double sanitize(double value) {
+ if (Double.isNaN(value)) {
+ return 0.0;
+ } else {
+ return value < -1.7179869183E10 ? -1.7179869183E10 : Math.min(value, 1.7179869183E10);
+ }
+ }
+}
diff --git a/src/main/java/net/elytrium/limbofilter/protocol/packets/Interact.java b/src/main/java/net/elytrium/limbofilter/protocol/packets/Interact.java
index f57e1dd..c29b71d 100644
--- a/src/main/java/net/elytrium/limbofilter/protocol/packets/Interact.java
+++ b/src/main/java/net/elytrium/limbofilter/protocol/packets/Interact.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -22,6 +22,7 @@
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import io.netty.buffer.ByteBuf;
+import net.elytrium.limbofilter.protocol.data.PackedVector;
public class Interact implements MinecraftPacket {
@@ -35,7 +36,15 @@ public class Interact implements MinecraftPacket {
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
- if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_7_6) > 0) {
+ if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_26_1) >= 0) {
+ this.entityId = ProtocolUtils.readVarInt(buf);
+ this.hand = ProtocolUtils.readVarInt(buf);
+ PackedVector target = PackedVector.read(buf);
+ this.targetX = (float) target.x();
+ this.targetY = (float) target.y();
+ this.targetZ = (float) target.z();
+ this.sneaking = buf.readBoolean();
+ } else if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_7_6) > 0) {
this.entityId = ProtocolUtils.readVarInt(buf);
this.type = ProtocolUtils.readVarInt(buf);
if (this.type == 2) {
diff --git a/src/main/java/net/elytrium/limbofilter/protocol/packets/SetEntityMetadata.java b/src/main/java/net/elytrium/limbofilter/protocol/packets/SetEntityMetadata.java
index 6bef892..75fd1bb 100644
--- a/src/main/java/net/elytrium/limbofilter/protocol/packets/SetEntityMetadata.java
+++ b/src/main/java/net/elytrium/limbofilter/protocol/packets/SetEntityMetadata.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -39,10 +39,6 @@ public SetEntityMetadata(int entityId, EntityMetadata metadata) {
this(entityId, protocolVersion -> metadata);
}
- public SetEntityMetadata() {
- throw new IllegalStateException();
- }
-
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
throw new IllegalStateException();
diff --git a/src/main/java/net/elytrium/limbofilter/protocol/packets/SpawnEntity.java b/src/main/java/net/elytrium/limbofilter/protocol/packets/SpawnEntity.java
index 0f95b77..378bdac 100644
--- a/src/main/java/net/elytrium/limbofilter/protocol/packets/SpawnEntity.java
+++ b/src/main/java/net/elytrium/limbofilter/protocol/packets/SpawnEntity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -24,6 +24,7 @@
import io.netty.buffer.ByteBuf;
import java.util.UUID;
import java.util.function.Function;
+import net.elytrium.limbofilter.protocol.data.PackedVector;
public class SpawnEntity implements MinecraftPacket {
@@ -58,10 +59,6 @@ public SpawnEntity(int id, UUID uuid, Function type, d
this.velocityZ = velocityZ;
}
- public SpawnEntity() {
- throw new IllegalStateException();
- }
-
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
throw new IllegalStateException();
@@ -80,6 +77,10 @@ public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersi
buf.writeDouble(this.positionX);
buf.writeDouble(this.positionY);
buf.writeDouble(this.positionZ);
+
+ if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_21_9)) {
+ PackedVector.write(buf, this.velocityX, this.velocityY, this.velocityZ);
+ }
} else {
buf.writeByte(this.type.apply(protocolVersion));
buf.writeInt((int) (this.positionX * 32.0));
@@ -94,9 +95,12 @@ public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersi
} else {
buf.writeInt(this.data);
}
- buf.writeShort((int) (this.velocityX * 8000.0F));
- buf.writeShort((int) (this.velocityY * 8000.0F));
- buf.writeShort((int) (this.velocityZ * 8000.0F));
+
+ if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_21_9)) {
+ buf.writeShort((int) (this.velocityX * 8000.0F));
+ buf.writeShort((int) (this.velocityY * 8000.0F));
+ buf.writeShort((int) (this.velocityZ * 8000.0F));
+ }
}
@Override
diff --git a/src/main/java/net/elytrium/limbofilter/stats/Statistics.java b/src/main/java/net/elytrium/limbofilter/stats/Statistics.java
index 0090368..475012f 100644
--- a/src/main/java/net/elytrium/limbofilter/stats/Statistics.java
+++ b/src/main/java/net/elytrium/limbofilter/stats/Statistics.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
diff --git a/src/main/templates/net/elytrium/limbofilter/BuildConstants.java b/src/main/templates/net/elytrium/limbofilter/BuildConstants.java
index f86eaf6..023e80d 100644
--- a/src/main/templates/net/elytrium/limbofilter/BuildConstants.java
+++ b/src/main/templates/net/elytrium/limbofilter/BuildConstants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 - 2023 Elytrium
+ * Copyright (C) 2021 - 2025 Elytrium
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by