forked from GeyserMC/Geyser
Merge entity mounts branch to master (#589)
* Initial support for entity mounts* * This only works for viewing other players on mounts/vehicles. Currently, mounting on vehicles through Geyser with bedrock does not work at all, though, you can see other Java players on mounts just fine. * Fix Bedrock player mounting; add minecart offset * Remove debug code * Fix boat animation * Remove debug code * Add notice of possible steering flip * Add translator for PlayerInputPacket * Upload WIP code for BoatEntity.java * Add animation for rowing on Bedrock side * Clean up debug code, start on boat movement * Add notice about flying horses * Rename BedrockPlayerInputPacket.java to BedrockPlayerInputTranslator.java * Delete BedrockPlayerInputPacket.java * Use Translator Annotation again; Thanks to LegacyGamerHD * Upload ineffective mount-on-login code * Upload current changes with no debug code * Change case where applicable * Change Integer[] to int[]; Change schedule() to execute() * Don't use Thread.Sleep() and instead call itself again * Fix players not being linked on login/chunk load * Little changes * Minor improvements/fixes to boats * Remove empty file * Fix horse flying. * Various entity mounting fixes * Add mounting offsets for skeleton and zombie horses * Another round of entity mount-related fixes - Add offsets for skeleton and zombie horses (Thanks to tester DirtNasty) - Boats can now be placed in survival (Thanks again to tester DirtNasty) - Boats and minecarts can now shake * Add translating for ServerVehicleMovePacket * Cleaning up * More cleaning up * Add interactive tag support for mountable entities * Boats move far more nicely * Add horse heart visuals * Update interactive tags Co-authored-by: RednedEpic <redned235@gmail.com>
This commit is contained in:
parent
d8d9fb7190
commit
59da87a10f
20 changed files with 599 additions and 14 deletions
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BoatEntity extends Entity {
|
||||
|
||||
private boolean isPaddlingLeft;
|
||||
private float paddleTimeLeft;
|
||||
private boolean isPaddlingRight;
|
||||
private float paddleTimeRight;
|
||||
|
||||
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
|
||||
private final float ROWING_SPEED = 0.05f;
|
||||
|
||||
public BoatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation.add(0, 0, 90));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||
// Rotation is basically only called when entering/exiting a boat.
|
||||
// We don't include the rotation (y) as it causes the boat to appear sideways
|
||||
super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), Vector3f.from(0, 0, rotation.getZ() + 90), isOnGround, teleported);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) {
|
||||
super.moveRelative(session, relX, relY, relZ, Vector3f.from(0, 0, rotation.getZ()), isOnGround);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
||||
// Time since last hit
|
||||
if (entityMetadata.getId() == 7) {
|
||||
metadata.put(EntityData.HURT_TIME, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// Rocking direction
|
||||
if (entityMetadata.getId() == 8) {
|
||||
metadata.put(EntityData.HURT_DIRECTION, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// 'Health' in Bedrock, damage taken in Java
|
||||
if (entityMetadata.getId() == 9) {
|
||||
// Not exactly health but it makes motion in Bedrock
|
||||
metadata.put(EntityData.HEALTH, 40 - ((int) (float) entityMetadata.getValue()));
|
||||
}
|
||||
|
||||
if (entityMetadata.getId() == 10) {
|
||||
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||
} else if (entityMetadata.getId() == 11) {
|
||||
isPaddlingLeft = (boolean) entityMetadata.getValue();
|
||||
if (!isPaddlingLeft) {
|
||||
metadata.put(EntityData.PADDLE_TIME_LEFT, 0f);
|
||||
}
|
||||
else {
|
||||
// Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
|
||||
// This is an asynchronous method that emulates Bedrock rowing until "false" is sent.
|
||||
paddleTimeLeft = 0f;
|
||||
session.getConnector().getGeneralThreadPool().execute(() ->
|
||||
updateLeftPaddle(session, entityMetadata)
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (entityMetadata.getId() == 12) {
|
||||
isPaddlingRight = (boolean) entityMetadata.getValue();
|
||||
if (!isPaddlingRight) {
|
||||
metadata.put(EntityData.PADDLE_TIME_RIGHT, 0f);
|
||||
} else {
|
||||
paddleTimeRight = 0f;
|
||||
session.getConnector().getGeneralThreadPool().execute(() ->
|
||||
updateRightPaddle(session, entityMetadata)
|
||||
);
|
||||
}
|
||||
} else if (entityMetadata.getId() == 13) {
|
||||
// Possibly - I don't think this does anything?
|
||||
metadata.put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
public void updateLeftPaddle(GeyserSession session, EntityMetadata entityMetadata) {
|
||||
if (isPaddlingLeft) {
|
||||
paddleTimeLeft += ROWING_SPEED;
|
||||
metadata.put(EntityData.PADDLE_TIME_LEFT, paddleTimeLeft);
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||
updateLeftPaddle(session, entityMetadata),
|
||||
100,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}}
|
||||
|
||||
public void updateRightPaddle(GeyserSession session, EntityMetadata entityMetadata) {
|
||||
if (isPaddlingRight) {
|
||||
paddleTimeRight += ROWING_SPEED;
|
||||
metadata.put(EntityData.PADDLE_TIME_RIGHT, paddleTimeRight);
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
session.getConnector().getGeneralThreadPool().schedule(() ->
|
||||
updateRightPaddle(session, entityMetadata),
|
||||
100,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
}}
|
||||
}
|
|
@ -44,7 +44,6 @@ import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
|||
import com.nukkitx.protocol.bedrock.data.EntityFlags;
|
||||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.entity.attribute.Attribute;
|
||||
|
@ -85,7 +84,7 @@ public class Entity {
|
|||
|
||||
protected boolean valid;
|
||||
|
||||
protected LongSet passengers = new LongOpenHashSet();
|
||||
protected LongOpenHashSet passengers = new LongOpenHashSet();
|
||||
protected Map<AttributeType, Attribute> attributes = new HashMap<>();
|
||||
protected EntityDataMap metadata = new EntityDataMap();
|
||||
|
||||
|
|
|
@ -25,12 +25,40 @@
|
|||
|
||||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public class MinecartEntity extends Entity {
|
||||
|
||||
public MinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
||||
if (entityMetadata.getId() == 7) {
|
||||
metadata.put(EntityData.HEALTH, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// Direction in which the minecart is shaking
|
||||
if (entityMetadata.getId() == 8) {
|
||||
metadata.put(EntityData.HURT_DIRECTION, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// Power in Java, time in Bedrock
|
||||
if (entityMetadata.getId() == 9) {
|
||||
metadata.put(EntityData.HURT_TIME, Math.min((int) (float) entityMetadata.getValue(), 15));
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
|
||||
super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), rotation, isOnGround, teleported);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,6 +97,11 @@ public class PlayerEntity extends LivingEntity {
|
|||
addPlayerPacket.setPlatformChatId("");
|
||||
addPlayerPacket.getMetadata().putAll(metadata);
|
||||
|
||||
long linkedEntityId = session.getEntityCache().getCachedPlayerEntityLink(entityId);
|
||||
if (linkedEntityId != -1) {
|
||||
addPlayerPacket.getEntityLinks().add(new EntityLink(session.getEntityCache().getEntityByJavaId(linkedEntityId).getGeyserId(), geyserId, EntityLink.Type.RIDER, false));
|
||||
}
|
||||
|
||||
valid = true;
|
||||
session.sendUpstreamPacket(addPlayerPacket);
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ public enum AttributeType {
|
|||
MOVEMENT_SPEED("generic.movementSpeed", "minecraft:movement", 0f, 1024f, 0.1f),
|
||||
FLYING_SPEED("generic.flyingSpeed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f),
|
||||
ATTACK_DAMAGE("generic.attackDamage", "minecraft:attack_damage", 0f, 2048f, 1f),
|
||||
HORSE_JUMP_STRENGTH("horse.jumpStrength", "minecraft:horse.jump_strength", 0.0f, 2.0f, 0.7f),
|
||||
|
||||
// Java Attributes
|
||||
ARMOR("generic.armor", null, 0f, 30f, 0f),
|
||||
|
|
|
@ -27,25 +27,69 @@ package org.geysermc.connector.entity.living.animal.horse;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.Attribute;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import org.geysermc.connector.entity.attribute.AttributeType;
|
||||
import org.geysermc.connector.entity.living.animal.AnimalEntity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.AttributeUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AbstractHorseEntity extends AnimalEntity {
|
||||
|
||||
// For updating the horse visual easier
|
||||
private float health = 20f;
|
||||
|
||||
public AbstractHorseEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
||||
if (entityMetadata.getId() == 8) {
|
||||
health = (float) entityMetadata.getValue();
|
||||
updateBedrockAttributes(session);
|
||||
}
|
||||
|
||||
if (entityMetadata.getId() == 16) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x02) == 0x02);
|
||||
metadata.getFlags().setFlag(EntityFlag.SADDLED, (xd & 0x04) == 0x04);
|
||||
metadata.getFlags().setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10);
|
||||
metadata.getFlags().setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20);
|
||||
}
|
||||
|
||||
// Needed to control horses
|
||||
metadata.getFlags().setFlag(EntityFlag.CAN_POWER_JUMP, true);
|
||||
metadata.getFlags().setFlag(EntityFlag.WASD_CONTROLLED, true);
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockAttributes(GeyserSession session) {
|
||||
if (!valid) return;
|
||||
|
||||
float maxHealth = attributes.containsKey(AttributeType.MAX_HEALTH) ? attributes.get(AttributeType.MAX_HEALTH).getValue() : 20f;
|
||||
|
||||
List<com.nukkitx.protocol.bedrock.data.Attribute> attributesLocal = new ArrayList<>();
|
||||
for (Map.Entry<AttributeType, org.geysermc.connector.entity.attribute.Attribute> entry : this.attributes.entrySet()) {
|
||||
if (!entry.getValue().getType().isBedrockAttribute())
|
||||
continue;
|
||||
|
||||
attributesLocal.add(AttributeUtils.getBedrockAttribute(entry.getValue()));
|
||||
}
|
||||
attributesLocal.add(new Attribute("minecraft:health", 0.0f, maxHealth, health, maxHealth));
|
||||
|
||||
UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket();
|
||||
updateAttributesPacket.setRuntimeEntityId(geyserId);
|
||||
updateAttributesPacket.setAttributes(attributesLocal);
|
||||
session.sendUpstreamPacket(updateAttributesPacket);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.entity.living.animal.horse;
|
|||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
|
@ -41,8 +42,9 @@ public class HorseEntity extends AbstractHorseEntity {
|
|||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 18) {
|
||||
metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue());
|
||||
metadata.put(EntityData.MARK_VARIANT, (((int) entityMetadata.getValue()) >> 8) % 5);
|
||||
}
|
||||
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
}
|
|
@ -119,22 +119,22 @@ public enum EntityType {
|
|||
SNOWBALL(ThrowableEntity.class, 81, 0.25f),
|
||||
THROWN_EGG(ThrowableEntity.class, 82, 0.25f, 0.25f, 0.25f, 0f, "minecraft:egg"),
|
||||
PAINTING(PaintingEntity.class, 83, 0f),
|
||||
MINECART(MinecartEntity.class, 84, 0.7f, 0.98f),
|
||||
MINECART(MinecartEntity.class, 84, 0.7f, 0.98f, 0.98f, 0.35f),
|
||||
FIREBALL(ItemedFireballEntity.class, 85, 1.0f),
|
||||
THROWN_POTION(ThrowableEntity.class, 86, 0.25f, 0.25f, 0.25f, 0f, "minecraft:splash_potion"),
|
||||
THROWN_ENDERPEARL(ThrowableEntity.class, 87, 0.25f, 0.25f, 0.25f, 0f, "minecraft:ender_pearl"),
|
||||
LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f),
|
||||
WITHER_SKULL(Entity.class, 89, 0.3125f),
|
||||
BOAT(Entity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f),
|
||||
BOAT(BoatEntity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f),
|
||||
WITHER_SKULL_DANGEROUS(Entity.class, 91, 0f),
|
||||
LIGHTNING_BOLT(Entity.class, 93, 0f),
|
||||
SMALL_FIREBALL(ItemedFireballEntity.class, 94, 0.3125f),
|
||||
AREA_EFFECT_CLOUD(AreaEffectCloudEntity.class, 95, 0.5f, 1.0f),
|
||||
MINECART_HOPPER(MinecartEntity.class, 96, 0.7f, 0.98f, 0.98f, 0f, "minecraft:hopper_minecart"),
|
||||
MINECART_TNT(MinecartEntity.class, 97, 0.7f, 0.98f, 0.98f, 0f, "minecraft:tnt_minecart"),
|
||||
MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0f, "minecraft:chest_minecart"),
|
||||
MINECART_HOPPER(MinecartEntity.class, 96, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:hopper_minecart"),
|
||||
MINECART_TNT(MinecartEntity.class, 97, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:tnt_minecart"),
|
||||
MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:chest_minecart"),
|
||||
|
||||
MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0f, "minecraft:command_block_minecart"),
|
||||
MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"),
|
||||
LINGERING_POTION(ThrowableEntity.class, 101, 0f),
|
||||
LLAMA_SPIT(Entity.class, 102, 0.25f),
|
||||
EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f),
|
||||
|
|
|
@ -58,6 +58,7 @@ import org.geysermc.common.AuthType;
|
|||
import org.geysermc.common.window.FormWindow;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.PlayerEntity;
|
||||
import org.geysermc.connector.inventory.PlayerInventory;
|
||||
import org.geysermc.connector.network.remote.RemoteServer;
|
||||
|
@ -157,6 +158,9 @@ public class GeyserSession implements CommandSender {
|
|||
private boolean manyDimPackets = false;
|
||||
private ServerRespawnPacket lastDimPacket = null;
|
||||
|
||||
@Setter
|
||||
private Entity ridingVehicleEntity;
|
||||
|
||||
@Setter
|
||||
private int craftSlot = 0;
|
||||
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
package org.geysermc.connector.network.session.cache;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.*;
|
||||
import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
|
@ -49,6 +47,7 @@ public class EntityCache {
|
|||
private Long2LongMap entityIdTranslations = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
|
||||
private Map<UUID, PlayerEntity> playerEntities = Collections.synchronizedMap(new HashMap<>());
|
||||
private Map<UUID, BossBar> bossBars = Collections.synchronizedMap(new HashMap<>());
|
||||
private Long2LongMap cachedPlayerEntityLinks = Long2LongMaps.synchronize(new Long2LongOpenHashMap());
|
||||
|
||||
@Getter
|
||||
private AtomicLong nextEntityId = new AtomicLong(2L);
|
||||
|
@ -148,4 +147,12 @@ public class EntityCache {
|
|||
playerEntities = null;
|
||||
bossBars = null;
|
||||
}
|
||||
|
||||
public long getCachedPlayerEntityLink(long playerId) {
|
||||
return cachedPlayerEntityLinks.getOrDefault(playerId, -1);
|
||||
}
|
||||
|
||||
public void addCachedPlayerEntityLink(long playerId, long linkedEntityId) {
|
||||
cachedPlayerEntityLinks.put(playerId, linkedEntityId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.geysermc.connector.network.translators.Translator;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerSwingArmPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientSteerBoatPacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.AnimatePacket;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -38,6 +39,9 @@ import java.util.concurrent.TimeUnit;
|
|||
@Translator(packet = AnimatePacket.class)
|
||||
public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
|
||||
|
||||
private boolean isSteeringLeft;
|
||||
private boolean isSteeringRight;
|
||||
|
||||
@Override
|
||||
public void translate(AnimatePacket packet, GeyserSession session) {
|
||||
// Stop the player sending animations before they have fully spawned into the server
|
||||
|
@ -54,6 +58,18 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
|
|||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
break;
|
||||
// These two might need to be flipped, but my recommendation is getting moving working first
|
||||
case ROW_LEFT:
|
||||
// Packet value is a float of how long one has been rowing, so we convert that into a boolean
|
||||
isSteeringLeft = packet.getRowingTime() > 0.0;
|
||||
ClientSteerBoatPacket steerLeftPacket = new ClientSteerBoatPacket(isSteeringRight, isSteeringLeft);
|
||||
session.sendDownstreamPacket(steerLeftPacket);
|
||||
break;
|
||||
case ROW_RIGHT:
|
||||
isSteeringRight = packet.getRowingTime() > 0.0;
|
||||
ClientSteerBoatPacket steerRightPacket = new ClientSteerBoatPacket(isSteeringRight, isSteeringLeft);
|
||||
session.sendDownstreamPacket(steerRightPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
|
@ -32,7 +34,9 @@ import org.geysermc.connector.network.translators.Translator;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket;
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.InteractPacket;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
|
||||
|
@ -59,6 +63,58 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
|||
InteractAction.ATTACK, Hand.MAIN_HAND);
|
||||
session.sendDownstreamPacket(attackPacket);
|
||||
break;
|
||||
case LEAVE_VEHICLE:
|
||||
ClientPlayerStatePacket sneakPacket = new ClientPlayerStatePacket((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
|
||||
if (packet.getRuntimeEntityId() != 0) {
|
||||
Entity interactEntity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId());
|
||||
if (interactEntity == null)
|
||||
return;
|
||||
|
||||
String interactiveTag;
|
||||
switch (interactEntity.getEntityType()) {
|
||||
case PIG:
|
||||
if (interactEntity.getMetadata().getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||
interactiveTag = "action.interact.mount";
|
||||
} else interactiveTag = "";
|
||||
break;
|
||||
case HORSE:
|
||||
case SKELETON_HORSE:
|
||||
case ZOMBIE_HORSE:
|
||||
case DONKEY:
|
||||
case MULE:
|
||||
case LLAMA:
|
||||
case TRADER_LLAMA:
|
||||
if (interactEntity.getMetadata().getFlags().getFlag(EntityFlag.TAMED)) {
|
||||
interactiveTag = "action.interact.ride.horse";
|
||||
} else {
|
||||
interactiveTag = "action.interact.mount";
|
||||
}
|
||||
break;
|
||||
case BOAT:
|
||||
interactiveTag = "action.interact.ride.boat";
|
||||
break;
|
||||
case MINECART:
|
||||
interactiveTag = "action.interact.ride.minecart";
|
||||
break;
|
||||
default:
|
||||
return; // No need to process any further since there is no interactive tag
|
||||
}
|
||||
session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag);
|
||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||
} else {
|
||||
if (!(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == null) ||
|
||||
!(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == "")) {
|
||||
// No interactive tag should be sent
|
||||
session.getPlayerEntity().getMetadata().remove(EntityData.INTERACTIVE_TAG);
|
||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,13 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(),
|
||||
false);
|
||||
session.sendDownstreamPacket(blockPacket);
|
||||
|
||||
// Otherwise boats will not be able to be placed in survival
|
||||
if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemTranslator.BOAT) {
|
||||
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||
session.sendDownstreamPacket(itemPacket);
|
||||
}
|
||||
|
||||
Vector3i blockPos = packet.getBlockPosition();
|
||||
// TODO: Find a better way to do this?
|
||||
switch (packet.getFace()) {
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientVehicleMovePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
// Used for horses
|
||||
@Translator(packet = MoveEntityAbsolutePacket.class)
|
||||
public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator<MoveEntityAbsolutePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(MoveEntityAbsolutePacket packet, GeyserSession session) {
|
||||
|
||||
ClientVehicleMovePacket clientVehicleMovePacket = new ClientVehicleMovePacket(
|
||||
packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ(),
|
||||
packet.getRotation().getY() - 90, packet.getRotation().getX()
|
||||
);
|
||||
session.sendDownstreamPacket(clientVehicleMovePacket);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.geysermc.connector.network.translators.bedrock;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientSteerVehiclePacket;
|
||||
import com.nukkitx.protocol.bedrock.packet.PlayerInputPacket;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
// Makes minecarts respond to player input
|
||||
@Translator(packet = PlayerInputPacket.class)
|
||||
public class BedrockPlayerInputTranslator extends PacketTranslator<PlayerInputPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(PlayerInputPacket packet, GeyserSession session) {
|
||||
ClientSteerVehiclePacket clientSteerVehiclePacket = new ClientSteerVehiclePacket(
|
||||
packet.getInputMotion().getX(), packet.getInputMotion().getY(), packet.isJumping(), packet.isSneaking()
|
||||
);
|
||||
|
||||
session.sendDownstreamPacket(clientSteerVehiclePacket);
|
||||
}
|
||||
}
|
|
@ -48,6 +48,8 @@ public class ItemTranslator {
|
|||
|
||||
// Shield ID, used in Entity.java
|
||||
public static final int SHIELD = 829;
|
||||
// Boat ID, used in BedrockInventoryTransactionTranslator.java
|
||||
public static final int BOAT = 333;
|
||||
|
||||
public void init() {
|
||||
Reflections ref = new Reflections("org.geysermc.connector.network.translators.item");
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
@ -42,7 +43,10 @@ public class JavaEntityPositionRotationTranslator extends PacketTranslator<Serve
|
|||
entity = session.getPlayerEntity();
|
||||
}
|
||||
if (entity == null) return;
|
||||
|
||||
if (entity.getEntityType() == EntityType.BOAT) {
|
||||
entity.moveRelative(session, packet.getMoveX(), packet.getMoveY(), packet.getMoveZ(), packet.getYaw() - 90, packet.getPitch(), packet.isOnGround());
|
||||
} else {
|
||||
entity.moveRelative(session, packet.getMoveX(), packet.getMoveY(), packet.getMoveZ(), packet.getYaw(), packet.getPitch(), packet.isOnGround());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,9 @@ public class JavaEntityPropertiesTranslator extends PacketTranslator<ServerEntit
|
|||
case GENERIC_KNOCKBACK_RESISTANCE:
|
||||
entity.getAttributes().put(AttributeType.KNOCKBACK_RESISTANCE, AttributeType.KNOCKBACK_RESISTANCE.getAttribute((float) AttributeUtils.calculateValue(attribute)));
|
||||
break;
|
||||
case HORSE_JUMP_STRENGTH:
|
||||
entity.getAttributes().put(AttributeType.HORSE_JUMP_STRENGTH, AttributeType.HORSE_JUMP_STRENGTH.getAttribute((float) AttributeUtils.calculateValue(attribute)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.java.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntitySetPassengersPacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityFlag;
|
||||
import com.nukkitx.protocol.bedrock.data.EntityLink;
|
||||
import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Translator(packet = ServerEntitySetPassengersPacket.class)
|
||||
public class JavaEntitySetPassengersTranslator extends PacketTranslator<ServerEntitySetPassengersPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerEntitySetPassengersPacket packet, GeyserSession session) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
|
||||
if (entity == null) return;
|
||||
|
||||
LongOpenHashSet passengers = entity.getPassengers().clone();
|
||||
boolean rider = true;
|
||||
for (long passengerId : packet.getPassengerIds()) {
|
||||
Entity passenger = session.getEntityCache().getEntityByJavaId(passengerId);
|
||||
if (passengerId == session.getPlayerEntity().getEntityId()) {
|
||||
passenger = session.getPlayerEntity();
|
||||
session.setRidingVehicleEntity(entity);
|
||||
}
|
||||
// Passenger hasn't loaded in and entity link needs to be set later
|
||||
if (passenger == null && passengerId != 0) {
|
||||
session.getEntityCache().addCachedPlayerEntityLink(passengerId, packet.getEntityId());
|
||||
}
|
||||
if (passenger == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EntityLink.Type type = rider ? EntityLink.Type.RIDER : EntityLink.Type.PASSENGER;
|
||||
SetEntityLinkPacket linkPacket = new SetEntityLinkPacket();
|
||||
linkPacket.setEntityLink(new EntityLink(entity.getGeyserId(), passenger.getGeyserId(), type, false));
|
||||
session.sendUpstreamPacket(linkPacket);
|
||||
passengers.add(passengerId);
|
||||
|
||||
// Head rotation on boats
|
||||
if (entity.getEntityType() == EntityType.BOAT) {
|
||||
passenger.getMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 1);
|
||||
passenger.getMetadata().put(EntityData.RIDER_MAX_ROTATION, 90f);
|
||||
passenger.getMetadata().put(EntityData.RIDER_MIN_ROTATION, !passengers.isEmpty() ? -90f : 0f);
|
||||
} else {
|
||||
passenger.getMetadata().remove(EntityData.RIDER_ROTATION_LOCKED);
|
||||
passenger.getMetadata().remove(EntityData.RIDER_MAX_ROTATION);
|
||||
passenger.getMetadata().remove(EntityData.RIDER_MIN_ROTATION);
|
||||
}
|
||||
|
||||
passenger.updateBedrockMetadata(session);
|
||||
this.updateOffset(passenger, entity.getEntityType(), session, rider, true);
|
||||
rider = false;
|
||||
}
|
||||
|
||||
entity.setPassengers(passengers);
|
||||
|
||||
for (long passengerId : entity.getPassengers()) {
|
||||
Entity passenger = session.getEntityCache().getEntityByJavaId(passengerId);
|
||||
if (passenger == null) {
|
||||
continue;
|
||||
}
|
||||
if (Arrays.stream(packet.getPassengerIds()).noneMatch(id -> id == passengerId)) {
|
||||
SetEntityLinkPacket linkPacket = new SetEntityLinkPacket();
|
||||
linkPacket.setEntityLink(new EntityLink(entity.getGeyserId(), passenger.getGeyserId(), EntityLink.Type.REMOVE, false));
|
||||
session.sendUpstreamPacket(linkPacket);
|
||||
passengers.remove(passenger.getEntityId());
|
||||
|
||||
this.updateOffset(passenger, entity.getEntityType(), session, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.getEntityType() == EntityType.HORSE) {
|
||||
entity.getMetadata().put(EntityData.RIDER_SEAT_POSITION, Vector3f.from(0.0f, 2.3200102f, -0.2f));
|
||||
entity.getMetadata().put(EntityData.RIDER_MAX_ROTATION, 181.0f);
|
||||
|
||||
entity.updateBedrockMetadata(session);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateOffset(Entity passenger, EntityType mountType, GeyserSession session, boolean rider, boolean riding) {
|
||||
// Without these, Bedrock players will find themselves in the floor when mounting
|
||||
float yOffset = 0;
|
||||
switch (mountType) {
|
||||
case BOAT:
|
||||
yOffset = passenger.getEntityType() == EntityType.PLAYER ? 1.02001f : -0.2f;
|
||||
break;
|
||||
case MINECART:
|
||||
yOffset = passenger.getEntityType() == EntityType.PLAYER ? 1.02001f : 0f;
|
||||
break;
|
||||
case DONKEY:
|
||||
yOffset = 2.1f;
|
||||
break;
|
||||
case HORSE:
|
||||
case SKELETON_HORSE:
|
||||
case ZOMBIE_HORSE:
|
||||
case MULE:
|
||||
yOffset = 2.3f;
|
||||
break;
|
||||
case LLAMA:
|
||||
case TRADER_LLAMA:
|
||||
yOffset = 2.5f;
|
||||
break;
|
||||
case PIG:
|
||||
yOffset = 1.85001f;
|
||||
break;
|
||||
}
|
||||
Vector3f offset = Vector3f.from(0f, yOffset, 0f);
|
||||
if (rider) {
|
||||
offset.add(Vector3f.from(0.2, 0, 0));
|
||||
} else {
|
||||
offset.add(Vector3f.from(-0.6, 0, 0));
|
||||
}
|
||||
passenger.getMetadata().getFlags().setFlag(EntityFlag.RIDING, riding);
|
||||
if (riding) {
|
||||
passenger.getMetadata().put(EntityData.RIDER_SEAT_POSITION, offset);
|
||||
}
|
||||
passenger.updateBedrockMetadata(session);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.network.translators.java.world;
|
||||
|
||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerVehicleMovePacket;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.Entity;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
||||
@Translator(packet = ServerVehicleMovePacket.class)
|
||||
public class JavaVehicleMoveTranslator extends PacketTranslator<ServerVehicleMovePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(ServerVehicleMovePacket packet, GeyserSession session) {
|
||||
Entity entity = session.getRidingVehicleEntity();
|
||||
if (entity == null) return;
|
||||
|
||||
entity.moveAbsolute(session, Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), false, false);
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue