diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java index ef4d55128..3f2c4f52c 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/base/VehicleEntity.java @@ -55,6 +55,7 @@ import org.joml.Vector4f; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.function.Function; import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; @@ -98,24 +99,33 @@ public abstract class VehicleEntity extends Entity { return orderedPassengers; } + // 仅在客户端存在的实体顺序获取,用于在客户端正确同步实体座位顺序 + public Function entityIndexOverride = null; + @Override - protected void addPassenger(Entity pPassenger) { - if (pPassenger.getVehicle() != this) { + protected void addPassenger(@NotNull Entity newPassenger) { + if (newPassenger.getVehicle() != this) { throw new IllegalStateException("Use x.startRiding(y), not y.addPassenger(x)"); } - int index = 0; - for (Entity passenger : orderedPassengers) { - if (passenger == null) { - break; - } - index++; - } - if (index >= getMaxPassengers()) return; + int index; - orderedPassengers.set(index, pPassenger); + if (entityIndexOverride != null && entityIndexOverride.apply(newPassenger) != -1) { + index = entityIndexOverride.apply(newPassenger); + } else { + index = 0; + for (Entity passenger : orderedPassengers) { + if (passenger == null) { + break; + } + index++; + } + } + if (index >= getMaxPassengers() || index < 0) return; + + orderedPassengers.set(index, newPassenger); this.passengers = ImmutableList.copyOf(orderedPassengers.stream().filter(Objects::nonNull).toList()); - this.gameEvent(GameEvent.ENTITY_MOUNT, pPassenger); + this.gameEvent(GameEvent.ENTITY_MOUNT, newPassenger); } @Override diff --git a/src/main/java/com/atsuishio/superbwarfare/mixins/ClientPacketListenerMixin.java b/src/main/java/com/atsuishio/superbwarfare/mixins/ClientPacketListenerMixin.java index 466a0b30d..95e046e5c 100644 --- a/src/main/java/com/atsuishio/superbwarfare/mixins/ClientPacketListenerMixin.java +++ b/src/main/java/com/atsuishio/superbwarfare/mixins/ClientPacketListenerMixin.java @@ -6,6 +6,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.PacketUtils; import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; import net.minecraft.world.entity.Entity; import org.spongepowered.asm.mixin.Final; @@ -19,7 +20,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; * Code based on @Luke100000's ImmersiveAircraft */ @Mixin(ClientPacketListener.class) -public class ClientPacketListenerMixin { +public abstract class ClientPacketListenerMixin { @Shadow @Final @@ -28,6 +29,53 @@ public class ClientPacketListenerMixin { @Shadow private ClientLevel level; + /** + * 正确处理VehicleEntity的带顺序乘客 + */ + @Inject(method = "handleSetEntityPassengersPacket(Lnet/minecraft/network/protocol/game/ClientboundSetPassengersPacket;)V", at = @At("HEAD"), cancellable = true) + public void vehicleEntityUpdate(ClientboundSetPassengersPacket pPacket, CallbackInfo ci) { + PacketUtils.ensureRunningOnSameThread(pPacket, (ClientPacketListener) (Object) this, this.minecraft); + + // 只处理VehicleEntity + Entity entity = this.level.getEntity(pPacket.getVehicle()); + if (!(entity instanceof VehicleEntity vehicle)) return; + ci.cancel(); + + var player = this.minecraft.player; + assert player != null; + boolean hasIndirectPassenger = entity.hasIndirectPassenger(player); + + entity.ejectPassengers(); + + // 获取排序后的Passengers + var passengers = pPacket.getPassengers(); + vehicle.entityIndexOverride = (e) -> { + for (int i = 0; i < passengers.length; i++) { + if (passengers[i] == e.getId()) { + return i; + } + } + return -1; + }; + + for (int i : passengers) { + if (i == -1) continue; + + Entity passenger = this.level.getEntity(i); + if (passenger != null) { + passenger.startRiding(entity, true); + if (passenger == player && !hasIndirectPassenger) { + Component component = Component.translatable("mount.onboard", ModKeyMappings.DISMOUNT.getTranslatedKeyMessage()); + this.minecraft.gui.setOverlayMessage(component, false); + this.minecraft.getNarrator().sayNow(component); + } + } + } + + vehicle.entityIndexOverride = null; + } + + @Inject(method = "handleSetEntityPassengersPacket(Lnet/minecraft/network/protocol/game/ClientboundSetPassengersPacket;)V", at = @At("TAIL")) public void handleSetEntityPassengersPacket(ClientboundSetPassengersPacket pPacket, CallbackInfo ci) { Entity entity = this.level.getEntity(pPacket.getVehicle()); diff --git a/src/main/java/com/atsuishio/superbwarfare/mixins/ClientboundSetPassengersPacketMixin.java b/src/main/java/com/atsuishio/superbwarfare/mixins/ClientboundSetPassengersPacketMixin.java new file mode 100644 index 000000000..29c061d6b --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/mixins/ClientboundSetPassengersPacketMixin.java @@ -0,0 +1,37 @@ +package com.atsuishio.superbwarfare.mixins; + +import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity; +import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; +import net.minecraft.world.entity.Entity; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; + +@Mixin(ClientboundSetPassengersPacket.class) +public class ClientboundSetPassengersPacketMixin { + + @Mutable + @Shadow + @Final + private int[] passengers; + + @Inject(method = "(Lnet/minecraft/world/entity/Entity;)V", at = @At("RETURN")) + private void init(Entity entity, CallbackInfo ci) { + if (entity instanceof VehicleEntity vehicle) { + // 使用顺序乘客信息代替原乘客信息 + List list = vehicle.getOrderedPassengers(); + passengers = new int[list.size()]; + + for (int i = 0; i < list.size(); ++i) { + var passenger = list.get(i); + passengers[i] = passenger == null ? -1 : passenger.getId(); + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/mixins.superbwarfare.json b/src/main/resources/mixins.superbwarfare.json index 22c3f9cf8..39eeddbc8 100644 --- a/src/main/resources/mixins.superbwarfare.json +++ b/src/main/resources/mixins.superbwarfare.json @@ -5,6 +5,7 @@ "refmap": "mixins.superbwarfare.refmap.json", "mixins": [ "ClientboundSetEntityMotionPacketMixin", + "ClientboundSetPassengersPacketMixin", "EntityMixin", "ExplosionMixin", "LivingEntityMixin",