3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-10-01 23:50:11 +02:00

Boats are leashable

Dieser Commit ist enthalten in:
Camotoy 2024-06-02 23:36:44 -04:00
Ursprung 65fd409a00
Commit 8ad10f8a9e
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 7EEFB66FE798081F
17 geänderte Dateien mit 120 neuen und 38 gelöschten Zeilen

Datei anzeigen

@ -41,7 +41,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
public class BoatEntity extends Entity implements Tickable {
public class BoatEntity extends Entity implements Leashable, Tickable {
/**
* Required when IS_BUOYANT is sent in order for boats to work in the water. <br>
@ -65,6 +65,8 @@ public class BoatEntity extends Entity implements Tickable {
@Getter
private int variant;
private long leashHolderBedrockId = -1;
// 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.1f;
@ -147,8 +149,18 @@ public class BoatEntity extends Entity implements Tickable {
}
}
@Override
public void setLeashHolderBedrockId(long bedrockId) {
this.leashHolderBedrockId = bedrockId;
dirtyMetadata.put(EntityDataTypes.LEASH_HOLDER, bedrockId);
}
@Override
protected InteractiveTag testInteraction(Hand hand) {
InteractiveTag tag = super.testInteraction(hand);
if (tag != InteractiveTag.NONE) {
return tag;
}
if (session.isSneaking()) {
return InteractiveTag.NONE;
} else if (passengers.size() < 2) {
@ -160,6 +172,10 @@ public class BoatEntity extends Entity implements Tickable {
@Override
public InteractionResult interact(Hand hand) {
InteractionResult result = super.interact(hand);
if (result != InteractionResult.PASS) {
return result;
}
if (session.isSneaking()) {
return InteractionResult.PASS;
} else {
@ -191,6 +207,11 @@ public class BoatEntity extends Entity implements Tickable {
}
}
@Override
public long leashHolderBedrockId() {
return leashHolderBedrockId;
}
private void sendAnimationPacket(GeyserSession session, Entity rower, AnimatePacket.Action action, float rowTime) {
AnimatePacket packet = new AnimatePacket();
packet.setRuntimeEntityId(rower.getGeyserId());

Datei anzeigen

@ -40,6 +40,7 @@ import org.geysermc.geyser.api.entity.type.GeyserEntity;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.GeyserDirtyMetadata;
import org.geysermc.geyser.entity.properties.GeyserEntityPropertyManager;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.EntityUtils;
@ -557,6 +558,17 @@ public class Entity implements GeyserEntity {
* Should usually mirror {@link #interact(Hand)} without any side effects.
*/
protected InteractiveTag testInteraction(Hand hand) {
if (isAlive() && this instanceof Leashable leashable) {
if (leashable.leashHolderBedrockId() == session.getPlayerEntity().getGeyserId()) {
// Note this might be client side. Has yet to be an issue though, as of Java 1.21.
return InteractiveTag.REMOVE_LEASH;
}
if (session.getPlayerInventory().getItemInHand(hand).asItem() == Items.LEAD && leashable.canBeLeashed()) {
// We shall leash
return InteractiveTag.LEASH;
}
}
return InteractiveTag.NONE;
}
@ -565,6 +577,18 @@ public class Entity implements GeyserEntity {
* to ensure packet parity as well as functionality parity (such as sound effect responses).
*/
public InteractionResult interact(Hand hand) {
if (isAlive() && this instanceof Leashable leashable) {
if (leashable.leashHolderBedrockId() == session.getPlayerEntity().getGeyserId()) {
// Note this might also update client side (a theoretical Geyser/client desync and Java parity issue).
// Has yet to be an issue though, as of Java 1.21.
return InteractionResult.SUCCESS;
}
if (session.getPlayerInventory().getItemInHand(hand).asItem() == Items.LEAD && leashable.canBeLeashed()) {
// We shall leash
return InteractionResult.SUCCESS;
}
}
return InteractionResult.PASS;
}

Datei anzeigen

@ -0,0 +1,44 @@
/*
* Copyright (c) 2024 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.geyser.entity.type;
/**
* I can haz lead
* (The item, not the mineral)
*/
public interface Leashable {
void setLeashHolderBedrockId(long bedrockId);
long leashHolderBedrockId();
default boolean canBeLeashed() {
return isNotLeashed();
}
default boolean isNotLeashed() {
return leashHolderBedrockId() == -1L;
}
}

Datei anzeigen

@ -38,7 +38,7 @@ public class AmbientEntity extends MobEntity {
}
@Override
protected boolean canBeLeashed() {
public boolean canBeLeashed() {
return false;
}
}

Datei anzeigen

@ -43,7 +43,7 @@ public class DolphinEntity extends WaterEntity {
}
@Override
protected boolean canBeLeashed() {
public boolean canBeLeashed() {
return true;
}

Datei anzeigen

@ -25,12 +25,12 @@
package org.geysermc.geyser.entity.type.living;
import lombok.Getter;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Leashable;
import org.geysermc.geyser.entity.type.LivingEntity;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
@ -43,11 +43,10 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
public class MobEntity extends LivingEntity {
public class MobEntity extends LivingEntity implements Leashable {
/**
* If another mob is holding this mob by a leash, this variable tracks their Bedrock entity ID.
*/
@Getter
private long leashHolderBedrockId;
public MobEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
@ -65,6 +64,7 @@ public class MobEntity extends LivingEntity {
setFlag(EntityFlag.NO_AI, (xd & 0x01) == 0x01);
}
@Override
public void setLeashHolderBedrockId(long bedrockId) {
this.leashHolderBedrockId = bedrockId;
dirtyMetadata.put(EntityDataTypes.LEASH_HOLDER, bedrockId);
@ -79,10 +79,7 @@ public class MobEntity extends LivingEntity {
return InteractiveTag.REMOVE_LEASH;
} else {
GeyserItemStack itemStack = session.getPlayerInventory().getItemInHand(hand);
if (itemStack.asItem() == Items.LEAD && canBeLeashed()) {
// We shall leash
return InteractiveTag.LEASH;
} else if (itemStack.asItem() == Items.NAME_TAG) {
if (itemStack.asItem() == Items.NAME_TAG) {
InteractionResult result = checkInteractWithNameTag(itemStack);
if (result.consumesAction()) {
return InteractiveTag.NAME;
@ -99,9 +96,6 @@ public class MobEntity extends LivingEntity {
if (!isAlive()) {
// dead lol
return InteractionResult.PASS;
} else if (leashHolderBedrockId == session.getPlayerEntity().getGeyserId()) {
// TODO looks like the client assumes it will go through and removes the attachment itself?
return InteractionResult.SUCCESS;
} else {
GeyserItemStack itemInHand = session.getPlayerInventory().getItemInHand(hand);
InteractionResult result = checkPriorityInteractions(itemInHand);
@ -115,10 +109,7 @@ public class MobEntity extends LivingEntity {
}
private InteractionResult checkPriorityInteractions(GeyserItemStack itemInHand) {
if (itemInHand.asItem() == Items.LEAD && canBeLeashed()) {
// We shall leash
return InteractionResult.SUCCESS;
} else if (itemInHand.asItem() == Items.NAME_TAG) {
if (itemInHand.asItem() == Items.NAME_TAG) {
InteractionResult result = checkInteractWithNameTag(itemInHand);
if (result.consumesAction()) {
return result;
@ -143,12 +134,14 @@ public class MobEntity extends LivingEntity {
return InteractionResult.PASS;
}
protected boolean canBeLeashed() {
@Override
public boolean canBeLeashed() {
return isNotLeashed() && !isEnemy();
}
protected final boolean isNotLeashed() {
return leashHolderBedrockId == -1L;
@Override
public long leashHolderBedrockId() {
return leashHolderBedrockId;
}
/**

Datei anzeigen

@ -122,7 +122,7 @@ public class SquidEntity extends WaterEntity implements Tickable {
}
@Override
protected boolean canBeLeashed() {
public boolean canBeLeashed() {
return isNotLeashed();
}

Datei anzeigen

@ -38,7 +38,7 @@ public class WaterEntity extends CreatureEntity {
}
@Override
protected boolean canBeLeashed() {
public boolean canBeLeashed() {
return false;
}
}

Datei anzeigen

@ -72,7 +72,7 @@ public class AxolotlEntity extends AnimalEntity {
}
@Override
protected boolean canBeLeashed() {
public boolean canBeLeashed() {
return true;
}

Datei anzeigen

@ -63,7 +63,7 @@ public class HoglinEntity extends AnimalEntity {
}
@Override
protected boolean canBeLeashed() {
public boolean canBeLeashed() {
return isNotLeashed();
}

Datei anzeigen

@ -123,7 +123,7 @@ public class PandaEntity extends AnimalEntity {
}
@Override
protected boolean canBeLeashed() {
public boolean canBeLeashed() {
return false;
}

Datei anzeigen

@ -56,7 +56,7 @@ public class TurtleEntity extends AnimalEntity {
}
@Override
protected boolean canBeLeashed() {
public boolean canBeLeashed() {
return false;
}
}

Datei anzeigen

@ -84,7 +84,7 @@ public abstract class TameableEntity extends AnimalEntity {
}
@Override
protected boolean canBeLeashed() {
public boolean canBeLeashed() {
return isNotLeashed();
}
}

Datei anzeigen

@ -127,7 +127,7 @@ public class WolfEntity extends TameableEntity {
}
@Override
protected boolean canBeLeashed() {
public boolean canBeLeashed() {
return !getFlag(EntityFlag.ANGRY) && super.canBeLeashed();
}

Datei anzeigen

@ -47,7 +47,7 @@ public class AbstractMerchantEntity extends AgeableEntity {
}
@Override
protected boolean canBeLeashed() {
public boolean canBeLeashed() {
return false;
}

Datei anzeigen

@ -58,7 +58,7 @@ public class ZoglinEntity extends MonsterEntity {
}
@Override
protected boolean canBeLeashed() {
public boolean canBeLeashed() {
return isNotLeashed();
}

Datei anzeigen

@ -25,15 +25,15 @@
package org.geysermc.geyser.translator.protocol.java.entity;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityLinkPacket;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.living.MobEntity;
import org.geysermc.geyser.entity.type.Leashable;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityLinkPacket;
/**
* Called when a leash is attached, removed or updated from an entity
@ -44,16 +44,16 @@ public class JavaSetEntityLinkTranslator extends PacketTranslator<ClientboundSet
@Override
public void translate(GeyserSession session, ClientboundSetEntityLinkPacket packet) {
Entity holderId = session.getEntityCache().getEntityByJavaId(packet.getEntityId());
if (!(holderId instanceof MobEntity mobEntity)) {
if (!(holderId instanceof Leashable asLeashable)) {
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();
holderId.setFlag(EntityFlag.LEASHED, false);
asLeashable.setLeashHolderBedrockId(-1L);
holderId.updateBedrockMetadata();
EntityEventPacket eventPacket = new EntityEventPacket();
eventPacket.setRuntimeEntityId(holderId.getGeyserId());
eventPacket.setType(EntityEventType.REMOVE_LEASH);
@ -62,8 +62,8 @@ public class JavaSetEntityLinkTranslator extends PacketTranslator<ClientboundSet
return;
}
mobEntity.setFlag(EntityFlag.LEASHED, true);
mobEntity.setLeashHolderBedrockId(attachedToId.getGeyserId());
holderId.setFlag(EntityFlag.LEASHED, true);
asLeashable.setLeashHolderBedrockId(attachedToId.getGeyserId());
holderId.updateBedrockMetadata();
}
}