9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-25 01:49:30 +00:00

Merge pull request #96 from jhqwqmc/dev

feat(network): 优化数据包处理逻辑
This commit is contained in:
XiaoMoMi
2025-04-09 01:16:48 +08:00
committed by GitHub
11 changed files with 171 additions and 346 deletions

View File

@@ -117,14 +117,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
}
private PacketIds setupPacketIds() {
if (VersionHelper.isVersionNewerThan1_21()) {
return new PacketIds1_21();
} else if (VersionHelper.isVersionNewerThan1_20_5()) {
if (VersionHelper.isVersionNewerThan1_20_5()) {
return new PacketIds1_20_5();
} else if (VersionHelper.isVersionNewerThan1_20_3()) {
return new PacketIds1_20_3();
} else if (VersionHelper.isVersionNewerThan1_20_2()) {
return new PacketIds1_20_2();
} else {
return new PacketIds1_20();
}

View File

@@ -1325,6 +1325,8 @@ public class PacketConsumers {
}
} else if (type == Reflections.instance$EntityType$BLOCK_DISPLAY$registryId) {
user.entityView().put(id, Reflections.instance$EntityType$BLOCK_DISPLAY);
} else if (type == Reflections.instance$EntityType$TEXT_DISPLAY$registryId) {
user.entityView().put(id, Reflections.instance$EntityType$TEXT_DISPLAY);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundAddEntityPacket", e);
@@ -1683,43 +1685,108 @@ public class PacketConsumers {
}
};
@SuppressWarnings("unchecked")
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> SET_ENTITY_DATA = (user, event) -> {
try {
FriendlyByteBuf buf = event.getBuffer();
int id = buf.readVarInt();
Object entityType = user.entityView().get(id);
boolean isChanged = false;
List<Object> packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf);
if (entityType == Reflections.instance$EntityType$BLOCK_DISPLAY) {
boolean isChanged = false;
List<Object> packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf);
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId != EntityDataUtils.BLOCK_STATE_DATA_ID) {
continue;
if (entityDataId == EntityDataUtils.BLOCK_STATE_DATA_ID) {
Object blockState = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
int stateId = BlockStateUtils.blockStateToId(blockState);
int newStateId;
if (!user.clientModEnabled()) {
newStateId = remap(stateId);
} else {
newStateId = remapMOD(stateId);
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, BlockStateUtils.idToBlockState(newStateId)
));
isChanged = true;
} else if (entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) {
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isPresent()) {
Object textComponent = optionalTextComponent.get();
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, String> tokens = CraftEngine.instance().imageManager().matchTags(json);
if (!tokens.isEmpty()) {
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, String> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(AdventureHelper.miniMessage().deserialize(token.getValue())));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component))
));
isChanged = true;
}
}
}
Object blockState = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
int stateId = BlockStateUtils.blockStateToId(blockState);
int newStateId;
if (!user.clientModEnabled()) {
newStateId = remap(stateId);
} else {
newStateId = remapMOD(stateId);
}
} else if (entityType == Reflections.instance$EntityType$TEXT_DISPLAY) {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId == EntityDataUtils.TEXT_DATA_ID) {
Object textComponent = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (textComponent == Reflections.instance$Component$empty) break;
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, String> tokens = CraftEngine.instance().imageManager().matchTags(json);
if (!tokens.isEmpty()) {
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, String> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(AdventureHelper.miniMessage().deserialize(token.getValue())));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, ComponentUtils.adventureToMinecraft(component)
));
isChanged = true;
break;
}
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, BlockStateUtils.idToBlockState(newStateId)
));
isChanged = true;
break;
}
if (isChanged) {
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeVarInt(id);
FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf);
} else {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) {
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isPresent()) {
Object textComponent = optionalTextComponent.get();
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, String> tokens = CraftEngine.instance().imageManager().matchTags(json);
if (!tokens.isEmpty()) {
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, String> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(AdventureHelper.miniMessage().deserialize(token.getValue())));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component))
));
isChanged = true;
break;
}
}
}
}
}
if (isChanged) {
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeVarInt(id);
FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e);
}

View File

@@ -1,26 +1,35 @@
package net.momirealms.craftengine.bukkit.plugin.network.impl;
import com.google.gson.JsonElement;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.VersionHelper;
import java.util.HashMap;
import java.util.Map;
public class PacketIdFinder {
private static final Map<String, Map<String, Integer>> gamePacketIds = new HashMap<>();
private static final Map<String, Map<String, Integer>> gamePacketIdsByName = new HashMap<>();
private static final Map<String, Map<Class<?>, Integer>> gamePacketIdsByClazz = new HashMap<>();
static {
try {
Object packetReport = Reflections.constructor$PacketReport.newInstance((Object) null);
JsonElement jsonElement = (JsonElement) Reflections.method$PacketReport$serializePackets.invoke(packetReport);
var play = jsonElement.getAsJsonObject().get("play");
for (var entry : play.getAsJsonObject().entrySet()) {
Map<String, Integer> ids = new HashMap<>();
gamePacketIds.put(entry.getKey(), ids);
for (var entry2 : entry.getValue().getAsJsonObject().entrySet()) {
ids.put(entry2.getKey(), entry2.getValue().getAsJsonObject().get("protocol_id").getAsInt());
if (VersionHelper.isVersionNewerThan1_21()) {
Object packetReport = Reflections.constructor$PacketReport.newInstance((Object) null);
JsonElement jsonElement = (JsonElement) Reflections.method$PacketReport$serializePackets.invoke(packetReport);
var play = jsonElement.getAsJsonObject().get("play");
for (var entry : play.getAsJsonObject().entrySet()) {
Map<String, Integer> ids = new HashMap<>();
gamePacketIdsByName.put(entry.getKey(), ids);
for (var entry2 : entry.getValue().getAsJsonObject().entrySet()) {
ids.put(entry2.getKey(), entry2.getValue().getAsJsonObject().get("protocol_id").getAsInt());
}
}
} else if (VersionHelper.isVersionNewerThan1_20_5()) {
gamePacketIdsByName.putAll(FastNMS.INSTANCE.method$getGamePacketIdsByName());
} else {
gamePacketIdsByClazz.putAll(FastNMS.INSTANCE.method$getGamePacketIdsByClazz());
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to get packets", e);
@@ -28,6 +37,10 @@ public class PacketIdFinder {
}
public static int clientboundByName(String packetName) {
return gamePacketIds.get("clientbound").getOrDefault(packetName, -1);
return gamePacketIdsByName.get("clientbound").getOrDefault(packetName, -1);
}
public static int clientboundByClazz(Class<?> clazz) {
return gamePacketIdsByClazz.get("clientbound").getOrDefault(clazz, -1);
}
}

View File

@@ -1,87 +1,88 @@
package net.momirealms.craftengine.bukkit.plugin.network.impl;
import net.momirealms.craftengine.bukkit.plugin.network.PacketIds;
import net.momirealms.craftengine.bukkit.util.Reflections;
public class PacketIds1_20 implements PacketIds {
@Override
public int clientboundBlockUpdatePacket() {
return 10;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundBlockUpdatePacket);
}
@Override
public int clientboundSectionBlocksUpdatePacket() {
return 67;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSectionBlocksUpdatePacket);
}
@Override
public int clientboundLevelParticlesPacket() {
return 38;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundLevelParticlesPacket);
}
@Override
public int clientboundLevelEventPacket() {
return 37;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundLevelEventPacket);
}
@Override
public int clientboundAddEntityPacket() {
return 1;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundAddEntityPacket);
}
@Override
public int clientboundOpenScreenPacket() {
return 48;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundOpenScreenPacket);
}
@Override
public int clientboundSoundPacket() {
return 98;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSoundPacket);
}
@Override
public int clientboundRemoveEntitiesPacket() {
return 62;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundRemoveEntitiesPacket);
}
@Override
public int clientboundSetEntityDataPacket() {
return 82;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetEntityDataPacket);
}
@Override
public int clientboundSetTitleTextPacket() {
return 95;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetTitleTextPacket);
}
@Override
public int clientboundSetSubtitleTextPacket() {
return 93;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetSubtitleTextPacket);
}
@Override
public int clientboundSetActionBarTextPacket() {
return 70;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetActionBarTextPacket);
}
@Override
public int clientboundBossEventPacket() {
return 11;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundBossEventPacket);
}
@Override
public int clientboundSystemChatPacket() {
return 100;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSystemChatPacket);
}
@Override
public int clientboundTabListPacket() {
return 101;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundTabListPacket);
}
@Override
public int clientboundSetPlayerTeamPacket() {
return 90;
return PacketIdFinder.clientboundByClazz(Reflections.clazz$ClientboundSetPlayerTeamPacket);
}
@Override

View File

@@ -1,91 +0,0 @@
package net.momirealms.craftengine.bukkit.plugin.network.impl;
import net.momirealms.craftengine.bukkit.plugin.network.PacketIds;
public class PacketIds1_20_2 implements PacketIds {
@Override
public int clientboundBlockUpdatePacket() {
return 9;
}
@Override
public int clientboundSectionBlocksUpdatePacket() {
return 69;
}
@Override
public int clientboundLevelParticlesPacket() {
return 39;
}
@Override
public int clientboundLevelEventPacket() {
return 38;
}
@Override
public int clientboundAddEntityPacket() {
return 1;
}
@Override
public int clientboundOpenScreenPacket() {
return 49;
}
@Override
public int clientboundSoundPacket() {
return 100;
}
@Override
public int clientboundRemoveEntitiesPacket() {
return 64;
}
@Override
public int clientboundSetEntityDataPacket() {
return 84;
}
@Override
public int clientboundSetTitleTextPacket() {
return 97;
}
@Override
public int clientboundSetSubtitleTextPacket() {
return 95;
}
@Override
public int clientboundSetActionBarTextPacket() {
return 72;
}
@Override
public int clientboundBossEventPacket() {
return 10;
}
@Override
public int clientboundSystemChatPacket() {
return 103;
}
@Override
public int clientboundTabListPacket() {
return 104;
}
@Override
public int clientboundSetPlayerTeamPacket() {
return 92;
}
@Override
public int clientboundSetObjectivePacket() {
return 90;
}
}

View File

@@ -1,91 +0,0 @@
package net.momirealms.craftengine.bukkit.plugin.network.impl;
import net.momirealms.craftengine.bukkit.plugin.network.PacketIds;
public class PacketIds1_20_3 implements PacketIds {
@Override
public int clientboundBlockUpdatePacket() {
return 9;
}
@Override
public int clientboundSectionBlocksUpdatePacket() {
return 71;
}
@Override
public int clientboundLevelParticlesPacket() {
return 39;
}
@Override
public int clientboundLevelEventPacket() {
return 38;
}
@Override
public int clientboundAddEntityPacket() {
return 1;
}
@Override
public int clientboundOpenScreenPacket() {
return 49;
}
@Override
public int clientboundSoundPacket() {
return 102;
}
@Override
public int clientboundRemoveEntitiesPacket() {
return 64;
}
@Override
public int clientboundSetEntityDataPacket() {
return 86;
}
@Override
public int clientboundSetTitleTextPacket() {
return 99;
}
@Override
public int clientboundSetSubtitleTextPacket() {
return 97;
}
@Override
public int clientboundSetActionBarTextPacket() {
return 74;
}
@Override
public int clientboundBossEventPacket() {
return 10;
}
@Override
public int clientboundSystemChatPacket() {
return 105;
}
@Override
public int clientboundTabListPacket() {
return 106;
}
@Override
public int clientboundSetPlayerTeamPacket() {
return 94;
}
@Override
public int clientboundSetObjectivePacket() {
return 92;
}
}

View File

@@ -6,82 +6,82 @@ public class PacketIds1_20_5 implements PacketIds {
@Override
public int clientboundBlockUpdatePacket() {
return 9;
return PacketIdFinder.clientboundByName("minecraft:block_update");
}
@Override
public int clientboundSectionBlocksUpdatePacket() {
return 73;
return PacketIdFinder.clientboundByName("minecraft:section_blocks_update");
}
@Override
public int clientboundLevelParticlesPacket() {
return 41;
return PacketIdFinder.clientboundByName("minecraft:level_particles");
}
@Override
public int clientboundLevelEventPacket() {
return 40;
return PacketIdFinder.clientboundByName("minecraft:level_event");
}
@Override
public int clientboundAddEntityPacket() {
return 1;
return PacketIdFinder.clientboundByName("minecraft:add_entity");
}
@Override
public int clientboundOpenScreenPacket() {
return 51;
return PacketIdFinder.clientboundByName("minecraft:open_screen");
}
@Override
public int clientboundSoundPacket() {
return 104;
return PacketIdFinder.clientboundByName("minecraft:sound");
}
@Override
public int clientboundRemoveEntitiesPacket() {
return 66;
return PacketIdFinder.clientboundByName("minecraft:remove_entities");
}
@Override
public int clientboundSetEntityDataPacket() {
return 88;
return PacketIdFinder.clientboundByName("minecraft:set_entity_data");
}
@Override
public int clientboundSetTitleTextPacket() {
return 101;
return PacketIdFinder.clientboundByName("minecraft:set_title_text");
}
@Override
public int clientboundSetSubtitleTextPacket() {
return 99;
return PacketIdFinder.clientboundByName("minecraft:set_subtitle_text");
}
@Override
public int clientboundSetActionBarTextPacket() {
return 76;
return PacketIdFinder.clientboundByName("minecraft:set_action_bar_text");
}
@Override
public int clientboundBossEventPacket() {
return 10;
return PacketIdFinder.clientboundByName("minecraft:boss_event");
}
@Override
public int clientboundSystemChatPacket() {
return 108;
return PacketIdFinder.clientboundByName("minecraft:system_chat");
}
@Override
public int clientboundTabListPacket() {
return 109;
return PacketIdFinder.clientboundByName("minecraft:tab_list");
}
@Override
public int clientboundSetPlayerTeamPacket() {
return 96;
return PacketIdFinder.clientboundByName("minecraft:set_player_team");
}
@Override

View File

@@ -1,91 +0,0 @@
package net.momirealms.craftengine.bukkit.plugin.network.impl;
import net.momirealms.craftengine.bukkit.plugin.network.PacketIds;
public class PacketIds1_21 implements PacketIds {
@Override
public int clientboundBlockUpdatePacket() {
return PacketIdFinder.clientboundByName("minecraft:block_update");
}
@Override
public int clientboundSectionBlocksUpdatePacket() {
return PacketIdFinder.clientboundByName("minecraft:section_blocks_update");
}
@Override
public int clientboundLevelParticlesPacket() {
return PacketIdFinder.clientboundByName("minecraft:level_particles");
}
@Override
public int clientboundLevelEventPacket() {
return PacketIdFinder.clientboundByName("minecraft:level_event");
}
@Override
public int clientboundAddEntityPacket() {
return PacketIdFinder.clientboundByName("minecraft:add_entity");
}
@Override
public int clientboundOpenScreenPacket() {
return PacketIdFinder.clientboundByName("minecraft:open_screen");
}
@Override
public int clientboundSoundPacket() {
return PacketIdFinder.clientboundByName("minecraft:sound");
}
@Override
public int clientboundRemoveEntitiesPacket() {
return PacketIdFinder.clientboundByName("minecraft:remove_entities");
}
@Override
public int clientboundSetEntityDataPacket() {
return PacketIdFinder.clientboundByName("minecraft:set_entity_data");
}
@Override
public int clientboundSetTitleTextPacket() {
return PacketIdFinder.clientboundByName("minecraft:set_title_text");
}
@Override
public int clientboundSetSubtitleTextPacket() {
return PacketIdFinder.clientboundByName("minecraft:set_subtitle_text");
}
@Override
public int clientboundSetActionBarTextPacket() {
return PacketIdFinder.clientboundByName("minecraft:set_action_bar_text");
}
@Override
public int clientboundBossEventPacket() {
return PacketIdFinder.clientboundByName("minecraft:boss_event");
}
@Override
public int clientboundSystemChatPacket() {
return PacketIdFinder.clientboundByName("minecraft:system_chat");
}
@Override
public int clientboundTabListPacket() {
return PacketIdFinder.clientboundByName("minecraft:tab_list");
}
@Override
public int clientboundSetPlayerTeamPacket() {
return PacketIdFinder.clientboundByName("minecraft:set_player_team");
}
@Override
public int clientboundSetObjectivePacket() {
return PacketIdFinder.clientboundByName("minecraft:set_objective");
}
}

View File

@@ -12,6 +12,8 @@ public class EntityDataUtils {
private static final int LEFT_ALIGNMENT = 0x08; // 8
private static final int RIGHT_ALIGNMENT = 0x10; // 16
public static final int BLOCK_STATE_DATA_ID = VersionHelper.isVersionNewerThan1_20_2() ? 23 : 22;
public static final int TEXT_DATA_ID = VersionHelper.isVersionNewerThan1_20_2() ? 23 : 22;
public static final int CUSTOM_NAME_DATA_ID = 2;
public static byte encodeTextDisplayMask(boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackground, int alignment) {
int bitMask = 0;

View File

@@ -6270,14 +6270,35 @@ public class Reflections {
);
public static final int instance$EntityType$BLOCK_DISPLAY$registryId;
public static final int instance$EntityType$TEXT_DISPLAY$registryId;
public static final int instance$EntityType$FALLING_BLOCK$registryId;
static {
try {
instance$EntityType$BLOCK_DISPLAY$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$BLOCK_DISPLAY);
instance$EntityType$TEXT_DISPLAY$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$TEXT_DISPLAY);
instance$EntityType$FALLING_BLOCK$registryId = (int) Reflections.method$Registry$getId.invoke(Reflections.instance$BuiltInRegistries$ENTITY_TYPE, instance$EntityType$FALLING_BLOCK);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static final Class<?> clazz$ClientboundSetTitleTextPacket = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundSetTitleTextPacket")
)
);
public static final Class<?> clazz$ClientboundSetSubtitleTextPacket = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundSetSubtitleTextPacket")
)
);
public static final Class<?> clazz$ClientboundTabListPacket = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundTabListPacket"),
BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayOutPlayerListHeaderFooter")
)
);
}

View File

@@ -51,7 +51,7 @@ byte_buddy_version=1.17.5
ahocorasick_version=0.6.3
snake_yaml_version=2.4
anti_grief_version=0.13
nms_helper_version=0.46
nms_helper_version=0.47
# Ignite Dependencies
mixinextras_version=0.4.1
mixin_version=0.15.2+mixin.0.8.7