9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-29 11:59:11 +00:00

refactor(bukkit): 添加水下气泡

- 准备设计配置格式
This commit is contained in:
jhqwqmc
2025-05-10 13:51:03 +08:00
parent 0c5d23a260
commit 29b0c9c8c5
6 changed files with 69 additions and 38 deletions

View File

@@ -42,7 +42,6 @@ public class TestCommand extends BukkitCommandFeature<CommandSender> {
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.senderType(Player.class)
.required("forceUpdate", BooleanParser.booleanParser())
.required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() {
@Override
public @NonNull CompletableFuture<? extends @NonNull Iterable<? extends @NonNull Suggestion>> suggestionsFuture(@NonNull CommandContext<Object> context, @NonNull CommandInput input) {
@@ -55,18 +54,6 @@ public class TestCommand extends BukkitCommandFeature<CommandSender> {
.required("rotationLeft", StringParser.stringParser())
.handler(context -> {
Player player = context.sender();
if (context.get("forceUpdate")) {
net.momirealms.craftengine.core.entity.player.Player cePlayer = plugin().adapt(player);
Collection<Trident> tridents = player.getWorld().getEntitiesByClass(Trident.class);
List<Object> packets = new ArrayList<>();
for (Trident trident : tridents) {
int entityId = FastNMS.INSTANCE.method$Entity$getId(FastNMS.INSTANCE.method$CraftEntity$getHandle(trident));
player.sendMessage("COMMAND entityId: " + entityId);
packets.add(CustomTridentUtils.buildCustomTridentSetEntityDataPacket(cePlayer, entityId));
}
cePlayer.sendPackets(packets, true);
return;
}
NamespacedKey namespacedKey = context.get("id");
ItemStack item = new ItemStack(Material.TRIDENT);
item.editMeta((meta) -> {

View File

@@ -152,7 +152,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
registerNMSPacketConsumer(PacketConsumers.LOGIN_ACKNOWLEDGED, Reflections.clazz$ServerboundLoginAcknowledgedPacket);
registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, Reflections.clazz$ServerboundResourcePackPacket);
registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, Reflections.clazz$ClientboundEntityEventPacket);
registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_DATA, Reflections.clazz$ClientboundSetEntityDataPacket);
registerNMSPacketConsumer(PacketConsumers.MOVE_ENTITY_ALL, Reflections.clazz$ClientboundMoveEntityPacket$PosRot);
registerByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket());
registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
@@ -172,7 +171,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
registerByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket());
registerByteBufPacketConsumer(PacketConsumers.ADD_ENTITY_BYTEBUFFER, this.packetIds.clientboundAddEntityPacket());
registerByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket());
registerByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA_BYTEBUFFER, this.packetIds.clientboundSetEntityDataPacket());
registerByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket());
}
public static BukkitNetworkManager instance() {

View File

@@ -2008,10 +2008,20 @@ public class PacketConsumers {
};
@SuppressWarnings("unchecked")
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> SET_ENTITY_DATA_BYTEBUFFER = (user, event) -> {
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> SET_ENTITY_DATA = (user, event) -> {
try {
FriendlyByteBuf buf = event.getBuffer();
int id = buf.readVarInt();
if (user.tridentView().containsKey(id)) {
List<Object> packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf);
List<Object> newPackedItems = CustomTridentUtils.buildCustomTridentSetEntityDataPacket(user, packedItems, id);
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeVarInt(id);
FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(newPackedItems, buf);
return;
}
Object entityType = user.entityView().get(id);
if (entityType == Reflections.instance$EntityType$BLOCK_DISPLAY) {
boolean isChanged = false;
@@ -2331,17 +2341,6 @@ public class PacketConsumers {
}
};
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> SET_ENTITY_DATA = (user, event, packet) -> {
try {
int entityId = Reflections.field$clazz$ClientboundSetEntityDataPacket$id.getInt(packet);
if (user.tridentView().containsKey(entityId)) {
CustomTridentUtils.modifyCustomTridentSetEntityData(user, event, entityId);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e);
}
};
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> MOVE_ENTITY_ALL = (user, event, packet) -> {
try {
int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet);

View File

@@ -13,6 +13,7 @@ import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MCUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Trident;
@@ -39,6 +40,8 @@ public class CustomTridentUtils {
public static void handleCustomTrident(NetWorkUser user, NMSPacketEvent event, Object packet) throws IllegalAccessException {
int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet);
Trident trident = getTridentById(user, entityId);
if (trident == null) return;
World world = trident.getWorld();
Object serverEntity;
Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(trident);
Object tracker = Reflections.field$Entity$trackedEntity.get(nmsEntity);
@@ -59,14 +62,26 @@ public class CustomTridentUtils {
SchedulerTask task = CraftEngine.instance().scheduler().asyncRepeating(() -> {
try {
Reflections.method$ServerEntity$sendChanges.invoke(serverEntity);
if (!isInGround(nmsEntity)) {
world.spawnParticle(ParticleUtils.getParticle("BUBBLE"), trident.getLocation(), 1, 0, 0, 0, 0);
}
} catch (IllegalAccessException | InvocationTargetException e) {
CraftEngine.instance().logger().warn("Failed to send entity data packet", e);
}
}, 5, 5, TimeUnit.MILLISECONDS);
}, 0, 5, TimeUnit.MILLISECONDS);
user.tridentTaskView().put(entityId, task);
}
}
private static boolean isInGround(Object nmsEntity) throws IllegalAccessException, InvocationTargetException {
if (!Reflections.field$Entity$wasTouchingWater.getBoolean(nmsEntity)) return true;
if (VersionHelper.isOrAbove1_21_2()) {
return (boolean) Reflections.method$AbstractArrow$isInGround.invoke(nmsEntity);
} else {
return Reflections.field$AbstractArrow$inGround.getBoolean(nmsEntity);
}
}
@Nullable
public static Trident getTridentById(NetWorkUser user, int entityId) {
Player player = (Player) user.platformPlayer();
@@ -135,20 +150,22 @@ public class CustomTridentUtils {
Reflections.field$ClientboundMoveEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot));
}
public static Object buildCustomTridentSetEntityDataPacket(NetWorkUser user, int entityId) {
public static List<Object> buildCustomTridentSetEntityDataPacket(NetWorkUser user, List<Object> packedItems, int entityId) {
List<Object> newPackedItems = new ArrayList<>();
for (Object packedItem : packedItems) {
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId < 8) {
newPackedItems.add(packedItem);
}
}
List<Object> newData = user.tridentView().getOrDefault(entityId, List.of());
if (newData.isEmpty()) {
Trident trident = getTridentById(user, entityId);
if (notCustomTrident(trident)) return null;
if (notCustomTrident(trident)) return newPackedItems;
newData = buildEntityDataValues(trident);
user.tridentView().put(entityId, newData);
}
return FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, newData);
}
public static void modifyCustomTridentSetEntityData(NetWorkUser user, NMSPacketEvent event, int entityId) {
Object packet = buildCustomTridentSetEntityDataPacket(user, entityId);
if (packet == null) return;
event.replacePacket(packet);
newPackedItems.addAll(newData);
return newPackedItems;
}
}

View File

@@ -12,6 +12,7 @@ public class ParticleUtils {
return switch (particle) {
case "REDSTONE" -> Particle.valueOf("DUST");
case "VILLAGER_HAPPY", "HAPPY_VILLAGER" -> Particle.valueOf(VersionHelper.isOrAbove1_20_5() ? "HAPPY_VILLAGER" : "VILLAGER_HAPPY");
case "BUBBLE" -> Particle.valueOf(VersionHelper.isOrAbove1_20_5() ? "BUBBLE" : "WATER_BUBBLE");
default -> Particle.valueOf(particle);
};
}

View File

@@ -6632,7 +6632,7 @@ public class Reflections {
)
);
public static final Field field$clazz$ClientboundSetEntityDataPacket$id = requireNonNull(
public static final Field field$ClientboundSetEntityDataPacket$id = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ClientboundSetEntityDataPacket, int.class, 0
)
@@ -6730,4 +6730,32 @@ public class Reflections {
clazz$ChunkMap$TrackedEntity, clazz$ServerEntity, 0
)
);
public static final Field field$Entity$wasTouchingWater = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$Entity, VersionHelper.isOrAbove1_21_2()
? new String[]{ "wasTouchingWater", "ag" } : VersionHelper.isOrAbove1_20_5()
? new String[]{ "wasTouchingWater", "aj" } : VersionHelper.isOrAbove1_20_2()
? new String[]{ "wasTouchingWater", "ai" } : new String[]{ "wasTouchingWater", "ah" }
)
);
public static final Class<?> clazz$AbstractArrow = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.entity.projectile.EntityArrow",
"world.entity.projectile.AbstractArrow"
)
);
// 1.20~1.21.1
public static final Field field$AbstractArrow$inGround =
ReflectionUtils.getDeclaredField(
clazz$AbstractArrow, boolean.class, 0
);
// 1.21.2+
public static final Method method$AbstractArrow$isInGround =
ReflectionUtils.getMethod(
clazz$AbstractArrow, boolean.class, VersionHelper.isOrAbove1_21_5() ? new String[]{ "isInGround", "e" } : new String[]{ "isInGround", "l" }
);
}