Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-10-05 09:20:07 +02:00
Update the interactive tag when necessary (#2039)
Update the interactive tag on entity metadata update, item slot change, and sneaking update; that way, if the tag should change, it will change.
Dieser Commit ist enthalten in:
Ursprung
f827b28852
Commit
930c4c538e
@ -264,6 +264,12 @@ public class GeyserSession implements CommandSender {
|
|||||||
@Setter
|
@Setter
|
||||||
private Entity ridingVehicleEntity;
|
private Entity ridingVehicleEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entity that the client is currently looking at.
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
private Entity mouseoverEntity;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private Int2ObjectMap<Recipe> craftingRecipes;
|
private Int2ObjectMap<Recipe> craftingRecipes;
|
||||||
private final Set<String> unlockedRecipes;
|
private final Set<String> unlockedRecipes;
|
||||||
@ -804,6 +810,11 @@ public class GeyserSession implements CommandSender {
|
|||||||
this.sneaking = sneaking;
|
this.sneaking = sneaking;
|
||||||
collisionManager.updatePlayerBoundingBox();
|
collisionManager.updatePlayerBoundingBox();
|
||||||
collisionManager.updateScaffoldingFlags();
|
collisionManager.updateScaffoldingFlags();
|
||||||
|
|
||||||
|
if (mouseoverEntity != null) {
|
||||||
|
// Horses, etc can change their property depending on if you're sneaking
|
||||||
|
InteractiveTagManager.updateTag(this, mouseoverEntity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,6 +35,7 @@ import org.geysermc.connector.network.translators.PacketTranslator;
|
|||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
import org.geysermc.connector.utils.CooldownUtils;
|
import org.geysermc.connector.utils.CooldownUtils;
|
||||||
|
import org.geysermc.connector.utils.InteractiveTagManager;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@ -67,5 +68,10 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator<MobEquipment
|
|||||||
|
|
||||||
// Java sends a cooldown indicator whenever you switch an item
|
// Java sends a cooldown indicator whenever you switch an item
|
||||||
CooldownUtils.sendCooldown(session);
|
CooldownUtils.sendCooldown(session);
|
||||||
|
|
||||||
|
// Update the interactive tag, if an entity is present
|
||||||
|
if (session.getMouseoverEntity() != null) {
|
||||||
|
InteractiveTagManager.updateTag(session, session.getMouseoverEntity());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,61 +31,21 @@ 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.ClientPlayerInteractEntityPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap;
|
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
||||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.InteractPacket;
|
import com.nukkitx.protocol.bedrock.packet.InteractPacket;
|
||||||
import lombok.Getter;
|
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.entity.living.animal.horse.AbstractHorseEntity;
|
import org.geysermc.connector.entity.living.animal.horse.AbstractHorseEntity;
|
||||||
import org.geysermc.connector.entity.living.animal.horse.HorseEntity;
|
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
|
||||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
|
import org.geysermc.connector.utils.InteractiveTagManager;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Translator(packet = InteractPacket.class)
|
@Translator(packet = InteractPacket.class)
|
||||||
public class BedrockInteractTranslator extends PacketTranslator<InteractPacket> {
|
public class BedrockInteractTranslator extends PacketTranslator<InteractPacket> {
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of all foods a horse/donkey can eat on Java Edition.
|
|
||||||
* Used to display interactive tag if needed.
|
|
||||||
*/
|
|
||||||
private static final List<String> DONKEY_AND_HORSE_FOODS = Arrays.asList("golden_apple", "enchanted_golden_apple",
|
|
||||||
"golden_carrot", "sugar", "apple", "wheat", "hay_block");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of all flowers. Used for feeding bees.
|
|
||||||
*/
|
|
||||||
private static final List<String> FLOWERS = Arrays.asList("dandelion", "poppy", "blue_orchid", "allium", "azure_bluet",
|
|
||||||
"red_tulip", "pink_tulip", "white_tulip", "orange_tulip", "cornflower", "lily_of_the_valley", "wither_rose",
|
|
||||||
"sunflower", "lilac", "rose_bush", "peony");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All entity types that can be leashed on Java Edition
|
|
||||||
*/
|
|
||||||
private static final List<EntityType> LEASHABLE_MOB_TYPES = Arrays.asList(EntityType.BEE, EntityType.CAT, EntityType.CHICKEN,
|
|
||||||
EntityType.COW, EntityType.DOLPHIN, EntityType.DONKEY, EntityType.FOX, EntityType.HOGLIN, EntityType.HORSE, EntityType.SKELETON_HORSE,
|
|
||||||
EntityType.ZOMBIE_HORSE, EntityType.IRON_GOLEM, EntityType.LLAMA, EntityType.TRADER_LLAMA, EntityType.MOOSHROOM,
|
|
||||||
EntityType.MULE, EntityType.OCELOT, EntityType.PARROT, EntityType.PIG, EntityType.POLAR_BEAR, EntityType.RABBIT,
|
|
||||||
EntityType.SHEEP, EntityType.SNOW_GOLEM, EntityType.STRIDER, EntityType.WOLF, EntityType.ZOGLIN);
|
|
||||||
|
|
||||||
private static final List<EntityType> SADDLEABLE_WHEN_TAMED_MOB_TYPES = Arrays.asList(EntityType.DONKEY, EntityType.HORSE,
|
|
||||||
EntityType.ZOMBIE_HORSE, EntityType.MULE);
|
|
||||||
/**
|
|
||||||
* A list of all foods a wolf can eat on Java Edition.
|
|
||||||
* Used to display interactive tag if needed.
|
|
||||||
*/
|
|
||||||
private static final List<String> WOLF_FOODS = Arrays.asList("pufferfish", "tropical_fish", "chicken", "cooked_chicken",
|
|
||||||
"porkchop", "beef", "rabbit", "cooked_porkchop", "cooked_beef", "rotten_flesh", "mutton", "cooked_mutton",
|
|
||||||
"cooked_rabbit");
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(InteractPacket packet, GeyserSession session) {
|
public void translate(InteractPacket packet, GeyserSession session) {
|
||||||
Entity entity;
|
Entity entity;
|
||||||
@ -121,241 +81,16 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
|||||||
// Handle the buttons for mobile - "Mount", etc; and the suggestions for console - "ZL: Mount", etc
|
// Handle the buttons for mobile - "Mount", etc; and the suggestions for console - "ZL: Mount", etc
|
||||||
if (packet.getRuntimeEntityId() != 0) {
|
if (packet.getRuntimeEntityId() != 0) {
|
||||||
Entity interactEntity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId());
|
Entity interactEntity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId());
|
||||||
if (interactEntity == null)
|
session.setMouseoverEntity(interactEntity);
|
||||||
|
if (interactEntity == null) {
|
||||||
return;
|
return;
|
||||||
EntityDataMap entityMetadata = interactEntity.getMetadata();
|
|
||||||
ItemEntry itemEntry = session.getPlayerInventory().getItemInHand().getItemEntry();
|
|
||||||
String javaIdentifierStripped = itemEntry.getJavaIdentifier().replace("minecraft:", "");
|
|
||||||
|
|
||||||
// TODO - in the future, update these in the metadata? So the client doesn't have to wiggle their cursor around for it to happen
|
|
||||||
// TODO - also, might be good to abstract out the eating thing. I know there will need to be food tracked for https://github.com/GeyserMC/Geyser/issues/1005 but not all food is breeding food
|
|
||||||
InteractiveTag interactiveTag = InteractiveTag.NONE;
|
|
||||||
if (entityMetadata.getLong(EntityData.LEASH_HOLDER_EID) == session.getPlayerEntity().getGeyserId()) {
|
|
||||||
// Unleash the entity
|
|
||||||
interactiveTag = InteractiveTag.REMOVE_LEASH;
|
|
||||||
} else if (javaIdentifierStripped.equals("saddle") && !entityMetadata.getFlags().getFlag(EntityFlag.SADDLED) &&
|
|
||||||
((SADDLEABLE_WHEN_TAMED_MOB_TYPES.contains(interactEntity.getEntityType()) && entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) ||
|
|
||||||
interactEntity.getEntityType() == EntityType.PIG || interactEntity.getEntityType() == EntityType.STRIDER)) {
|
|
||||||
// Entity can be saddled and the conditions meet (entity can be saddled and, if needed, is tamed)
|
|
||||||
interactiveTag = InteractiveTag.SADDLE;
|
|
||||||
} else if (javaIdentifierStripped.equals("name_tag") && session.getPlayerInventory().getItemInHand().getNbt() != null &&
|
|
||||||
session.getPlayerInventory().getItemInHand().getNbt().contains("display")) {
|
|
||||||
// Holding a named name tag
|
|
||||||
interactiveTag = InteractiveTag.NAME;
|
|
||||||
} else if (javaIdentifierStripped.equals("lead") && LEASHABLE_MOB_TYPES.contains(interactEntity.getEntityType()) &&
|
|
||||||
entityMetadata.getLong(EntityData.LEASH_HOLDER_EID) == -1L) {
|
|
||||||
// Holding a leash and the mob is leashable for sure
|
|
||||||
// (Plugins can change this behavior so that's something to look into in the far far future)
|
|
||||||
interactiveTag = InteractiveTag.LEASH;
|
|
||||||
} else {
|
|
||||||
switch (interactEntity.getEntityType()) {
|
|
||||||
case BEE:
|
|
||||||
if (FLOWERS.contains(javaIdentifierStripped)) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BOAT:
|
|
||||||
interactiveTag = InteractiveTag.BOARD_BOAT;
|
|
||||||
break;
|
|
||||||
case CAT:
|
|
||||||
if (javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
} else if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) &&
|
|
||||||
entityMetadata.getLong(EntityData.OWNER_EID) == session.getPlayerEntity().getGeyserId()) {
|
|
||||||
// Tamed and owned by player - can sit/stand
|
|
||||||
interactiveTag = entityMetadata.getFlags().getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CHICKEN:
|
|
||||||
if (javaIdentifierStripped.contains("seeds")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MOOSHROOM:
|
|
||||||
// Shear the mooshroom
|
|
||||||
if (javaIdentifierStripped.equals("shears")) {
|
|
||||||
interactiveTag = InteractiveTag.MOOSHROOM_SHEAR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Bowls are acceptable here
|
|
||||||
else if (javaIdentifierStripped.equals("bowl")) {
|
|
||||||
interactiveTag = InteractiveTag.MOOSHROOM_MILK_STEW;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Fall down to COW as this works on mooshrooms
|
|
||||||
case COW:
|
|
||||||
if (javaIdentifierStripped.equals("wheat")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
} else if (javaIdentifierStripped.equals("bucket")) {
|
|
||||||
// Milk the cow
|
|
||||||
interactiveTag = InteractiveTag.MILK;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CREEPER:
|
|
||||||
if (javaIdentifierStripped.equals("flint_and_steel")) {
|
|
||||||
// Today I learned that you can ignite a creeper with flint and steel! Huh.
|
|
||||||
interactiveTag = InteractiveTag.IGNITE_CREEPER;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DONKEY:
|
|
||||||
case LLAMA:
|
|
||||||
case MULE:
|
|
||||||
if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) && !entityMetadata.getFlags().getFlag(EntityFlag.CHESTED)
|
|
||||||
&& javaIdentifierStripped.equals("chest")) {
|
|
||||||
// Can attach a chest
|
|
||||||
interactiveTag = InteractiveTag.ATTACH_CHEST;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Intentional fall-through
|
|
||||||
case HORSE:
|
|
||||||
case SKELETON_HORSE:
|
|
||||||
case TRADER_LLAMA:
|
|
||||||
case ZOMBIE_HORSE:
|
|
||||||
boolean tamed = entityMetadata.getFlags().getFlag(EntityFlag.TAMED);
|
|
||||||
if (session.isSneaking() && tamed && (interactEntity instanceof HorseEntity || entityMetadata.getFlags().getFlag(EntityFlag.CHESTED))) {
|
|
||||||
interactiveTag = InteractiveTag.OPEN_CONTAINER;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// have another switch statement as, while these share mount attributes they don't share food
|
|
||||||
switch (interactEntity.getEntityType()) {
|
|
||||||
case LLAMA:
|
|
||||||
case TRADER_LLAMA:
|
|
||||||
if (javaIdentifierStripped.equals("wheat") || javaIdentifierStripped.equals("hay_block")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DONKEY:
|
|
||||||
case HORSE:
|
|
||||||
// Undead can't eat
|
|
||||||
if (DONKEY_AND_HORSE_FOODS.contains(javaIdentifierStripped)) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!entityMetadata.getFlags().getFlag(EntityFlag.BABY)) {
|
|
||||||
// Can't ride a baby
|
|
||||||
if (tamed) {
|
|
||||||
interactiveTag = InteractiveTag.RIDE_HORSE;
|
|
||||||
} else if (itemEntry.equals(ItemEntry.AIR)) {
|
|
||||||
// Can't hide an untamed entity without having your hand empty
|
|
||||||
interactiveTag = InteractiveTag.MOUNT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FOX:
|
|
||||||
if (javaIdentifierStripped.equals("sweet_berries")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case HOGLIN:
|
|
||||||
if (javaIdentifierStripped.equals("crimson_fungus")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MINECART:
|
|
||||||
interactiveTag = InteractiveTag.RIDE_MINECART;
|
|
||||||
break;
|
|
||||||
case MINECART_CHEST:
|
|
||||||
case MINECART_COMMAND_BLOCK:
|
|
||||||
case MINECART_HOPPER:
|
|
||||||
interactiveTag = InteractiveTag.OPEN_CONTAINER;
|
|
||||||
break;
|
|
||||||
case OCELOT:
|
|
||||||
if (javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PANDA:
|
|
||||||
if (javaIdentifierStripped.equals("bamboo")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PARROT:
|
|
||||||
if (javaIdentifierStripped.contains("seeds") || javaIdentifierStripped.equals("cookie")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PIG:
|
|
||||||
if (javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("potato") || javaIdentifierStripped.equals("beetroot")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
} else if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
|
||||||
interactiveTag = InteractiveTag.MOUNT;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PIGLIN:
|
|
||||||
if (!entityMetadata.getFlags().getFlag(EntityFlag.BABY) && javaIdentifierStripped.equals("gold_ingot")) {
|
|
||||||
interactiveTag = InteractiveTag.BARTER;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RABBIT:
|
|
||||||
if (javaIdentifierStripped.equals("dandelion") || javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("golden_carrot")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SHEEP:
|
|
||||||
if (javaIdentifierStripped.equals("wheat")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
} else if (!entityMetadata.getFlags().getFlag(EntityFlag.SHEARED)) {
|
|
||||||
if (javaIdentifierStripped.equals("shears")) {
|
|
||||||
// Shear the sheep
|
|
||||||
interactiveTag = InteractiveTag.SHEAR;
|
|
||||||
} else if (javaIdentifierStripped.contains("_dye")) {
|
|
||||||
// Dye the sheep
|
|
||||||
interactiveTag = InteractiveTag.DYE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STRIDER:
|
|
||||||
if (javaIdentifierStripped.equals("warped_fungus")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
} else if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
|
||||||
interactiveTag = InteractiveTag.RIDE_STRIDER;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TURTLE:
|
|
||||||
if (javaIdentifierStripped.equals("seagrass")) {
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VILLAGER:
|
|
||||||
if (entityMetadata.getInt(EntityData.VARIANT) != 14 && entityMetadata.getInt(EntityData.VARIANT) != 0
|
|
||||||
&& entityMetadata.getFloat(EntityData.SCALE) >= 0.75f) { // Not a nitwit, has a profession and is not a baby
|
|
||||||
interactiveTag = InteractiveTag.TRADE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WANDERING_TRADER:
|
|
||||||
interactiveTag = InteractiveTag.TRADE; // Since you can always trade with a wandering villager, presumably.
|
|
||||||
break;
|
|
||||||
case WOLF:
|
|
||||||
if (javaIdentifierStripped.equals("bone") && !entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
|
||||||
// Bone and untamed - can tame
|
|
||||||
interactiveTag = InteractiveTag.TAME;
|
|
||||||
} else if (WOLF_FOODS.contains(javaIdentifierStripped)) {
|
|
||||||
// Compatible food in hand - feed
|
|
||||||
// Sometimes just sits/stands when the wolf isn't hungry - there doesn't appear to be a way to fix this
|
|
||||||
interactiveTag = InteractiveTag.FEED;
|
|
||||||
} else if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) &&
|
|
||||||
entityMetadata.getLong(EntityData.OWNER_EID) == session.getPlayerEntity().getGeyserId()) {
|
|
||||||
// Tamed and owned by player - can sit/stand
|
|
||||||
interactiveTag = entityMetadata.getFlags().getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ZOMBIE_VILLAGER:
|
|
||||||
// We can't guarantee the existence of the weakness effect so we just always show it.
|
|
||||||
if (javaIdentifierStripped.equals("golden_apple")) {
|
|
||||||
interactiveTag = InteractiveTag.CURE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag.getValue());
|
|
||||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
InteractiveTagManager.updateTag(session, interactEntity);
|
||||||
} else {
|
} else {
|
||||||
if (!session.getPlayerEntity().getMetadata().getString(EntityData.INTERACTIVE_TAG).isEmpty()) {
|
if (session.getMouseoverEntity() != null) {
|
||||||
// No interactive tag should be sent
|
// No interactive tag should be sent
|
||||||
|
session.setMouseoverEntity(null);
|
||||||
session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, "");
|
session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, "");
|
||||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||||
}
|
}
|
||||||
@ -384,65 +119,4 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* All interactive tags in enum form. For potential API usage.
|
|
||||||
*/
|
|
||||||
public enum InteractiveTag {
|
|
||||||
NONE(true),
|
|
||||||
IGNITE_CREEPER("creeper"),
|
|
||||||
EDIT,
|
|
||||||
LEAVE_BOAT("exit.boat"),
|
|
||||||
FEED,
|
|
||||||
FISH("fishing"),
|
|
||||||
MILK,
|
|
||||||
MOOSHROOM_SHEAR("mooshear"),
|
|
||||||
MOOSHROOM_MILK_STEW("moostew"),
|
|
||||||
BOARD_BOAT("ride.boat"),
|
|
||||||
RIDE_MINECART("ride.minecart"),
|
|
||||||
RIDE_HORSE("ride.horse"),
|
|
||||||
RIDE_STRIDER("ride.strider"),
|
|
||||||
SHEAR,
|
|
||||||
SIT,
|
|
||||||
STAND,
|
|
||||||
TALK,
|
|
||||||
TAME,
|
|
||||||
DYE,
|
|
||||||
CURE,
|
|
||||||
OPEN_CONTAINER("opencontainer"),
|
|
||||||
CREATE_MAP("createMap"),
|
|
||||||
TAKE_PICTURE("takepicture"),
|
|
||||||
SADDLE,
|
|
||||||
MOUNT,
|
|
||||||
BOOST,
|
|
||||||
WRITE,
|
|
||||||
LEASH,
|
|
||||||
REMOVE_LEASH("unleash"),
|
|
||||||
NAME,
|
|
||||||
ATTACH_CHEST("attachchest"),
|
|
||||||
TRADE,
|
|
||||||
POSE_ARMOR_STAND("armorstand.pose"),
|
|
||||||
EQUIP_ARMOR_STAND("armorstand.equip"),
|
|
||||||
READ,
|
|
||||||
WAKE_VILLAGER("wakevillager"),
|
|
||||||
BARTER;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The full string that should be passed on to the client.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
private final String value;
|
|
||||||
|
|
||||||
InteractiveTag(boolean isNone) {
|
|
||||||
this.value = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
InteractiveTag(String value) {
|
|
||||||
this.value = "action.interact." + value;
|
|
||||||
}
|
|
||||||
|
|
||||||
InteractiveTag() {
|
|
||||||
this.value = "action.interact." + name().toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import org.geysermc.connector.network.translators.Translator;
|
|||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityMetadataPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityMetadataPacket;
|
||||||
|
import org.geysermc.connector.utils.InteractiveTagManager;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
@Translator(packet = ServerEntityMetadataPacket.class)
|
@Translator(packet = ServerEntityMetadataPacket.class)
|
||||||
@ -63,5 +64,10 @@ public class JavaEntityMetadataTranslator extends PacketTranslator<ServerEntityM
|
|||||||
}
|
}
|
||||||
|
|
||||||
entity.updateBedrockMetadata(session);
|
entity.updateBedrockMetadata(session);
|
||||||
|
|
||||||
|
// Update the interactive tag, if necessary
|
||||||
|
if (session.getMouseoverEntity() != null && session.getMouseoverEntity().getEntityId() == entity.getEntityId()) {
|
||||||
|
InteractiveTagManager.updateTag(session, entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,376 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2021 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.utils;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
import org.geysermc.connector.entity.living.animal.horse.HorseEntity;
|
||||||
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class InteractiveTagManager {
|
||||||
|
/**
|
||||||
|
* A list of all foods a horse/donkey can eat on Java Edition.
|
||||||
|
* Used to display interactive tag if needed.
|
||||||
|
*/
|
||||||
|
private static final Set<String> DONKEY_AND_HORSE_FOODS = ImmutableSet.of("golden_apple", "enchanted_golden_apple",
|
||||||
|
"golden_carrot", "sugar", "apple", "wheat", "hay_block");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of all flowers. Used for feeding bees.
|
||||||
|
*/
|
||||||
|
private static final Set<String> FLOWERS = ImmutableSet.of("dandelion", "poppy", "blue_orchid", "allium", "azure_bluet",
|
||||||
|
"red_tulip", "pink_tulip", "white_tulip", "orange_tulip", "cornflower", "lily_of_the_valley", "wither_rose",
|
||||||
|
"sunflower", "lilac", "rose_bush", "peony");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All entity types that can be leashed on Java Edition
|
||||||
|
*/
|
||||||
|
private static final Set<EntityType> LEASHABLE_MOB_TYPES = EnumSet.of(EntityType.BEE, EntityType.CAT, EntityType.CHICKEN,
|
||||||
|
EntityType.COW, EntityType.DOLPHIN, EntityType.DONKEY, EntityType.FOX, EntityType.HOGLIN, EntityType.HORSE, EntityType.SKELETON_HORSE,
|
||||||
|
EntityType.ZOMBIE_HORSE, EntityType.IRON_GOLEM, EntityType.LLAMA, EntityType.TRADER_LLAMA, EntityType.MOOSHROOM,
|
||||||
|
EntityType.MULE, EntityType.OCELOT, EntityType.PARROT, EntityType.PIG, EntityType.POLAR_BEAR, EntityType.RABBIT,
|
||||||
|
EntityType.SHEEP, EntityType.SNOW_GOLEM, EntityType.STRIDER, EntityType.WOLF, EntityType.ZOGLIN);
|
||||||
|
|
||||||
|
private static final Set<EntityType> SADDLEABLE_WHEN_TAMED_MOB_TYPES = EnumSet.of(EntityType.DONKEY, EntityType.HORSE,
|
||||||
|
EntityType.ZOMBIE_HORSE, EntityType.MULE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of all foods a wolf can eat on Java Edition.
|
||||||
|
* Used to display interactive tag if needed.
|
||||||
|
*/
|
||||||
|
private static final Set<String> WOLF_FOODS = ImmutableSet.of("pufferfish", "tropical_fish", "chicken", "cooked_chicken",
|
||||||
|
"porkchop", "beef", "rabbit", "cooked_porkchop", "cooked_beef", "rotten_flesh", "mutton", "cooked_mutton",
|
||||||
|
"cooked_rabbit");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the suggestion that the client currently has on their screen for this entity (for example, "Feed" or "Ride")
|
||||||
|
*
|
||||||
|
* @param session the Bedrock client session
|
||||||
|
* @param interactEntity the entity that the client is currently facing.
|
||||||
|
*/
|
||||||
|
public static void updateTag(GeyserSession session, Entity interactEntity) {
|
||||||
|
EntityDataMap entityMetadata = interactEntity.getMetadata();
|
||||||
|
ItemEntry itemEntry = session.getPlayerInventory().getItemInHand().getItemEntry();
|
||||||
|
String javaIdentifierStripped = itemEntry.getJavaIdentifier().replace("minecraft:", "");
|
||||||
|
|
||||||
|
// TODO - in the future, update these in the metadata? So the client doesn't have to wiggle their cursor around for it to happen
|
||||||
|
// TODO - also, might be good to abstract out the eating thing. I know there will need to be food tracked for https://github.com/GeyserMC/Geyser/issues/1005 but not all food is breeding food
|
||||||
|
InteractiveTag interactiveTag = InteractiveTag.NONE;
|
||||||
|
if (entityMetadata.getLong(EntityData.LEASH_HOLDER_EID) == session.getPlayerEntity().getGeyserId()) {
|
||||||
|
// Unleash the entity
|
||||||
|
interactiveTag = InteractiveTag.REMOVE_LEASH;
|
||||||
|
} else if (javaIdentifierStripped.equals("saddle") && !entityMetadata.getFlags().getFlag(EntityFlag.SADDLED) &&
|
||||||
|
((SADDLEABLE_WHEN_TAMED_MOB_TYPES.contains(interactEntity.getEntityType()) && entityMetadata.getFlags().getFlag(EntityFlag.TAMED) && !session.isSneaking()) ||
|
||||||
|
interactEntity.getEntityType() == EntityType.PIG || interactEntity.getEntityType() == EntityType.STRIDER)) {
|
||||||
|
// Entity can be saddled and the conditions meet (entity can be saddled and, if needed, is tamed)
|
||||||
|
interactiveTag = InteractiveTag.SADDLE;
|
||||||
|
} else if (javaIdentifierStripped.equals("name_tag") && session.getPlayerInventory().getItemInHand().getNbt() != null &&
|
||||||
|
session.getPlayerInventory().getItemInHand().getNbt().contains("display")) {
|
||||||
|
// Holding a named name tag
|
||||||
|
interactiveTag = InteractiveTag.NAME;
|
||||||
|
} else if (javaIdentifierStripped.equals("lead") && LEASHABLE_MOB_TYPES.contains(interactEntity.getEntityType()) &&
|
||||||
|
entityMetadata.getLong(EntityData.LEASH_HOLDER_EID, -1L) == -1L) {
|
||||||
|
// Holding a leash and the mob is leashable for sure
|
||||||
|
// (Plugins can change this behavior so that's something to look into in the far far future)
|
||||||
|
interactiveTag = InteractiveTag.LEASH;
|
||||||
|
} else {
|
||||||
|
switch (interactEntity.getEntityType()) {
|
||||||
|
case BEE:
|
||||||
|
if (FLOWERS.contains(javaIdentifierStripped)) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BOAT:
|
||||||
|
interactiveTag = InteractiveTag.BOARD_BOAT;
|
||||||
|
break;
|
||||||
|
case CAT:
|
||||||
|
if (javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
} else if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) &&
|
||||||
|
entityMetadata.getLong(EntityData.OWNER_EID) == session.getPlayerEntity().getGeyserId()) {
|
||||||
|
// Tamed and owned by player - can sit/stand
|
||||||
|
interactiveTag = entityMetadata.getFlags().getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CHICKEN:
|
||||||
|
if (javaIdentifierStripped.contains("seeds")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MOOSHROOM:
|
||||||
|
// Shear the mooshroom
|
||||||
|
if (javaIdentifierStripped.equals("shears")) {
|
||||||
|
interactiveTag = InteractiveTag.MOOSHROOM_SHEAR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Bowls are acceptable here
|
||||||
|
else if (javaIdentifierStripped.equals("bowl")) {
|
||||||
|
interactiveTag = InteractiveTag.MOOSHROOM_MILK_STEW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Fall down to COW as this works on mooshrooms
|
||||||
|
case COW:
|
||||||
|
if (javaIdentifierStripped.equals("wheat")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
} else if (javaIdentifierStripped.equals("bucket")) {
|
||||||
|
// Milk the cow
|
||||||
|
interactiveTag = InteractiveTag.MILK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CREEPER:
|
||||||
|
if (javaIdentifierStripped.equals("flint_and_steel")) {
|
||||||
|
// Today I learned that you can ignite a creeper with flint and steel! Huh.
|
||||||
|
interactiveTag = InteractiveTag.IGNITE_CREEPER;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DONKEY:
|
||||||
|
case LLAMA:
|
||||||
|
case MULE:
|
||||||
|
if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) && !entityMetadata.getFlags().getFlag(EntityFlag.CHESTED)
|
||||||
|
&& javaIdentifierStripped.equals("chest")) {
|
||||||
|
// Can attach a chest
|
||||||
|
interactiveTag = InteractiveTag.ATTACH_CHEST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Intentional fall-through
|
||||||
|
case HORSE:
|
||||||
|
case SKELETON_HORSE:
|
||||||
|
case TRADER_LLAMA:
|
||||||
|
case ZOMBIE_HORSE:
|
||||||
|
boolean tamed = entityMetadata.getFlags().getFlag(EntityFlag.TAMED);
|
||||||
|
if (session.isSneaking() && tamed && (interactEntity instanceof HorseEntity || entityMetadata.getFlags().getFlag(EntityFlag.CHESTED))) {
|
||||||
|
interactiveTag = InteractiveTag.OPEN_CONTAINER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// have another switch statement as, while these share mount attributes they don't share food
|
||||||
|
switch (interactEntity.getEntityType()) {
|
||||||
|
case LLAMA:
|
||||||
|
case TRADER_LLAMA:
|
||||||
|
if (javaIdentifierStripped.equals("wheat") || javaIdentifierStripped.equals("hay_block")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DONKEY:
|
||||||
|
case HORSE:
|
||||||
|
// Undead can't eat
|
||||||
|
if (DONKEY_AND_HORSE_FOODS.contains(javaIdentifierStripped)) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!entityMetadata.getFlags().getFlag(EntityFlag.BABY)) {
|
||||||
|
// Can't ride a baby
|
||||||
|
if (tamed) {
|
||||||
|
interactiveTag = InteractiveTag.RIDE_HORSE;
|
||||||
|
} else if (itemEntry.equals(ItemEntry.AIR)) {
|
||||||
|
// Can't hide an untamed entity without having your hand empty
|
||||||
|
interactiveTag = InteractiveTag.MOUNT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FOX:
|
||||||
|
if (javaIdentifierStripped.equals("sweet_berries")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HOGLIN:
|
||||||
|
if (javaIdentifierStripped.equals("crimson_fungus")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MINECART:
|
||||||
|
interactiveTag = InteractiveTag.RIDE_MINECART;
|
||||||
|
break;
|
||||||
|
case MINECART_CHEST:
|
||||||
|
case MINECART_COMMAND_BLOCK:
|
||||||
|
case MINECART_HOPPER:
|
||||||
|
interactiveTag = InteractiveTag.OPEN_CONTAINER;
|
||||||
|
break;
|
||||||
|
case OCELOT:
|
||||||
|
if (javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PANDA:
|
||||||
|
if (javaIdentifierStripped.equals("bamboo")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PARROT:
|
||||||
|
if (javaIdentifierStripped.contains("seeds") || javaIdentifierStripped.equals("cookie")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PIG:
|
||||||
|
if (javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("potato") || javaIdentifierStripped.equals("beetroot")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
} else if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||||
|
interactiveTag = InteractiveTag.MOUNT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PIGLIN:
|
||||||
|
if (!entityMetadata.getFlags().getFlag(EntityFlag.BABY) && javaIdentifierStripped.equals("gold_ingot")) {
|
||||||
|
interactiveTag = InteractiveTag.BARTER;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RABBIT:
|
||||||
|
if (javaIdentifierStripped.equals("dandelion") || javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("golden_carrot")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SHEEP:
|
||||||
|
if (javaIdentifierStripped.equals("wheat")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
} else if (!entityMetadata.getFlags().getFlag(EntityFlag.SHEARED)) {
|
||||||
|
if (javaIdentifierStripped.equals("shears")) {
|
||||||
|
// Shear the sheep
|
||||||
|
interactiveTag = InteractiveTag.SHEAR;
|
||||||
|
} else if (javaIdentifierStripped.contains("_dye")) {
|
||||||
|
// Dye the sheep
|
||||||
|
interactiveTag = InteractiveTag.DYE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STRIDER:
|
||||||
|
if (javaIdentifierStripped.equals("warped_fungus")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
} else if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) {
|
||||||
|
interactiveTag = InteractiveTag.RIDE_STRIDER;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TURTLE:
|
||||||
|
if (javaIdentifierStripped.equals("seagrass")) {
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VILLAGER:
|
||||||
|
if (entityMetadata.getInt(EntityData.VARIANT) != 14 && entityMetadata.getInt(EntityData.VARIANT) != 0
|
||||||
|
&& entityMetadata.getFloat(EntityData.SCALE) >= 0.75f) { // Not a nitwit, has a profession and is not a baby
|
||||||
|
interactiveTag = InteractiveTag.TRADE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WANDERING_TRADER:
|
||||||
|
interactiveTag = InteractiveTag.TRADE; // Since you can always trade with a wandering villager, presumably.
|
||||||
|
break;
|
||||||
|
case WOLF:
|
||||||
|
if (javaIdentifierStripped.equals("bone") && !entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) {
|
||||||
|
// Bone and untamed - can tame
|
||||||
|
interactiveTag = InteractiveTag.TAME;
|
||||||
|
} else if (WOLF_FOODS.contains(javaIdentifierStripped)) {
|
||||||
|
// Compatible food in hand - feed
|
||||||
|
// Sometimes just sits/stands when the wolf isn't hungry - there doesn't appear to be a way to fix this
|
||||||
|
interactiveTag = InteractiveTag.FEED;
|
||||||
|
} else if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) &&
|
||||||
|
entityMetadata.getLong(EntityData.OWNER_EID) == session.getPlayerEntity().getGeyserId()) {
|
||||||
|
// Tamed and owned by player - can sit/stand
|
||||||
|
interactiveTag = entityMetadata.getFlags().getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZOMBIE_VILLAGER:
|
||||||
|
// We can't guarantee the existence of the weakness effect so we just always show it.
|
||||||
|
if (javaIdentifierStripped.equals("golden_apple")) {
|
||||||
|
interactiveTag = InteractiveTag.CURE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag.getValue());
|
||||||
|
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All interactive tags in enum form. For potential API usage.
|
||||||
|
*/
|
||||||
|
public enum InteractiveTag {
|
||||||
|
NONE(true),
|
||||||
|
IGNITE_CREEPER("creeper"),
|
||||||
|
EDIT,
|
||||||
|
LEAVE_BOAT("exit.boat"),
|
||||||
|
FEED,
|
||||||
|
FISH("fishing"),
|
||||||
|
MILK,
|
||||||
|
MOOSHROOM_SHEAR("mooshear"),
|
||||||
|
MOOSHROOM_MILK_STEW("moostew"),
|
||||||
|
BOARD_BOAT("ride.boat"),
|
||||||
|
RIDE_MINECART("ride.minecart"),
|
||||||
|
RIDE_HORSE("ride.horse"),
|
||||||
|
RIDE_STRIDER("ride.strider"),
|
||||||
|
SHEAR,
|
||||||
|
SIT,
|
||||||
|
STAND,
|
||||||
|
TALK,
|
||||||
|
TAME,
|
||||||
|
DYE,
|
||||||
|
CURE,
|
||||||
|
OPEN_CONTAINER("opencontainer"),
|
||||||
|
CREATE_MAP("createMap"),
|
||||||
|
TAKE_PICTURE("takepicture"),
|
||||||
|
SADDLE,
|
||||||
|
MOUNT,
|
||||||
|
BOOST,
|
||||||
|
WRITE,
|
||||||
|
LEASH,
|
||||||
|
REMOVE_LEASH("unleash"),
|
||||||
|
NAME,
|
||||||
|
ATTACH_CHEST("attachchest"),
|
||||||
|
TRADE,
|
||||||
|
POSE_ARMOR_STAND("armorstand.pose"),
|
||||||
|
EQUIP_ARMOR_STAND("armorstand.equip"),
|
||||||
|
READ,
|
||||||
|
WAKE_VILLAGER("wakevillager"),
|
||||||
|
BARTER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The full string that should be passed on to the client.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
InteractiveTag(boolean isNone) {
|
||||||
|
this.value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractiveTag(String value) {
|
||||||
|
this.value = "action.interact." + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractiveTag() {
|
||||||
|
this.value = "action.interact." + name().toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren