9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2026-01-04 15:41:38 +00:00

添加advancement包替换

This commit is contained in:
XiaoMoMi
2025-07-11 22:51:47 +08:00
parent d3bbacbe84
commit aa4ef03255
21 changed files with 410 additions and 7 deletions

View File

@@ -9,8 +9,6 @@ import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
import java.util.Locale;
import static java.util.Objects.requireNonNull;
public class MMOItemsProvider implements ExternalItemProvider<ItemStack> {

View File

@@ -29,7 +29,6 @@ import net.momirealms.craftengine.core.plugin.logger.Debugger;
import net.momirealms.craftengine.core.util.*;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.event.HandlerList;
import org.bukkit.inventory.ItemStack;

View File

@@ -11,7 +11,6 @@ import net.momirealms.craftengine.core.item.recipe.RecipeTypes;
import net.momirealms.craftengine.core.item.recipe.input.CraftingInput;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.UniqueKey;
import org.bukkit.block.Crafter;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

View File

@@ -25,7 +25,6 @@ import net.momirealms.craftengine.core.item.recipe.RecipeTypes;
import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ReflectionUtils;
import net.momirealms.craftengine.core.util.UniqueKey;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.bukkit.inventory.ItemStack;

View File

@@ -176,6 +176,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
registerS2CByteBufPacketConsumer(PacketConsumers.ADD_RECIPE_BOOK, this.packetIds.clientboundRecipeBookAddPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.PLACE_GHOST_RECIPE, this.packetIds.clientboundPlaceGhostRecipePacket());
registerS2CByteBufPacketConsumer(PacketConsumers.UPDATE_RECIPES, this.packetIds.clientboundUpdateRecipesPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.UPDATE_ADVANCEMENTS, this.packetIds.clientboundUpdateAdvancementsPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.ADD_ENTITY, this.packetIds.clientboundAddEntityPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket());

View File

@@ -1,6 +1,7 @@
package net.momirealms.craftengine.bukkit.plugin.network;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Either;
import io.netty.buffer.ByteBuf;
@@ -34,6 +35,8 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityType
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.*;
import net.momirealms.craftengine.core.advancement.network.AdvancementHolder;
import net.momirealms.craftengine.core.advancement.network.AdvancementProgress;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.font.FontManager;
@@ -2534,4 +2537,37 @@ public class PacketConsumers {
CraftEngine.instance().logger().warn("Failed to handle ClientboundUpdateRecipesPacket", e);
}
};
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> UPDATE_ADVANCEMENTS = (user, event) -> {
try {
FriendlyByteBuf buf = event.getBuffer();
boolean reset = buf.readBoolean();
List<AdvancementHolder> added = buf.readCollection(ArrayList::new, byteBuf -> {
AdvancementHolder holder = AdvancementHolder.read(byteBuf);
holder.applyClientboundData((BukkitServerPlayer) user);
return holder;
});
Set<Key> removed = buf.readCollection(Sets::newLinkedHashSetWithExpectedSize, FriendlyByteBuf::readKey);
Map<Key, AdvancementProgress> progress = buf.readMap(FriendlyByteBuf::readKey, AdvancementProgress::read);
boolean showAdvancement = false;
if (VersionHelper.isOrAbove1_21_5()) {
showAdvancement = buf.readBoolean();
}
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeBoolean(reset);
buf.writeCollection(added, (byteBuf, advancementHolder) -> advancementHolder.write(byteBuf));
buf.writeCollection(removed, FriendlyByteBuf::writeKey);
buf.writeMap(progress, FriendlyByteBuf::writeKey, (byteBuf, advancementProgress) -> advancementProgress.write(byteBuf));
if (VersionHelper.isOrAbove1_21_5()) {
buf.writeBoolean(showAdvancement);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundUpdateAdvancementsPacket", e);
}
};
}

View File

@@ -58,6 +58,8 @@ public interface PacketIds {
int clientboundPlaceGhostRecipePacket();
int clientboundUpdateAdvancementsPacket();
int serverboundContainerClickPacket();
int serverboundSetCreativeModeSlotPacket();

View File

@@ -164,4 +164,9 @@ public class PacketIds1_20 implements PacketIds {
public int clientboundUpdateRecipesPacket() {
return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundUpdateRecipesPacket);
}
@Override
public int clientboundUpdateAdvancementsPacket() {
return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundUpdateAdvancementsPacket);
}
}

View File

@@ -149,6 +149,11 @@ public class PacketIds1_20_5 implements PacketIds {
return PacketIdFinder.clientboundByName("minecraft:update_recipes");
}
@Override
public int clientboundUpdateAdvancementsPacket() {
return PacketIdFinder.clientboundByName("minecraft:update_advancements");
}
@Override
public int serverboundContainerClickPacket() {
return PacketIdFinder.serverboundByName("minecraft:container_click");

View File

@@ -1580,4 +1580,11 @@ public final class NetworkReflections {
"network.protocol.game.ClientboundUpdateRecipesPacket"
)
);
public static final Class<?> clazz$ClientboundUpdateAdvancementsPacket = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"network.protocol.game.PacketPlayOutAdvancements",
"network.protocol.game.ClientboundUpdateAdvancementsPacket"
)
);
}

View File

@@ -12,7 +12,6 @@ import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.QuadFunction;
import net.momirealms.craftengine.core.util.UniqueKey;
import net.momirealms.craftengine.core.world.BlockHitResult;
import net.momirealms.craftengine.core.world.BlockPos;
import org.bukkit.block.data.BlockData;

View File

@@ -221,7 +221,7 @@ image:
intercept-packets:
system-chat: true
tab-list: true # Tab list header and footer
player-info: true # User list in tab
player-info: true # Player list in tab
set-score: true
actionbar: true
title: true
@@ -233,6 +233,7 @@ image:
armor-stand: true # Legacy Holograms
text-display: true # Modern Holograms
item: true
advancement: true
# Defines Unicode characters used for <shift:xxx> positioning
# - Must match the font defined in resource packs
# - Do NOT modify unless you understand text rendering mechanics

View File

@@ -0,0 +1,23 @@
package net.momirealms.craftengine.core.advancement;
public enum AdvancementType {
TASK("task"),
CHALLENGE("challenge"),
GOAL("goal"),;
private final String id;
AdvancementType(String id) {
this.id = id;
}
public String id() {
return id;
}
public static final AdvancementType[] VALUES = values();
public static AdvancementType byId(int id) {
return VALUES[id];
}
}

View File

@@ -0,0 +1,67 @@
package net.momirealms.craftengine.core.advancement.network;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.jetbrains.annotations.ApiStatus;
import java.util.Map;
import java.util.Optional;
public class Advancement {
private final Optional<Key> parent;
private final Optional<AdvancementDisplay> displayInfo;
// 1.20-1.20.1
private final Map<String, Void> criteria;
private final AdvancementRequirements requirements;
private final boolean sendsTelemetryEvent;
public Advancement(Optional<Key> parent, Optional<AdvancementDisplay> displayInfo, AdvancementRequirements requirements, boolean sendsTelemetryEvent) {
this.criteria = null;
this.displayInfo = displayInfo;
this.parent = parent;
this.requirements = requirements;
this.sendsTelemetryEvent = sendsTelemetryEvent;
}
@ApiStatus.Obsolete
public Advancement(Optional<Key> parent, Optional<AdvancementDisplay> displayInfo, Map<String, Void> criteria, AdvancementRequirements requirements, boolean sendsTelemetryEvent) {
this.criteria = criteria;
this.displayInfo = displayInfo;
this.parent = parent;
this.requirements = requirements;
this.sendsTelemetryEvent = sendsTelemetryEvent;
}
public static Advancement read(FriendlyByteBuf buf) {
Optional<Key> parent = buf.readOptional(FriendlyByteBuf::readKey);
Optional<AdvancementDisplay> displayInfo = buf.readOptional(byteBuf -> AdvancementDisplay.read(buf));
if (VersionHelper.isOrAbove1_20_2()) {
AdvancementRequirements requirements = AdvancementRequirements.read(buf);
boolean sendsTelemetryEvent = buf.readBoolean();
return new Advancement(parent, displayInfo, requirements, sendsTelemetryEvent);
} else {
Map<String, Void> criteria = buf.readMap(FriendlyByteBuf::readUtf, (byteBuf -> null));
AdvancementRequirements requirements = AdvancementRequirements.read(buf);
boolean sendsTelemetryEvent = buf.readBoolean();
return new Advancement(parent, displayInfo, criteria, requirements, sendsTelemetryEvent);
}
}
public void write(FriendlyByteBuf buf) {
buf.writeOptional(this.parent, FriendlyByteBuf::writeKey);
buf.writeOptional(this.displayInfo, (byteBuf, info) -> info.write(buf));
if (!VersionHelper.isOrAbove1_20_2()) {
buf.writeMap(this.criteria, FriendlyByteBuf::writeUtf, ((byteBuf, unused) -> {}));
}
this.requirements.write(buf);
buf.writeBoolean(this.sendsTelemetryEvent);
}
public void applyClientboundData(Player player) {
this.displayInfo.ifPresent(info -> info.applyClientboundData(player));
}
}

View File

@@ -0,0 +1,115 @@
package net.momirealms.craftengine.core.advancement.network;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.core.advancement.AdvancementType;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.util.AdventureHelper;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.sparrow.nbt.Tag;
import java.util.Map;
import java.util.Optional;
public class AdvancementDisplay {
public static final int FLAG_BACKGROUND = 0b001;
public static final int FLAG_SHOW_TOAST = 0b010;
public static final int FLAG_HIDDEN = 0b100;
private Component title;
private Component description;
private Item<Object> icon;
private Optional<Key> background;
private final AdvancementType type;
private final boolean showToast;
private final boolean hidden;
private float x;
private float y;
public AdvancementDisplay(Component title,
Component description,
Item<Object> icon,
Optional<Key> background,
AdvancementType type,
boolean showToast,
boolean hidden,
float x,
float y) {
this.type = type;
this.showToast = showToast;
this.hidden = hidden;
this.background = background;
this.description = description;
this.icon = icon;
this.title = title;
this.x = x;
this.y = y;
}
public void applyClientboundData(Player player) {
this.icon = CraftEngine.instance().itemManager().s2c(this.icon, player);
}
public void write(FriendlyByteBuf buf) {
buf.writeComponent(this.title);
buf.writeComponent(this.description);
CraftEngine.instance().itemManager().encode(buf, this.icon);
buf.writeVarInt(this.type.ordinal());
int flags = 0;
if (this.background.isPresent()) {
flags |= FLAG_BACKGROUND;
}
if (this.showToast) {
flags |= FLAG_SHOW_TOAST;
}
if (this.hidden) {
flags |= FLAG_HIDDEN;
}
buf.writeInt(flags);
this.background.ifPresent(buf::writeKey);
buf.writeFloat(this.x);
buf.writeFloat(this.y);
}
public static AdvancementDisplay read(FriendlyByteBuf buf) {
Component title = readComponent(buf);
Component description = readComponent(buf);
Item<Object> icon = CraftEngine.instance().itemManager().decode(buf);
AdvancementType type = AdvancementType.byId(buf.readVarInt());
int flags = buf.readInt();
boolean hasBackground = (flags & 1) != 0;
Optional<Key> background = hasBackground ? Optional.of(buf.readKey()) : Optional.empty();
boolean showToast = (flags & 2) != 0;
boolean hidden = (flags & 4) != 0;
float x = buf.readFloat();
float y = buf.readFloat();
return new AdvancementDisplay(title, description, icon, background, type, showToast, hidden, x, y);
}
private static Component readComponent(FriendlyByteBuf buf) {
if (Config.interceptAdvancement()) {
if (VersionHelper.isOrAbove1_20_3()) {
Tag nbt = buf.readNbt(false);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString());
Component component = AdventureHelper.nbtToComponent(nbt);
if (!tokens.isEmpty()) {
component = AdventureHelper.replaceText(component, tokens);
}
return component;
} else {
String json = buf.readUtf();
Component component = AdventureHelper.jsonToComponent(json);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(json);
if (!tokens.isEmpty()) {
component = AdventureHelper.replaceText(component, tokens);
}
return component;
}
} else {
return buf.readComponent();
}
}
}

View File

@@ -0,0 +1,23 @@
package net.momirealms.craftengine.core.advancement.network;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import net.momirealms.craftengine.core.util.Key;
public record AdvancementHolder(Key id, Advancement advancement) {
public static AdvancementHolder read(FriendlyByteBuf buf) {
Key key = buf.readKey();
Advancement ad = Advancement.read(buf);
return new AdvancementHolder(key, ad);
}
public void write(FriendlyByteBuf buf) {
buf.writeKey(this.id);
this.advancement.write(buf);
}
public void applyClientboundData(Player player) {
this.advancement.applyClientboundData(player);
}
}

View File

@@ -0,0 +1,27 @@
package net.momirealms.craftengine.core.advancement.network;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import java.util.HashMap;
import java.util.Map;
public class AdvancementProgress {
private final Map<String, CriterionProgress> progress;
public AdvancementProgress(Map<String, CriterionProgress> progress) {
this.progress = progress;
}
public AdvancementProgress() {
this.progress = new HashMap<>();
}
public void write(FriendlyByteBuf buf) {
buf.writeMap(this.progress, FriendlyByteBuf::writeUtf, ((byteBuf, criterionProgress) -> criterionProgress.write(buf)));
}
public static AdvancementProgress read(FriendlyByteBuf buf) {
Map<String, CriterionProgress> progress = buf.readMap(FriendlyByteBuf::readUtf, CriterionProgress::read);
return new AdvancementProgress(progress);
}
}

View File

@@ -0,0 +1,23 @@
package net.momirealms.craftengine.core.advancement.network;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import java.util.ArrayList;
import java.util.List;
public class AdvancementRequirements {
public static final AdvancementRequirements EMPTY = new AdvancementRequirements(List.of());
private final List<List<String>> requirements;
public AdvancementRequirements(List<List<String>> requirements) {
this.requirements = requirements;
}
public void write(FriendlyByteBuf byteBuf) {
byteBuf.writeCollection(this.requirements, ((buf, strings) -> buf.writeCollection(strings, FriendlyByteBuf::writeUtf)));
}
public static AdvancementRequirements read(FriendlyByteBuf byteBuf) {
return new AdvancementRequirements(byteBuf.readCollection(ArrayList::new, buf -> buf.readCollection(ArrayList::new, FriendlyByteBuf::readUtf)));
}
}

View File

@@ -0,0 +1,42 @@
package net.momirealms.craftengine.core.advancement.network;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import org.jetbrains.annotations.Nullable;
import java.time.Instant;
public class CriterionProgress {
@Nullable
private Instant obtainedTimestamp;
public CriterionProgress() {
}
public CriterionProgress(@Nullable Instant obtainedTimestamp) {
this.obtainedTimestamp = obtainedTimestamp;
}
public boolean isDone() {
return this.obtainedTimestamp != null;
}
public void grant() {
this.obtainedTimestamp = Instant.now();
}
public void revoke() {
this.obtainedTimestamp = null;
}
public @Nullable Instant obtainedTimestamp() {
return obtainedTimestamp;
}
public void write(FriendlyByteBuf buf) {
buf.writeNullable(this.obtainedTimestamp, FriendlyByteBuf::writeInstant);
}
public static CriterionProgress read(FriendlyByteBuf buf) {
return new CriterionProgress(buf.readNullable(FriendlyByteBuf::readInstant));
}
}

View File

@@ -150,6 +150,7 @@ public class Config {
protected boolean image$intercept_packets$player_info;
protected boolean image$intercept_packets$set_score;
protected boolean image$intercept_packets$item;
protected boolean image$intercept_packets$advancement;
protected boolean item$client_bound_model;
protected boolean item$non_italic_tag;
@@ -393,6 +394,7 @@ public class Config {
image$intercept_packets$player_info = config.getBoolean("image.intercept-packets.player-info", true);
image$intercept_packets$set_score = config.getBoolean("image.intercept-packets.set-score", true);
image$intercept_packets$item = config.getBoolean("image.intercept-packets.item", true);
image$intercept_packets$advancement = config.getBoolean("image.intercept-packets.advancement", true);
// emoji
emoji$chat = config.getBoolean("emoji.chat", true);
@@ -742,6 +744,10 @@ public class Config {
return instance.image$intercept_packets$item;
}
public static boolean interceptAdvancement() {
return instance.image$intercept_packets$advancement;
}
public static boolean predictBreaking() {
return instance.block$predict_breaking;
}

View File

@@ -11,6 +11,7 @@ import io.netty.handler.codec.EncoderException;
import io.netty.util.ByteProcessor;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.core.registry.Registry;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.sparrow.nbt.NBT;
@@ -29,6 +30,7 @@ import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -47,6 +49,30 @@ public class FriendlyByteBuf extends ByteBuf {
return source;
}
public Component readComponent() {
if (VersionHelper.isOrAbove1_20_3()) {
return AdventureHelper.nbtToComponent(this.readNbt(false));
} else {
return AdventureHelper.jsonToComponent(this.readUtf());
}
}
public void writeComponent(Component component) {
if (VersionHelper.isOrAbove1_20_3()) {
this.writeNbt(AdventureHelper.componentToNbt(component), false);
} else {
this.writeUtf(AdventureHelper.componentToJson(component));
}
}
public Instant readInstant() {
return Instant.ofEpochMilli(this.readLong());
}
public void writeInstant(Instant instant) {
this.writeLong(instant.toEpochMilli());
}
public <T, C extends Collection<T>> C readCollection(IntFunction<C> collectionFactory, Reader<T> reader) {
int i = this.readVarInt();
C collection = collectionFactory.apply(i);