正确处理载具座位数据同步

This commit is contained in:
Light_Quanta 2025-03-06 21:16:09 +08:00
parent a9fddff258
commit fb514ecfad
No known key found for this signature in database
GPG key ID: 11A39A1B8C890959
4 changed files with 109 additions and 13 deletions

View file

@ -55,6 +55,7 @@ import org.joml.Vector4f;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function;
import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle; import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle;
@ -98,24 +99,33 @@ public abstract class VehicleEntity extends Entity {
return orderedPassengers; return orderedPassengers;
} }
// 仅在客户端存在的实体顺序获取用于在客户端正确同步实体座位顺序
public Function<Entity, Integer> entityIndexOverride = null;
@Override @Override
protected void addPassenger(Entity pPassenger) { protected void addPassenger(@NotNull Entity newPassenger) {
if (pPassenger.getVehicle() != this) { if (newPassenger.getVehicle() != this) {
throw new IllegalStateException("Use x.startRiding(y), not y.addPassenger(x)"); throw new IllegalStateException("Use x.startRiding(y), not y.addPassenger(x)");
} }
int index = 0; int index;
for (Entity passenger : orderedPassengers) {
if (passenger == null) {
break;
}
index++;
}
if (index >= getMaxPassengers()) return;
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.passengers = ImmutableList.copyOf(orderedPassengers.stream().filter(Objects::nonNull).toList());
this.gameEvent(GameEvent.ENTITY_MOUNT, pPassenger); this.gameEvent(GameEvent.ENTITY_MOUNT, newPassenger);
} }
@Override @Override

View file

@ -6,6 +6,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.PacketUtils;
import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
@ -19,7 +20,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
* Code based on @Luke100000's ImmersiveAircraft * Code based on @Luke100000's ImmersiveAircraft
*/ */
@Mixin(ClientPacketListener.class) @Mixin(ClientPacketListener.class)
public class ClientPacketListenerMixin { public abstract class ClientPacketListenerMixin {
@Shadow @Shadow
@Final @Final
@ -28,6 +29,53 @@ public class ClientPacketListenerMixin {
@Shadow @Shadow
private ClientLevel level; 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")) @Inject(method = "handleSetEntityPassengersPacket(Lnet/minecraft/network/protocol/game/ClientboundSetPassengersPacket;)V", at = @At("TAIL"))
public void handleSetEntityPassengersPacket(ClientboundSetPassengersPacket pPacket, CallbackInfo ci) { public void handleSetEntityPassengersPacket(ClientboundSetPassengersPacket pPacket, CallbackInfo ci) {
Entity entity = this.level.getEntity(pPacket.getVehicle()); Entity entity = this.level.getEntity(pPacket.getVehicle());

View file

@ -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 = "<init>(Lnet/minecraft/world/entity/Entity;)V", at = @At("RETURN"))
private void init(Entity entity, CallbackInfo ci) {
if (entity instanceof VehicleEntity vehicle) {
// 使用顺序乘客信息代替原乘客信息
List<Entity> 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();
}
}
}
}

View file

@ -5,6 +5,7 @@
"refmap": "mixins.superbwarfare.refmap.json", "refmap": "mixins.superbwarfare.refmap.json",
"mixins": [ "mixins": [
"ClientboundSetEntityMotionPacketMixin", "ClientboundSetEntityMotionPacketMixin",
"ClientboundSetPassengersPacketMixin",
"EntityMixin", "EntityMixin",
"ExplosionMixin", "ExplosionMixin",
"LivingEntityMixin", "LivingEntityMixin",