Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-24 15:20:25 +01:00
Fix some mount offsets and strange behaviors with GSit (#2701)
* Prevent boats from floating when a Bedrock player rides in the back * Update llama and shulker mount height offset * Fix Trader llama mount offset * Change passengers to an IntList Also move rotation lock stuff to EntityUtils * Allow EntityCache.getEntityByJavaId to return the session's player Removes many checks from several translators. * Fix mount offset on armorstands and area effect clouds Also prevent area effect clouds from despawning when used as an invisible entity (used in GSit to offset players riding on other players) * Update mount offsets on height changes TODO test this * Actually update vehicleId and optimize StriderEntity metadata update * Don't hide marker armor stands and properly update mount offsets * What? * Remove y offset for Shulkers riding other entities * Confirm teleports in the order received This allows Bedrock players to move after standing up when using GSit * Fix mount offset for riders on baby zoglins * Cache only the latest teleport and confirm teleports immediately * Fix crawling with GSit * Inline var and undo respawn method * Use Entity reference for vehicles * Remove ridingVehicleEntity from GeyserSession * Use Entity references for passengers and drop cachedPlayerEntityLinks * Reuse variable and remove setVehicle(null)
Dieser Commit ist enthalten in:
Ursprung
90442a8922
Commit
754bb42c19
@ -47,18 +47,19 @@ public class AreaEffectCloudEntity extends Entity {
|
||||
protected void initializeMetadata() {
|
||||
super.initializeMetadata();
|
||||
// Without this the cloud doesn't appear,
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_DURATION, 600);
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_DURATION, Integer.MAX_VALUE);
|
||||
|
||||
// This disabled client side shrink of the cloud
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, 0.0f);
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_RATE, -0.005f);
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, -0.5f);
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_RATE, Float.MIN_VALUE);
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, Float.MIN_VALUE);
|
||||
|
||||
setFlag(EntityFlag.FIRE_IMMUNE, true);
|
||||
}
|
||||
|
||||
public void setRadius(FloatEntityMetadata entityMetadata) {
|
||||
float value = entityMetadata.getPrimitiveValue();
|
||||
// Anything less than 0.5 will cause the cloud to despawn
|
||||
float value = Math.max(entityMetadata.getPrimitiveValue(), 0.5f);
|
||||
dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, value);
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, 2.0f * value);
|
||||
}
|
||||
|
@ -84,8 +84,12 @@ public class BoatEntity extends Entity {
|
||||
|
||||
MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket();
|
||||
moveEntityPacket.setRuntimeEntityId(geyserId);
|
||||
// Minimal glitching when ClientboundMoveVehiclePacket is sent
|
||||
moveEntityPacket.setPosition(session.getRidingVehicleEntity() == this ? position.up(EntityDefinitions.PLAYER.offset() - this.definition.offset()) : this.position);
|
||||
if (session.getPlayerEntity().getVehicle() == this && session.getPlayerEntity().isRidingInFront()) {
|
||||
// Minimal glitching when ClientboundMoveVehiclePacket is sent
|
||||
moveEntityPacket.setPosition(position.up(EntityDefinitions.PLAYER.offset() - this.definition.offset()));
|
||||
} else {
|
||||
moveEntityPacket.setPosition(this.position);
|
||||
}
|
||||
moveEntityPacket.setRotation(getBedrockRotation());
|
||||
moveEntityPacket.setOnGround(isOnGround);
|
||||
moveEntityPacket.setTeleported(teleported);
|
||||
@ -128,7 +132,7 @@ public class BoatEntity extends Entity {
|
||||
paddleTimeLeft = 0f;
|
||||
if (!this.passengers.isEmpty()) {
|
||||
// Get the entity by the first stored passenger and convey motion in this manner
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(this.passengers.iterator().nextLong());
|
||||
Entity entity = this.passengers.get(0);
|
||||
if (entity != null) {
|
||||
updateLeftPaddle(session, entity);
|
||||
}
|
||||
@ -144,7 +148,7 @@ public class BoatEntity extends Entity {
|
||||
if (isPaddlingRight) {
|
||||
paddleTimeRight = 0f;
|
||||
if (!this.passengers.isEmpty()) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(this.passengers.iterator().nextLong());
|
||||
Entity entity = this.passengers.get(0);
|
||||
if (entity != null) {
|
||||
updateRightPaddle(session, entity);
|
||||
}
|
||||
|
@ -39,7 +39,6 @@ import com.nukkitx.protocol.bedrock.packet.AddEntityPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.RemoveEntityPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -48,8 +47,11 @@ import org.geysermc.geyser.entity.EntityDefinition;
|
||||
import org.geysermc.geyser.entity.GeyserDirtyMetadata;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.EntityUtils;
|
||||
import org.geysermc.geyser.util.MathUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -90,7 +92,8 @@ public class Entity {
|
||||
protected String nametag = "";
|
||||
/* Metadata end */
|
||||
|
||||
protected LongOpenHashSet passengers = new LongOpenHashSet();
|
||||
protected List<Entity> passengers = Collections.emptyList();
|
||||
protected Entity vehicle;
|
||||
/**
|
||||
* A container to store temporary metadata before it's sent to Bedrock.
|
||||
*/
|
||||
@ -181,11 +184,11 @@ public class Entity {
|
||||
public boolean despawnEntity() {
|
||||
if (!valid) return true;
|
||||
|
||||
for (long passenger : passengers) { // Make sure all passengers on the despawned entity are updated
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(passenger);
|
||||
if (entity == null) continue;
|
||||
entity.setFlag(EntityFlag.RIDING, false);
|
||||
entity.updateBedrockMetadata();
|
||||
for (Entity passenger : passengers) { // Make sure all passengers on the despawned entity are updated
|
||||
if (passenger == null) continue;
|
||||
passenger.setVehicle(null);
|
||||
passenger.setFlag(EntityFlag.RIDING, false);
|
||||
passenger.updateBedrockMetadata();
|
||||
}
|
||||
|
||||
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
|
||||
@ -391,6 +394,8 @@ public class Entity {
|
||||
if (height != boundingBoxHeight) {
|
||||
boundingBoxHeight = height;
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_HEIGHT, boundingBoxHeight);
|
||||
|
||||
updatePassengerOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,6 +440,30 @@ public class Entity {
|
||||
return Vector3f.from(pitch, headYaw, yaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the mount offsets of each passenger on this vehicle
|
||||
*/
|
||||
protected void updatePassengerOffsets() {
|
||||
for (Entity passenger : passengers) {
|
||||
if (passenger != null) {
|
||||
boolean rider = passengers.get(0) == this;
|
||||
EntityUtils.updateMountOffset(passenger, this, rider, true, passengers.size() > 1);
|
||||
passenger.updateBedrockMetadata();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this entity's mount offset
|
||||
*/
|
||||
protected void updateMountOffset() {
|
||||
if (vehicle != null) {
|
||||
boolean rider = vehicle.getPassengers().get(0) == this;
|
||||
EntityUtils.updateMountOffset(this, vehicle, rider, true, vehicle.getPassengers().size() > 1);
|
||||
updateBedrockMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <I extends Entity> I as(Class<I> entityClass) {
|
||||
return entityClass.isInstance(this) ? (I) this : null;
|
||||
|
@ -78,13 +78,7 @@ public class FishingHookEntity extends ThrowableEntity {
|
||||
|
||||
public void setHookedEntity(IntEntityMetadata entityMetadata) {
|
||||
int hookedEntityId = entityMetadata.getPrimitiveValue() - 1;
|
||||
Entity entity;
|
||||
if (session.getPlayerEntity().getEntityId() == hookedEntityId) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(hookedEntityId);
|
||||
}
|
||||
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(hookedEntityId);
|
||||
if (entity != null) {
|
||||
bedrockTargetId = entity.getGeyserId();
|
||||
dirtyMetadata.put(EntityData.TARGET_EID, bedrockTargetId);
|
||||
|
@ -146,13 +146,14 @@ public class ArmorStandEntity extends LivingEntity {
|
||||
isMarker = (xd & 0x10) == 0x10;
|
||||
if (oldIsMarker != isMarker) {
|
||||
if (isMarker) {
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.0f);
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f);
|
||||
setBoundingBoxWidth(0.0f);
|
||||
setBoundingBoxHeight(0.0f);
|
||||
dirtyMetadata.put(EntityData.SCALE, 0f);
|
||||
} else {
|
||||
toggleSmallStatus();
|
||||
}
|
||||
|
||||
updateMountOffset();
|
||||
updateSecondEntityStatus(false);
|
||||
}
|
||||
|
||||
@ -376,8 +377,8 @@ public class ArmorStandEntity extends LivingEntity {
|
||||
* If this armor stand is not a marker, set its bounding box size and scale.
|
||||
*/
|
||||
private void toggleSmallStatus() {
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, isSmall ? 0.25f : definition.width());
|
||||
dirtyMetadata.put(EntityData.BOUNDING_BOX_HEIGHT, isSmall ? 0.9875f : definition.height());
|
||||
setBoundingBoxWidth(isSmall ? 0.25f : definition.width());
|
||||
setBoundingBoxHeight(isSmall ? 0.9875f : definition.height());
|
||||
dirtyMetadata.put(EntityData.SCALE, isSmall ? 0.55f : 1f);
|
||||
}
|
||||
|
||||
|
@ -60,12 +60,8 @@ public class StriderEntity extends AnimalEntity {
|
||||
// Needs to copy the parent state
|
||||
if (getFlag(EntityFlag.RIDING)) {
|
||||
boolean parentShaking = false;
|
||||
//TODO optimize
|
||||
for (Entity ent : session.getEntityCache().getEntities().values()) {
|
||||
if (ent.getPassengers().contains(entityId) && ent instanceof StriderEntity) {
|
||||
parentShaking = ent.getFlag(EntityFlag.SHAKING);
|
||||
break;
|
||||
}
|
||||
if (vehicle instanceof StriderEntity) {
|
||||
parentShaking = vehicle.getFlag(EntityFlag.SHAKING);
|
||||
}
|
||||
|
||||
setFlag(EntityFlag.BREATHING, !parentShaking);
|
||||
@ -76,10 +72,9 @@ public class StriderEntity extends AnimalEntity {
|
||||
}
|
||||
|
||||
// Update the passengers if we have any
|
||||
for (long passenger : passengers) {
|
||||
Entity passengerEntity = session.getEntityCache().getEntityByJavaId(passenger);
|
||||
if (passengerEntity != null) {
|
||||
passengerEntity.updateBedrockMetadata();
|
||||
for (Entity passenger : passengers) {
|
||||
if (passenger != null) {
|
||||
passenger.updateBedrockMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,13 +42,7 @@ public class GuardianEntity extends MonsterEntity {
|
||||
|
||||
public void setGuardianTarget(IntEntityMetadata entityMetadata) {
|
||||
int entityId = entityMetadata.getPrimitiveValue();
|
||||
Entity entity;
|
||||
if (session.getPlayerEntity().getEntityId() == entityId) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(entityId);
|
||||
}
|
||||
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(entityId);
|
||||
if (entity != null) {
|
||||
dirtyMetadata.put(EntityData.TARGET_EID, entity.getGeyserId());
|
||||
} else {
|
||||
|
@ -44,6 +44,8 @@ public class PiglinEntity extends BasePiglinEntity {
|
||||
boolean isBaby = entityMetadata.getPrimitiveValue();
|
||||
dirtyMetadata.put(EntityData.SCALE, isBaby? .55f : 1f);
|
||||
setFlag(EntityFlag.BABY, isBaby);
|
||||
|
||||
updateMountOffset();
|
||||
}
|
||||
|
||||
public void setChargingCrossbow(BooleanEntityMetadata entityMetadata) {
|
||||
|
@ -60,15 +60,11 @@ public class WitherEntity extends MonsterEntity {
|
||||
|
||||
private void setTargetId(EntityData entityData, IntEntityMetadata entityMetadata) {
|
||||
int entityId = entityMetadata.getPrimitiveValue();
|
||||
Entity entity;
|
||||
if (session.getPlayerEntity().getEntityId() == entityId) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(entityId);
|
||||
}
|
||||
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(entityId);
|
||||
if (entity != null) {
|
||||
dirtyMetadata.put(entityData, entity.getGeyserId());
|
||||
} else {
|
||||
dirtyMetadata.put(entityData, (long) 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,17 @@ public class ZoglinEntity extends MonsterEntity {
|
||||
|
||||
public void setBaby(BooleanEntityMetadata entityMetadata) {
|
||||
boolean isBaby = entityMetadata.getPrimitiveValue();
|
||||
dirtyMetadata.put(EntityData.SCALE, isBaby? .55f : 1f);
|
||||
setFlag(EntityFlag.BABY, isBaby);
|
||||
if (isBaby != getFlag(EntityFlag.BABY)) {
|
||||
dirtyMetadata.put(EntityData.SCALE, isBaby ? .55f : 1f);
|
||||
setFlag(EntityFlag.BABY, isBaby);
|
||||
|
||||
updatePassengerOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getBoundingBoxHeight() {
|
||||
float scale = getFlag(EntityFlag.BABY) ? 0.55f : 1f;
|
||||
return scale * definition.height();
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,8 @@ public class ZombieEntity extends MonsterEntity {
|
||||
boolean isBaby = entityMetadata.getPrimitiveValue();
|
||||
dirtyMetadata.put(EntityData.SCALE, isBaby ? .55f : 1.0f);
|
||||
setFlag(EntityFlag.BABY, isBaby);
|
||||
|
||||
updateMountOffset();
|
||||
}
|
||||
|
||||
public void setConvertingToDrowned(BooleanEntityMetadata entityMetadata) {
|
||||
|
@ -123,14 +123,6 @@ public class PlayerEntity extends LivingEntity {
|
||||
|
||||
setFlagsDirty(false);
|
||||
|
||||
long linkedEntityId = session.getEntityCache().getCachedPlayerEntityLink(entityId);
|
||||
if (linkedEntityId != -1) {
|
||||
Entity linkedEntity = session.getEntityCache().getEntityByJavaId(linkedEntityId);
|
||||
if (linkedEntity != null) {
|
||||
addPlayerPacket.getEntityLinks().add(new EntityLinkData(linkedEntity.getGeyserId(), geyserId, EntityLinkData.Type.RIDER, false, false));
|
||||
}
|
||||
}
|
||||
|
||||
valid = true;
|
||||
session.sendUpstreamPacket(addPlayerPacket);
|
||||
}
|
||||
|
@ -35,11 +35,14 @@ import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.RespawnPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.AttributeUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
@ -73,7 +76,7 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||
private final GeyserSession session;
|
||||
|
||||
public SessionPlayerEntity(GeyserSession session) {
|
||||
super(session, 1, 1, new GameProfile(UUID.randomUUID(), "unknown"), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0);
|
||||
super(session, -1, 1, new GameProfile(UUID.randomUUID(), "unknown"), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0);
|
||||
|
||||
valid = true;
|
||||
this.session = session;
|
||||
@ -112,7 +115,10 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||
@Override
|
||||
public void setFlags(ByteEntityMetadata entityMetadata) {
|
||||
super.setFlags(entityMetadata);
|
||||
session.setSwimmingInWater((entityMetadata.getPrimitiveValue() & 0x10) == 0x10 && getFlag(EntityFlag.SPRINTING));
|
||||
// Swimming/crawling is controlled by the Java server
|
||||
boolean swimming = (entityMetadata.getPrimitiveValue() & 0x10) == 0x10;
|
||||
session.setSwimming(swimming);
|
||||
session.setSwimmingInWater(swimming && getFlag(EntityFlag.SPRINTING));
|
||||
refreshSpeed = true;
|
||||
}
|
||||
|
||||
|
@ -42,9 +42,7 @@ import com.github.steveice10.mc.protocol.data.game.recipe.Recipe;
|
||||
import com.github.steveice10.mc.protocol.data.game.statistic.CustomStatistic;
|
||||
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic;
|
||||
import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientIntentionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket;
|
||||
import com.github.steveice10.packetlib.BuiltinFlags;
|
||||
@ -68,7 +66,6 @@ import it.unimi.dsi.fastutil.ints.*;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
@ -167,7 +164,8 @@ public class GeyserSession implements GeyserConnection, CommandSender {
|
||||
private final TagCache tagCache;
|
||||
private final WorldCache worldCache;
|
||||
|
||||
private final Int2ObjectMap<TeleportCache> teleportMap = new Int2ObjectOpenHashMap<>();
|
||||
@Setter
|
||||
private TeleportCache unconfirmedTeleport;
|
||||
|
||||
private final WorldBorder worldBorder;
|
||||
/**
|
||||
@ -333,9 +331,6 @@ public class GeyserSession implements GeyserConnection, CommandSender {
|
||||
@Setter
|
||||
private Vector3f lastInteractionPlayerPosition = Vector3f.ZERO;
|
||||
|
||||
@Setter
|
||||
private Entity ridingVehicleEntity;
|
||||
|
||||
/**
|
||||
* The entity that the client is currently looking at.
|
||||
*/
|
||||
@ -1247,73 +1242,23 @@ public class GeyserSession implements GeyserConnection, CommandSender {
|
||||
return itemNetId.getAndIncrement();
|
||||
}
|
||||
|
||||
public void addTeleport(TeleportCache teleportCache) {
|
||||
teleportMap.put(teleportCache.getTeleportConfirmId(), teleportCache);
|
||||
|
||||
ObjectIterator<Int2ObjectMap.Entry<TeleportCache>> it = teleportMap.int2ObjectEntrySet().iterator();
|
||||
|
||||
// Remove any teleports with a higher number - maybe this is a world change that reset the ID to 0?
|
||||
while (it.hasNext()) {
|
||||
Int2ObjectMap.Entry<TeleportCache> entry = it.next();
|
||||
int nextID = entry.getValue().getTeleportConfirmId();
|
||||
if (nextID > teleportCache.getTeleportConfirmId()) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void confirmTeleport(Vector3d position) {
|
||||
if (teleportMap.size() == 0) {
|
||||
if (unconfirmedTeleport == null) {
|
||||
return;
|
||||
}
|
||||
int teleportID = -1;
|
||||
|
||||
for (Int2ObjectMap.Entry<TeleportCache> entry : teleportMap.int2ObjectEntrySet()) {
|
||||
if (entry.getValue().canConfirm(position)) {
|
||||
if (entry.getValue().getTeleportConfirmId() > teleportID) {
|
||||
teleportID = entry.getValue().getTeleportConfirmId();
|
||||
}
|
||||
}
|
||||
if (unconfirmedTeleport.canConfirm(position)) {
|
||||
unconfirmedTeleport = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (teleportID != -1) {
|
||||
ObjectIterator<Int2ObjectMap.Entry<TeleportCache>> it = teleportMap.int2ObjectEntrySet().iterator();
|
||||
|
||||
// Confirm the current teleport and any earlier ones
|
||||
while (it.hasNext()) {
|
||||
TeleportCache entry = it.next().getValue();
|
||||
int nextID = entry.getTeleportConfirmId();
|
||||
if (nextID <= teleportID) {
|
||||
ServerboundAcceptTeleportationPacket teleportConfirmPacket = new ServerboundAcceptTeleportationPacket(nextID);
|
||||
sendDownstreamPacket(teleportConfirmPacket);
|
||||
// Servers (especially ones like Hypixel) expect exact coordinates given back to them.
|
||||
ServerboundMovePlayerPosRotPacket positionPacket = new ServerboundMovePlayerPosRotPacket(playerEntity.isOnGround(),
|
||||
entry.getX(), entry.getY(), entry.getZ(), entry.getYaw(), entry.getPitch());
|
||||
sendDownstreamPacket(positionPacket);
|
||||
it.remove();
|
||||
geyser.getLogger().debug("Confirmed teleport " + nextID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (teleportMap.size() > 0) {
|
||||
int resendID = -1;
|
||||
for (Int2ObjectMap.Entry<TeleportCache> entry : teleportMap.int2ObjectEntrySet()) {
|
||||
TeleportCache teleport = entry.getValue();
|
||||
teleport.incrementUnconfirmedFor();
|
||||
if (teleport.shouldResend()) {
|
||||
if (teleport.getTeleportConfirmId() >= resendID) {
|
||||
resendID = teleport.getTeleportConfirmId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resendID != -1) {
|
||||
geyser.getLogger().debug("Resending teleport " + resendID);
|
||||
TeleportCache teleport = teleportMap.get(resendID);
|
||||
getPlayerEntity().moveAbsolute(Vector3f.from(teleport.getX(), teleport.getY(), teleport.getZ()),
|
||||
teleport.getYaw(), teleport.getPitch(), playerEntity.isOnGround(), true);
|
||||
}
|
||||
// Resend the teleport every few packets until Bedrock responds
|
||||
unconfirmedTeleport.incrementUnconfirmedFor();
|
||||
if (unconfirmedTeleport.shouldResend()) {
|
||||
unconfirmedTeleport.resetUnconfirmedFor();
|
||||
geyser.getLogger().debug("Resending teleport " + unconfirmedTeleport.getTeleportConfirmId());
|
||||
getPlayerEntity().moveAbsolute(Vector3f.from(unconfirmedTeleport.getX(), unconfirmedTeleport.getY(), unconfirmedTeleport.getZ()),
|
||||
unconfirmedTeleport.getYaw(), unconfirmedTeleport.getPitch(), playerEntity.isOnGround(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,15 +56,12 @@ public class EntityCache {
|
||||
private final Long2LongMap entityIdTranslations = new Long2LongOpenHashMap();
|
||||
private final Map<UUID, PlayerEntity> playerEntities = new Object2ObjectOpenHashMap<>();
|
||||
private final Map<UUID, BossBar> bossBars = new Object2ObjectOpenHashMap<>();
|
||||
private final Long2LongMap cachedPlayerEntityLinks = new Long2LongOpenHashMap();
|
||||
|
||||
@Getter
|
||||
private final AtomicLong nextEntityId = new AtomicLong(2L);
|
||||
|
||||
public EntityCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
|
||||
cachedPlayerEntityLinks.defaultReturnValue(-1L);
|
||||
}
|
||||
|
||||
public void spawnEntity(Entity entity) {
|
||||
@ -112,8 +109,6 @@ public class EntityCache {
|
||||
}
|
||||
|
||||
session.getPlayerWithCustomHeads().clear();
|
||||
// As a precaution
|
||||
cachedPlayerEntityLinks.clear();
|
||||
}
|
||||
|
||||
public Entity getEntityByGeyserId(long geyserId) {
|
||||
@ -121,6 +116,9 @@ public class EntityCache {
|
||||
}
|
||||
|
||||
public Entity getEntityByJavaId(long javaId) {
|
||||
if (javaId == session.getPlayerEntity().getEntityId()) {
|
||||
return session.getPlayerEntity();
|
||||
}
|
||||
return entities.get(entityIdTranslations.get(javaId));
|
||||
}
|
||||
|
||||
@ -160,14 +158,6 @@ public class EntityCache {
|
||||
bossBars.values().forEach(BossBar::updateBossBar);
|
||||
}
|
||||
|
||||
public long getCachedPlayerEntityLink(long playerId) {
|
||||
return cachedPlayerEntityLinks.remove(playerId);
|
||||
}
|
||||
|
||||
public void addCachedPlayerEntityLink(long playerId, long linkedEntityId) {
|
||||
cachedPlayerEntityLinks.put(playerId, linkedEntityId);
|
||||
}
|
||||
|
||||
public List<Tickable> getTickableEntities() {
|
||||
return tickableEntities;
|
||||
}
|
||||
|
@ -66,6 +66,10 @@ public class TeleportCache {
|
||||
unconfirmedFor++;
|
||||
}
|
||||
|
||||
public void resetUnconfirmedFor() {
|
||||
unconfirmedFor = 0;
|
||||
}
|
||||
|
||||
public boolean shouldResend() {
|
||||
return unconfirmedFor >= RESEND_THRESHOLD;
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ public class WorldBorder {
|
||||
// Move the player back, but allow gravity to take place
|
||||
// Teleported = true makes going back better, but disconnects the player from their mounted entity
|
||||
playerEntity.moveAbsolute(Vector3f.from(playerEntity.getPosition().getX(), (newPosition.getY() - EntityDefinitions.PLAYER.offset()), playerEntity.getPosition().getZ()),
|
||||
playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), playerEntity.isOnGround(), session.getRidingVehicleEntity() == null);
|
||||
playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), playerEntity.isOnGround(), playerEntity.getVehicle() == null);
|
||||
}
|
||||
return isInWorldBorder;
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator<MoveEn
|
||||
public void translate(GeyserSession session, MoveEntityAbsolutePacket packet) {
|
||||
session.setLastVehicleMoveTimestamp(System.currentTimeMillis());
|
||||
|
||||
Entity ridingEntity = session.getRidingVehicleEntity();
|
||||
Entity ridingEntity = session.getPlayerEntity().getVehicle();
|
||||
if (ridingEntity != null && session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), false)) {
|
||||
Vector3f position = Vector3f.from(ridingEntity.getPosition().getX(), packet.getPosition().getY(),
|
||||
ridingEntity.getPosition().getZ());
|
||||
|
@ -54,7 +54,7 @@ public class BedrockPlayerInputTranslator extends PacketTranslator<PlayerInputPa
|
||||
|
||||
// Bedrock only sends movement vehicle packets while moving
|
||||
// This allows horses to take damage while standing on magma
|
||||
Entity vehicle = session.getRidingVehicleEntity();
|
||||
Entity vehicle = session.getPlayerEntity().getVehicle();
|
||||
boolean sendMovement = false;
|
||||
if (vehicle instanceof AbstractHorseEntity && !(vehicle instanceof LlamaEntity)) {
|
||||
sendMovement = vehicle.isOnGround();
|
||||
|
@ -77,16 +77,17 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
||||
session.sendUpstreamPacket(attributesPacket);
|
||||
break;
|
||||
case START_SWIMMING:
|
||||
ServerboundPlayerCommandPacket startSwimPacket = new ServerboundPlayerCommandPacket((int) entity.getEntityId(), PlayerState.START_SPRINTING);
|
||||
session.sendDownstreamPacket(startSwimPacket);
|
||||
|
||||
session.setSwimming(true);
|
||||
if (!session.getPlayerEntity().getFlag(EntityFlag.SWIMMING)) {
|
||||
ServerboundPlayerCommandPacket startSwimPacket = new ServerboundPlayerCommandPacket((int) entity.getEntityId(), PlayerState.START_SPRINTING);
|
||||
session.sendDownstreamPacket(startSwimPacket);
|
||||
}
|
||||
break;
|
||||
case STOP_SWIMMING:
|
||||
ServerboundPlayerCommandPacket stopSwimPacket = new ServerboundPlayerCommandPacket((int) entity.getEntityId(), PlayerState.STOP_SPRINTING);
|
||||
session.sendDownstreamPacket(stopSwimPacket);
|
||||
|
||||
session.setSwimming(false);
|
||||
// Prevent packet spam when Bedrock players are crawling near the edge of a block
|
||||
if (session.isSwimmingInWater()) {
|
||||
ServerboundPlayerCommandPacket stopSwimPacket = new ServerboundPlayerCommandPacket((int) entity.getEntityId(), PlayerState.STOP_SPRINTING);
|
||||
session.sendDownstreamPacket(stopSwimPacket);
|
||||
}
|
||||
break;
|
||||
case START_GLIDE:
|
||||
// Otherwise gliding will not work in creative
|
||||
@ -134,13 +135,17 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
||||
session.setSneaking(false);
|
||||
break;
|
||||
case START_SPRINT:
|
||||
ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket((int) entity.getEntityId(), PlayerState.START_SPRINTING);
|
||||
session.sendDownstreamPacket(startSprintPacket);
|
||||
session.setSprinting(true);
|
||||
if (!session.getPlayerEntity().getFlag(EntityFlag.SWIMMING)) {
|
||||
ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket((int) entity.getEntityId(), PlayerState.START_SPRINTING);
|
||||
session.sendDownstreamPacket(startSprintPacket);
|
||||
session.setSprinting(true);
|
||||
}
|
||||
break;
|
||||
case STOP_SPRINT:
|
||||
ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket((int) entity.getEntityId(), PlayerState.STOP_SPRINTING);
|
||||
session.sendDownstreamPacket(stopSprintPacket);
|
||||
if (!session.getPlayerEntity().getFlag(EntityFlag.SWIMMING)) {
|
||||
ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket((int) entity.getEntityId(), PlayerState.STOP_SPRINTING);
|
||||
session.sendDownstreamPacket(stopSprintPacket);
|
||||
}
|
||||
session.setSprinting(false);
|
||||
break;
|
||||
case DROP_ITEM:
|
||||
|
@ -74,7 +74,6 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
||||
case LEAVE_VEHICLE:
|
||||
ServerboundPlayerCommandPacket sneakPacket = new ServerboundPlayerCommandPacket((int) entity.getEntityId(), PlayerState.START_SNEAKING);
|
||||
session.sendDownstreamPacket(sneakPacket);
|
||||
session.setRidingVehicleEntity(null);
|
||||
break;
|
||||
case MOUSEOVER:
|
||||
// Handle the buttons for mobile - "Mount", etc; and the suggestions for console - "ZL: Mount", etc
|
||||
@ -97,7 +96,7 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
||||
break;
|
||||
case OPEN_INVENTORY:
|
||||
if (session.getOpenInventory() == null) {
|
||||
Entity ridingEntity = session.getRidingVehicleEntity();
|
||||
Entity ridingEntity = session.getPlayerEntity().getVehicle();
|
||||
if (ridingEntity instanceof AbstractHorseEntity) {
|
||||
if (ridingEntity.getFlag(EntityFlag.TAMED)) {
|
||||
// We should request to open the horse inventory instead
|
||||
|
@ -67,7 +67,8 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
|
||||
// Send book update before the player moves
|
||||
session.getBookEditCache().checkForSend();
|
||||
|
||||
if (!session.getTeleportMap().isEmpty()) {
|
||||
// Ignore movement packets until Bedrock's position matches the teleported position
|
||||
if (session.getUnconfirmedTeleport() != null) {
|
||||
session.confirmTeleport(packet.getPosition().toDouble().sub(0, EntityDefinitions.PLAYER.offset(), 0));
|
||||
return;
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ import org.geysermc.geyser.translator.protocol.Translator;
|
||||
public class BedrockRiderJumpTranslator extends PacketTranslator<RiderJumpPacket> {
|
||||
@Override
|
||||
public void translate(GeyserSession session, RiderJumpPacket packet) {
|
||||
Entity vehicle = session.getRidingVehicleEntity();
|
||||
Entity vehicle = session.getPlayerEntity().getVehicle();
|
||||
if (vehicle instanceof AbstractHorseEntity) {
|
||||
ServerboundPlayerCommandPacket playerCommandPacket = new ServerboundPlayerCommandPacket((int) vehicle.getEntityId(), PlayerState.START_HORSE_JUMP, packet.getJumpStrength());
|
||||
session.sendDownstreamPacket(playerCommandPacket);
|
||||
|
@ -41,12 +41,7 @@ public class JavaAnimateTranslator extends PacketTranslator<ClientboundAnimatePa
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundAnimatePacket packet) {
|
||||
Entity entity;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (entity == null)
|
||||
return;
|
||||
|
||||
|
@ -47,12 +47,7 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundEntityEventPacket packet) {
|
||||
Entity entity;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (entity == null)
|
||||
return;
|
||||
|
||||
|
@ -37,9 +37,6 @@ public class JavaMoveEntityPosRotTranslator extends PacketTranslator<Clientbound
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundMoveEntityPosRotPacket packet) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
if (entity == null) return;
|
||||
|
||||
entity.updatePositionAndRotation(packet.getMoveX(), packet.getMoveY(), packet.getMoveZ(), packet.getYaw(), packet.getPitch(), packet.isOnGround());
|
||||
|
@ -36,12 +36,7 @@ public class JavaMoveEntityPosTranslator extends PacketTranslator<ClientboundMov
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundMoveEntityPosPacket packet) {
|
||||
Entity entity;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (entity == null) return;
|
||||
|
||||
entity.moveRelative(packet.getMoveX(), packet.getMoveY(), packet.getMoveZ(), entity.getYaw(), entity.getPitch(), entity.getHeadYaw(), packet.isOnGround());
|
||||
|
@ -37,9 +37,6 @@ public class JavaMoveEntityRotTranslator extends PacketTranslator<ClientboundMov
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundMoveEntityRotPacket packet) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
if (entity == null) return;
|
||||
|
||||
entity.updateRotation(packet.getYaw(), packet.getPitch(), packet.isOnGround());
|
||||
|
@ -37,7 +37,7 @@ public class JavaMoveVehicleTranslator extends PacketTranslator<ClientboundMoveV
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundMoveVehiclePacket packet) {
|
||||
Entity entity = session.getRidingVehicleEntity();
|
||||
Entity entity = session.getPlayerEntity().getVehicle();
|
||||
if (entity == null) return;
|
||||
|
||||
entity.moveAbsolute(Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), false, true);
|
||||
|
@ -38,12 +38,9 @@ public class JavaRemoveMobEffectTranslator extends PacketTranslator<ClientboundR
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundRemoveMobEffectPacket packet) {
|
||||
Entity entity;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (entity == session.getPlayerEntity()) {
|
||||
session.getEffectCache().removeEffect(packet.getEffect());
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
if (entity == null)
|
||||
return;
|
||||
|
@ -36,13 +36,7 @@ public class JavaRotateHeadTranslator extends PacketTranslator<ClientboundRotate
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundRotateHeadPacket packet) {
|
||||
Entity entity;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (entity == null) return;
|
||||
|
||||
entity.updateHeadLookRotation(packet.getHeadYaw());
|
||||
|
@ -40,12 +40,7 @@ public class JavaSetEntityDataTranslator extends PacketTranslator<ClientboundSet
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundSetEntityDataPacket packet) {
|
||||
Entity entity;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (entity == null) return;
|
||||
|
||||
EntityDefinition<?> definition = entity.getDefinition();
|
||||
|
@ -43,33 +43,23 @@ public class JavaSetEntityLinkTranslator extends PacketTranslator<ClientboundSet
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundSetEntityLinkPacket packet) {
|
||||
Entity holderId;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
holderId = session.getPlayerEntity();
|
||||
} else {
|
||||
holderId = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
Entity holderId = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (!(holderId instanceof MobEntity mobEntity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entity attachedToId;
|
||||
if (packet.getAttachedToId() == session.getPlayerEntity().getEntityId()) {
|
||||
attachedToId = session.getPlayerEntity();
|
||||
} else {
|
||||
attachedToId = session.getEntityCache().getEntityByJavaId(packet.getAttachedToId());
|
||||
if ((attachedToId == null || packet.getAttachedToId() == 0)) {
|
||||
// Is not being leashed
|
||||
mobEntity.setFlag(EntityFlag.LEASHED, false);
|
||||
mobEntity.setLeashHolderBedrockId(-1L);
|
||||
mobEntity.updateBedrockMetadata();
|
||||
EntityEventPacket eventPacket = new EntityEventPacket();
|
||||
eventPacket.setRuntimeEntityId(holderId.getGeyserId());
|
||||
eventPacket.setType(EntityEventType.REMOVE_LEASH);
|
||||
eventPacket.setData(0);
|
||||
session.sendUpstreamPacket(eventPacket);
|
||||
return;
|
||||
}
|
||||
Entity attachedToId = session.getEntityCache().getEntityByJavaId(packet.getAttachedToId());
|
||||
if (attachedToId == null || packet.getAttachedToId() == 0) {
|
||||
// Is not being leashed
|
||||
mobEntity.setFlag(EntityFlag.LEASHED, false);
|
||||
mobEntity.setLeashHolderBedrockId(-1L);
|
||||
mobEntity.updateBedrockMetadata();
|
||||
EntityEventPacket eventPacket = new EntityEventPacket();
|
||||
eventPacket.setRuntimeEntityId(holderId.getGeyserId());
|
||||
eventPacket.setType(EntityEventType.REMOVE_LEASH);
|
||||
eventPacket.setData(0);
|
||||
session.sendUpstreamPacket(eventPacket);
|
||||
return;
|
||||
}
|
||||
|
||||
mobEntity.setFlag(EntityFlag.LEASHED, true);
|
||||
|
@ -41,17 +41,12 @@ public class JavaSetEntityMotionTranslator extends PacketTranslator<ClientboundS
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundSetEntityMotionPacket packet) {
|
||||
Entity entity;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (entity == null) return;
|
||||
|
||||
entity.setMotion(Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ()));
|
||||
|
||||
if (entity == session.getRidingVehicleEntity() && entity instanceof AbstractHorseEntity) {
|
||||
if (entity == session.getPlayerEntity().getVehicle() && entity instanceof AbstractHorseEntity) {
|
||||
// Horses for some reason teleport back when a SetEntityMotionPacket is sent while
|
||||
// a player is riding on them. Java clients seem to ignore it anyways.
|
||||
return;
|
||||
|
@ -44,13 +44,7 @@ public class JavaSetEquipmentTranslator extends PacketTranslator<ClientboundSetE
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundSetEquipmentPacket packet) {
|
||||
Entity entity;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (entity == null)
|
||||
return;
|
||||
|
||||
|
@ -29,100 +29,73 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.Client
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.geyser.util.EntityUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Translator(packet = ClientboundSetPassengersPacket.class)
|
||||
public class JavaSetPassengersTranslator extends PacketTranslator<ClientboundSetPassengersPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundSetPassengersPacket packet) {
|
||||
Entity entity;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (entity == null) return;
|
||||
|
||||
LongOpenHashSet passengers = entity.getPassengers().clone();
|
||||
boolean rider = true;
|
||||
// Handle new/existing passengers
|
||||
List<Entity> newPassengers = new ArrayList<>();
|
||||
for (long passengerId : packet.getPassengerIds()) {
|
||||
Entity passenger = session.getEntityCache().getEntityByJavaId(passengerId);
|
||||
if (passengerId == session.getPlayerEntity().getEntityId()) {
|
||||
passenger = session.getPlayerEntity();
|
||||
session.setRidingVehicleEntity(entity);
|
||||
if (passenger == session.getPlayerEntity()) {
|
||||
session.getPlayerEntity().setVehicle(entity);
|
||||
// We need to confirm teleports before entering a vehicle, or else we will likely exit right out
|
||||
session.confirmTeleport(passenger.getPosition().sub(0, EntityDefinitions.PLAYER.offset(), 0).toDouble());
|
||||
}
|
||||
// Passenger hasn't loaded in (likely since we're waiting for a skin response)
|
||||
// and entity link needs to be set later
|
||||
if (passenger == null && passengerId != 0) {
|
||||
session.getEntityCache().addCachedPlayerEntityLink(passengerId, packet.getEntityId());
|
||||
}
|
||||
if (passenger == null) {
|
||||
// Can occur if the passenger is outside the client's tracking range
|
||||
// In this case, another SetPassengers packet will be sent when the passenger is spawned.
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean rider = packet.getPassengerIds()[0] == passengerId;
|
||||
EntityLinkData.Type type = rider ? EntityLinkData.Type.RIDER : EntityLinkData.Type.PASSENGER;
|
||||
SetEntityLinkPacket linkPacket = new SetEntityLinkPacket();
|
||||
linkPacket.setEntityLink(new EntityLinkData(entity.getGeyserId(), passenger.getGeyserId(), type, false));
|
||||
linkPacket.setEntityLink(new EntityLinkData(entity.getGeyserId(), passenger.getGeyserId(), type, false, false));
|
||||
session.sendUpstreamPacket(linkPacket);
|
||||
passengers.add(passengerId);
|
||||
|
||||
// Head rotation on boats
|
||||
if (entity.getDefinition() == EntityDefinitions.BOAT) {
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 1);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 90f);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_MIN_ROTATION, 1f);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_OFFSET, -90f);
|
||||
} else {
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 0);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 0f);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_MIN_ROTATION, 0f);
|
||||
}
|
||||
|
||||
passenger.updateBedrockMetadata();
|
||||
rider = false;
|
||||
}
|
||||
|
||||
entity.setPassengers(passengers);
|
||||
|
||||
for (long passengerId : entity.getPassengers()) {
|
||||
Entity passenger = session.getEntityCache().getEntityByJavaId(passengerId);
|
||||
if (passengerId == session.getPlayerEntity().getEntityId()) {
|
||||
passenger = session.getPlayerEntity();
|
||||
}
|
||||
if (passenger == null) {
|
||||
continue;
|
||||
}
|
||||
if (Arrays.stream(packet.getPassengerIds()).noneMatch(id -> id == passengerId)) {
|
||||
SetEntityLinkPacket linkPacket = new SetEntityLinkPacket();
|
||||
linkPacket.setEntityLink(new EntityLinkData(entity.getGeyserId(), passenger.getGeyserId(), EntityLinkData.Type.REMOVE, false));
|
||||
session.sendUpstreamPacket(linkPacket);
|
||||
passengers.remove(passenger.getEntityId());
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 0);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 0f);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_MIN_ROTATION, 0f);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_OFFSET, 0f);
|
||||
|
||||
EntityUtils.updateMountOffset(passenger, entity, false, false, (packet.getPassengerIds().length > 1));
|
||||
} else {
|
||||
EntityUtils.updateMountOffset(passenger, entity, (packet.getPassengerIds()[0] == passengerId), true, (packet.getPassengerIds().length > 1));
|
||||
}
|
||||
newPassengers.add(passenger);
|
||||
|
||||
passenger.setVehicle(entity);
|
||||
EntityUtils.updateRiderRotationLock(passenger, entity, true);
|
||||
EntityUtils.updateMountOffset(passenger, entity, rider, true, (packet.getPassengerIds().length > 1));
|
||||
// Force an update to the passenger metadata
|
||||
passenger.updateBedrockMetadata();
|
||||
}
|
||||
|
||||
// Handle passengers that were removed
|
||||
for (Entity passenger : entity.getPassengers()) {
|
||||
if (passenger == null) {
|
||||
continue;
|
||||
}
|
||||
if (!newPassengers.contains(passenger)) {
|
||||
SetEntityLinkPacket linkPacket = new SetEntityLinkPacket();
|
||||
linkPacket.setEntityLink(new EntityLinkData(entity.getGeyserId(), passenger.getGeyserId(), EntityLinkData.Type.REMOVE, false, false));
|
||||
session.sendUpstreamPacket(linkPacket);
|
||||
|
||||
passenger.setVehicle(null);
|
||||
EntityUtils.updateRiderRotationLock(passenger, entity, false);
|
||||
EntityUtils.updateMountOffset(passenger, entity, false, false, (packet.getPassengerIds().length > 1));
|
||||
// Force an update to the passenger metadata
|
||||
passenger.updateBedrockMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
entity.setPassengers(newPassengers);
|
||||
|
||||
switch (entity.getDefinition().entityType()) {
|
||||
case HORSE, SKELETON_HORSE, DONKEY, MULE, RAVAGER -> {
|
||||
entity.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 181.0f);
|
||||
|
@ -49,12 +49,7 @@ public class JavaTakeItemEntityTranslator extends PacketTranslator<ClientboundTa
|
||||
Entity collectedEntity = session.getEntityCache().getEntityByJavaId(packet.getCollectedEntityId());
|
||||
if (collectedEntity == null) return;
|
||||
// Collector is the entity 'picking up' the item
|
||||
Entity collectorEntity;
|
||||
if (packet.getCollectorEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
collectorEntity = session.getPlayerEntity();
|
||||
} else {
|
||||
collectorEntity = session.getEntityCache().getEntityByJavaId(packet.getCollectorEntityId());
|
||||
}
|
||||
Entity collectorEntity = session.getEntityCache().getEntityByJavaId(packet.getCollectorEntityId());
|
||||
if (collectorEntity == null) return;
|
||||
if (collectedEntity instanceof ExpOrbEntity) {
|
||||
// Player just picked up an experience orb
|
||||
|
@ -38,9 +38,6 @@ public class JavaTeleportEntityTranslator extends PacketTranslator<ClientboundTe
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundTeleportEntityPacket packet) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
}
|
||||
if (entity == null) return;
|
||||
|
||||
entity.teleport(Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), packet.isOnGround());
|
||||
|
@ -37,12 +37,7 @@ public class JavaUpdateAttributesTranslator extends PacketTranslator<Clientbound
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundUpdateAttributesPacket packet) {
|
||||
Entity entity;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (!(entity instanceof LivingEntity livingEntity)) return;
|
||||
|
||||
livingEntity.updateBedrockAttributes(session, packet.getAttributes());
|
||||
|
@ -38,12 +38,9 @@ public class JavaUpdateMobEffectTranslator extends PacketTranslator<ClientboundU
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundUpdateMobEffectPacket packet) {
|
||||
Entity entity;
|
||||
if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||
entity = session.getPlayerEntity();
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (entity == session.getPlayerEntity()) {
|
||||
session.getEffectCache().setEffect(packet.getEffect(), packet.getAmplifier());
|
||||
} else {
|
||||
entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
}
|
||||
if (entity == null)
|
||||
return;
|
||||
|
@ -28,22 +28,22 @@ package org.geysermc.geyser.translator.protocol.java.entity.player;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PositionElement;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData;
|
||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.RespawnPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.type.player.PlayerEntity;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.type.player.SessionPlayerEntity;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.TeleportCache;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
import org.geysermc.geyser.util.ChunkUtils;
|
||||
import org.geysermc.geyser.util.EntityUtils;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
|
||||
@Translator(packet = ClientboundPlayerPositionPacket.class)
|
||||
public class JavaPlayerPositionTranslator extends PacketTranslator<ClientboundPlayerPositionPacket> {
|
||||
@ -53,9 +53,10 @@ public class JavaPlayerPositionTranslator extends PacketTranslator<ClientboundPl
|
||||
if (!session.isLoggedIn())
|
||||
return;
|
||||
|
||||
PlayerEntity entity = session.getPlayerEntity();
|
||||
SessionPlayerEntity entity = session.getPlayerEntity();
|
||||
|
||||
if (!session.isSpawned()) {
|
||||
// The server sends an absolute teleport everytime the player is respawned
|
||||
Vector3f pos = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
|
||||
entity.setPosition(pos);
|
||||
entity.setYaw(packet.getYaw());
|
||||
@ -78,9 +79,10 @@ public class JavaPlayerPositionTranslator extends PacketTranslator<ClientboundPl
|
||||
|
||||
session.sendUpstreamPacket(movePlayerPacket);
|
||||
session.setSpawned(true);
|
||||
// Make sure the player moves away from (0, 32767, 0) before accepting movement packets
|
||||
session.setUnconfirmedTeleport(new TeleportCache(packet.getX(), packet.getY(), packet.getZ(), packet.getPitch(), packet.getYaw(), packet.getTeleportId()));
|
||||
|
||||
ServerboundAcceptTeleportationPacket teleportConfirmPacket = new ServerboundAcceptTeleportationPacket(packet.getTeleportId());
|
||||
session.sendDownstreamPacket(teleportConfirmPacket);
|
||||
acceptTeleport(session, packet.getX(), packet.getY(), packet.getZ(), packet.getYaw(), packet.getPitch(), packet.getTeleportId());
|
||||
|
||||
ChunkUtils.updateChunkPosition(session, pos.toInt());
|
||||
|
||||
@ -88,22 +90,19 @@ public class JavaPlayerPositionTranslator extends PacketTranslator<ClientboundPl
|
||||
return;
|
||||
}
|
||||
|
||||
session.setSpawned(true);
|
||||
Entity vehicle = session.getPlayerEntity().getVehicle();
|
||||
if (packet.isDismountVehicle() && vehicle != null) {
|
||||
|
||||
if (packet.isDismountVehicle() && session.getRidingVehicleEntity() != null) {
|
||||
Entity vehicle = session.getRidingVehicleEntity();
|
||||
SetEntityLinkPacket linkPacket = new SetEntityLinkPacket();
|
||||
linkPacket.setEntityLink(new EntityLinkData(vehicle.getGeyserId(), entity.getGeyserId(), EntityLinkData.Type.REMOVE, false, false));
|
||||
session.sendUpstreamPacket(linkPacket);
|
||||
vehicle.getPassengers().remove(entity.getEntityId());
|
||||
entity.getDirtyMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 0);
|
||||
entity.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 0f);
|
||||
entity.getDirtyMetadata().put(EntityData.RIDER_MIN_ROTATION, 0f);
|
||||
entity.getDirtyMetadata().put(EntityData.RIDER_ROTATION_OFFSET, 0f);
|
||||
session.setRidingVehicleEntity(null);
|
||||
entity.updateBedrockMetadata();
|
||||
|
||||
EntityUtils.updateMountOffset(entity, vehicle, false, false, entity.getPassengers().size() > 1);
|
||||
vehicle.getPassengers().remove(entity);
|
||||
session.getPlayerEntity().setVehicle(null);
|
||||
|
||||
EntityUtils.updateRiderRotationLock(entity, null, false);
|
||||
EntityUtils.updateMountOffset(entity, null, false, false, entity.getPassengers().size() > 1);
|
||||
entity.updateBedrockMetadata();
|
||||
}
|
||||
|
||||
// If coordinates are relative, then add to the existing coordinate
|
||||
@ -119,9 +118,9 @@ public class JavaPlayerPositionTranslator extends PacketTranslator<ClientboundPl
|
||||
float newYaw = packet.getYaw() +
|
||||
(packet.getRelative().contains(PositionElement.YAW) ? entity.getBedrockRotation().getY() : 0);
|
||||
|
||||
session.getGeyser().getLogger().debug("Teleport from " + entity.getPosition().getX() + " " + (entity.getPosition().getY() - EntityDefinitions.PLAYER.offset()) + " " + entity.getPosition().getZ());
|
||||
int id = packet.getTeleportId();
|
||||
|
||||
session.addTeleport(new TeleportCache(newX, newY, newZ, newPitch, newYaw, packet.getTeleportId()));
|
||||
session.getGeyser().getLogger().debug("Teleport (" + id + ") from " + entity.getPosition().getX() + " " + (entity.getPosition().getY() - EntityDefinitions.PLAYER.offset()) + " " + entity.getPosition().getZ());
|
||||
|
||||
Vector3f lastPlayerPosition = entity.getPosition().down(EntityDefinitions.PLAYER.offset());
|
||||
float lastPlayerPitch = entity.getBedrockRotation().getX();
|
||||
@ -131,9 +130,22 @@ public class JavaPlayerPositionTranslator extends PacketTranslator<ClientboundPl
|
||||
session.getGeyser().getLogger().debug("to " + entity.getPosition().getX() + " " + (entity.getPosition().getY() - EntityDefinitions.PLAYER.offset()) + " " + entity.getPosition().getZ());
|
||||
|
||||
// Bedrock ignores teleports that are extremely close to the player's original position and orientation,
|
||||
// so check if we can immediately confirm the teleport
|
||||
// so check if we need to cache the teleport
|
||||
if (lastPlayerPosition.distanceSquared(teleportDestination) < 0.001 && Math.abs(newPitch - lastPlayerPitch) < 5) {
|
||||
session.confirmTeleport(lastPlayerPosition.toDouble());
|
||||
session.setUnconfirmedTeleport(null);
|
||||
} else {
|
||||
session.setUnconfirmedTeleport(new TeleportCache(newX, newY, newZ, newPitch, newYaw, id));
|
||||
}
|
||||
|
||||
acceptTeleport(session, newX, newY, newZ, newYaw, newPitch, id);
|
||||
}
|
||||
|
||||
private void acceptTeleport(GeyserSession session, double x, double y, double z, float yaw, float pitch, int id) {
|
||||
// Confirm the teleport when we receive it to match Java edition
|
||||
ServerboundAcceptTeleportationPacket teleportConfirmPacket = new ServerboundAcceptTeleportationPacket(id);
|
||||
session.sendDownstreamPacket(teleportConfirmPacket);
|
||||
// Servers (especially ones like Hypixel) expect exact coordinates given back to them.
|
||||
ServerboundMovePlayerPosRotPacket positionPacket = new ServerboundMovePlayerPosRotPacket(false, x, y, z, yaw, pitch);
|
||||
session.sendDownstreamPacket(positionPacket);
|
||||
}
|
||||
}
|
||||
|
@ -71,12 +71,7 @@ public class JavaAddEntityTranslator extends PacketTranslator<ClientboundAddEnti
|
||||
} else if (packet.getType() == EntityType.FISHING_BOBBER) {
|
||||
// Fishing bobbers need the owner for the line
|
||||
int ownerEntityId = ((ProjectileData) packet.getData()).getOwnerId();
|
||||
Entity owner;
|
||||
if (session.getPlayerEntity().getEntityId() == ownerEntityId) {
|
||||
owner = session.getPlayerEntity();
|
||||
} else {
|
||||
owner = session.getEntityCache().getEntityByJavaId(ownerEntityId);
|
||||
}
|
||||
Entity owner = session.getEntityCache().getEntityByJavaId(ownerEntityId);
|
||||
// Java clients only spawn fishing hooks with a player as its owner
|
||||
if (owner instanceof PlayerEntity) {
|
||||
entity = new FishingHookEntity(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), packet.getUuid(),
|
||||
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.util;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.Effect;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
@ -74,7 +75,7 @@ public final class EntityUtils {
|
||||
switch (mount.getDefinition().entityType()) {
|
||||
case CHICKEN, SPIDER -> mountedHeightOffset = height * 0.5f;
|
||||
case DONKEY, MULE -> mountedHeightOffset -= 0.25f;
|
||||
case LLAMA -> mountedHeightOffset = height * 0.67f;
|
||||
case TRADER_LLAMA, LLAMA -> mountedHeightOffset = height * 0.6f;
|
||||
case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART,
|
||||
COMMAND_BLOCK_MINECART -> mountedHeightOffset = 0;
|
||||
case BOAT -> mountedHeightOffset = -0.1f;
|
||||
@ -144,20 +145,22 @@ public final class EntityUtils {
|
||||
float yOffset = mountedHeightOffset + heightOffset;
|
||||
float zOffset = 0;
|
||||
switch (mount.getDefinition().entityType()) {
|
||||
case BOAT:
|
||||
case BOAT -> {
|
||||
// Without the X offset, more than one entity on a boat is stacked on top of each other
|
||||
if (rider && moreThanOneEntity) {
|
||||
xOffset = 0.2f;
|
||||
} else if (moreThanOneEntity) {
|
||||
xOffset = -0.6f;
|
||||
}
|
||||
break;
|
||||
case CHICKEN:
|
||||
zOffset = -0.1f;
|
||||
break;
|
||||
case LLAMA:
|
||||
zOffset = -0.3f;
|
||||
break;
|
||||
}
|
||||
case CHICKEN -> zOffset = -0.1f;
|
||||
case TRADER_LLAMA, LLAMA -> zOffset = -0.3f;
|
||||
}
|
||||
if (passenger.getDefinition().entityType() == EntityType.SHULKER) {
|
||||
switch (mount.getDefinition().entityType()) {
|
||||
case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART,
|
||||
COMMAND_BLOCK_MINECART, BOAT -> yOffset = 0.1875f;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Bedrock Differences
|
||||
@ -165,8 +168,10 @@ public final class EntityUtils {
|
||||
* Horses are tinier
|
||||
* Players, Minecarts, and Boats have different origins
|
||||
*/
|
||||
if (passenger.getDefinition().entityType() == EntityType.PLAYER && mount.getDefinition().entityType() != EntityType.PLAYER) {
|
||||
yOffset += EntityDefinitions.PLAYER.offset();
|
||||
if (passenger.getDefinition().entityType() == EntityType.PLAYER) {
|
||||
if (mount.getDefinition().entityType() != EntityType.PLAYER && mount.getDefinition().entityType() != EntityType.AREA_EFFECT_CLOUD) {
|
||||
yOffset += EntityDefinitions.PLAYER.offset();
|
||||
}
|
||||
}
|
||||
switch (mount.getDefinition().entityType()) {
|
||||
case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART,
|
||||
@ -175,7 +180,21 @@ public final class EntityUtils {
|
||||
Vector3f offset = Vector3f.from(xOffset, yOffset, zOffset);
|
||||
passenger.setRiderSeatPosition(offset);
|
||||
}
|
||||
passenger.updateBedrockMetadata();
|
||||
}
|
||||
|
||||
public static void updateRiderRotationLock(Entity passenger, Entity mount, boolean isRiding) {
|
||||
if (isRiding && mount.getDefinition() == EntityDefinitions.BOAT) {
|
||||
// Head rotation is locked while riding in a boat
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 1);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 90f);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_MIN_ROTATION, 1f);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_OFFSET, -90f);
|
||||
} else {
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 0);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 0f);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_MIN_ROTATION, 0f);
|
||||
passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_OFFSET, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
private EntityUtils() {
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren