Merge remote-tracking branch 'refs/remotes/origin/master' into feature/floodgate-merge

# Conflicts:
#	bootstrap/bungeecord/base/build.gradle.kts
#	bootstrap/spigot/base/build.gradle.kts
#	bootstrap/spigot/base/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java
#	bootstrap/velocity/base/build.gradle.kts
#	core/build.gradle.kts
#	core/src/main/java/org/geysermc/geyser/GeyserImpl.java
#	core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java
#	core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java
#	core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java
#	core/src/main/java/org/geysermc/geyser/session/GeyserSession.java
#	core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java
#	core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java
#	gradle.properties
#	gradle/libs.versions.toml
#	settings.gradle.kts
This commit is contained in:
Tim203 2024-05-09 18:04:56 +02:00
commit 9f32ba81b1
No known key found for this signature in database
503 changed files with 19812 additions and 4402 deletions

View file

@ -6,6 +6,10 @@ plugins {
}
dependencies {
constraints {
implementation(libs.raknet) // Ensure protocol does not override the RakNet version
}
api(libs.floodgate.core)
compileOnlyApi(libs.base.api)
compileOnlyApi(projects.isolation)
@ -44,6 +48,8 @@ dependencies {
implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-x86_64" } }
implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-aarch_64" } }
implementation(libs.netty.transport.native.kqueue) { artifact { classifier = "osx-x86_64" } }
implementation(libs.netty.transport.native.io.uring) { artifact { classifier = "linux-x86_64" } }
implementation(libs.netty.transport.native.io.uring) { artifact { classifier = "linux-aarch_64" } }
// Adventure text serialization
api(libs.bundles.adventure)
@ -64,11 +70,6 @@ dependencies {
api(libs.events)
}
configurations.api {
// This is still experimental - additionally, it could only really benefit standalone
exclude(group = "io.netty.incubator", module = "netty-incubator-transport-native-io_uring")
}
tasks.processResources {
// This is solely for backwards compatibility for other programs that used this file before the switch to gradle.
// It used to be generated by the maven Git-Commit-Id-Plugin
@ -99,7 +100,7 @@ configure<BlossomExtension> {
}
fun Project.buildNumber(): Int =
(System.getenv("GITHUB_RUN_NUMBER") ?: jenkinsBuildNumber())?.let { Integer.parseInt(it) } ?: -1
(System.getenv("BUILD_NUMBER"))?.let { Integer.parseInt(it) } ?: -1
inner class GitInfo {
val branch: String
@ -132,9 +133,6 @@ inner class GitInfo {
}
}
// todo remove this when we're not using Jenkins anymore
fun jenkinsBuildNumber(): String? = System.getenv("BUILD_NUMBER")
// Manual task to download the bedrock data files from the CloudburstMC/Data repository
// Invoke with ./gradlew :core:downloadBedrockData --suffix=1_20_70
// Set suffix to the current Bedrock version

View file

@ -29,7 +29,6 @@ import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.steveice10.packetlib.tcp.TcpSession;
import io.netty.channel.epoll.Epoll;
import io.netty.util.NettyRuntime;
import io.netty.util.concurrent.DefaultThreadFactory;
@ -46,7 +45,6 @@ import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
import org.geysermc.api.Geyser;
import org.geysermc.cumulus.form.Form;
import org.geysermc.cumulus.form.util.FormBuilder;
import org.geysermc.erosion.packet.Packets;
import org.geysermc.floodgate.core.FloodgatePlatform;
import org.geysermc.geyser.api.GeyserApi;
import org.geysermc.geyser.api.command.CommandSource;
@ -86,6 +84,7 @@ import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.*;
import org.geysermc.mcprotocollib.network.tcp.TcpSession;
import java.io.File;
import java.io.FileWriter;
@ -394,7 +393,7 @@ public class GeyserImpl implements GeyserApi {
pendingMicrosoftAuthentication = new PendingMicrosoftAuthentication(config.getPendingAuthenticationTimeout());
Packets.initGeyser();
//Packets.initGeyser();
if (Epoll.isAvailable()) {
this.erosionUnixListener = new UnixSocketClientListener();

View file

@ -25,12 +25,12 @@
package org.geysermc.geyser.command.defaults;
import com.github.steveice10.mc.protocol.data.game.ClientCommand;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.command.GeyserCommand;
import org.geysermc.geyser.command.GeyserCommandSource;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.ClientCommand;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket;
public class StatisticsCommand extends GeyserCommand {

View file

@ -40,9 +40,11 @@ import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.network.CIDRMatcher;
import org.geysermc.geyser.text.AsteriskSerializer;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.util.WebUtils;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
@ -245,7 +247,18 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
List<CIDRMatcher> matchers = this.whitelistedIPsMatchers;
if (matchers == null) {
synchronized (this) {
this.whitelistedIPsMatchers = matchers = proxyProtocolWhitelistedIPs.stream()
// Check if proxyProtocolWhitelistedIPs contains URLs we need to fetch and parse by line
List<String> whitelistedCIDRs = new ArrayList<>();
for (String ip: proxyProtocolWhitelistedIPs) {
if (!ip.startsWith("http")) {
whitelistedCIDRs.add(ip);
continue;
}
WebUtils.getLineStream(ip).forEach(whitelistedCIDRs::add);
}
this.whitelistedIPsMatchers = matchers = whitelistedCIDRs.stream()
.map(CIDRMatcher::new)
.collect(Collectors.toList());
}

View file

@ -27,8 +27,8 @@ package org.geysermc.geyser.dump;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.text.AsteriskSerializer;
import java.util.List;

View file

@ -55,12 +55,7 @@ import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.*;
import java.util.stream.Collectors;
@Getter
@ -77,6 +72,7 @@ public class DumpInfo {
private final GeyserConfiguration config;
private final Floodgate floodgate;
private final Object2IntMap<BedrockPlatform> userPlatforms;
private final int connectionAttempts;
private final HashInfo hashInfo;
private final RamInfo ramInfo;
private LogsInfo logsInfo;
@ -128,6 +124,8 @@ public class DumpInfo {
userPlatforms.put(device, userPlatforms.getOrDefault(device, 0) + 1);
}
this.connectionAttempts = GeyserImpl.getInstance().getGeyserServer().getConnectionAttempts();
this.bootstrapInfo = GeyserImpl.getInstance().getBootstrap().getDumpInfo();
this.flagsInfo = new FlagsInfo();

View file

@ -25,14 +25,15 @@
package org.geysermc.geyser.entity;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.entity.factory.EntityFactory;
import org.geysermc.geyser.entity.properties.GeyserEntityProperties;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.translator.entity.EntityMetadataTranslator;
@ -49,10 +50,10 @@ import java.util.function.BiConsumer;
* @param <T> the entity type this definition represents
*/
public record EntityDefinition<T extends Entity>(EntityFactory<T> factory, EntityType entityType, String identifier,
float width, float height, float offset, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
float width, float height, float offset, GeyserEntityProperties registeredProperties, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
public static <T extends Entity> Builder<T> inherited(EntityFactory<T> factory, EntityDefinition<? super T> parent) {
return new Builder<>(factory, parent.entityType, parent.identifier, parent.width, parent.height, parent.offset, new ObjectArrayList<>(parent.translators));
return new Builder<>(factory, parent.entityType, parent.identifier, parent.width, parent.height, parent.offset, parent.registeredProperties, new ObjectArrayList<>(parent.translators));
}
public static <T extends Entity> Builder<T> builder(EntityFactory<T> factory) {
@ -87,6 +88,7 @@ public record EntityDefinition<T extends Entity>(EntityFactory<T> factory, Entit
private float width;
private float height;
private float offset = 0.00001f;
private GeyserEntityProperties registeredProperties;
private final List<EntityMetadataTranslator<? super T, ?, ?>> translators;
private Builder(EntityFactory<T> factory) {
@ -94,13 +96,14 @@ public record EntityDefinition<T extends Entity>(EntityFactory<T> factory, Entit
translators = new ObjectArrayList<>();
}
public Builder(EntityFactory<T> factory, EntityType type, String identifier, float width, float height, float offset, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
public Builder(EntityFactory<T> factory, EntityType type, String identifier, float width, float height, float offset, GeyserEntityProperties registeredProperties, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
this.factory = factory;
this.type = type;
this.identifier = identifier;
this.width = width;
this.height = height;
this.offset = offset;
this.registeredProperties = registeredProperties;
this.translators = translators;
}
@ -127,6 +130,11 @@ public record EntityDefinition<T extends Entity>(EntityFactory<T> factory, Entit
return this;
}
public Builder<T> properties(GeyserEntityProperties registeredProperties) {
this.registeredProperties = registeredProperties;
return this;
}
public <U, EM extends EntityMetadata<U, ? extends MetadataType<U>>> Builder<T> addTranslator(MetadataType<U> type, BiConsumer<T, EM> translateFunction) {
translators.add(new EntityMetadataTranslator<>(type, translateFunction));
return this;
@ -149,10 +157,13 @@ public record EntityDefinition<T extends Entity>(EntityFactory<T> factory, Entit
if (identifier == null && type != null) {
identifier = "minecraft:" + type.name().toLowerCase(Locale.ROOT);
}
EntityDefinition<T> definition = new EntityDefinition<>(factory, type, identifier, width, height, offset, translators);
EntityDefinition<T> definition = new EntityDefinition<>(factory, type, identifier, width, height, offset, registeredProperties, translators);
if (register && definition.entityType() != null) {
Registries.ENTITY_DEFINITIONS.get().putIfAbsent(definition.entityType(), definition);
Registries.JAVA_ENTITY_IDENTIFIERS.get().putIfAbsent("minecraft:" + type.name().toLowerCase(Locale.ROOT), definition);
if (definition.registeredProperties() != null) {
Registries.BEDROCK_ENTITY_PROPERTIES.get().add(definition.registeredProperties().toNbtMap(identifier));
}
}
return definition;
}

View file

@ -25,12 +25,14 @@
package org.geysermc.geyser.entity;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import org.geysermc.geyser.entity.type.living.monster.raid.RavagerEntity;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.properties.GeyserEntityProperties;
import org.geysermc.geyser.entity.type.*;
import org.geysermc.geyser.entity.type.living.*;
import org.geysermc.geyser.entity.type.living.animal.*;
@ -53,8 +55,9 @@ import org.geysermc.geyser.translator.text.MessageTranslator;
public final class EntityDefinitions {
public static final EntityDefinition<AllayEntity> ALLAY;
public static final EntityDefinition<AreaEffectCloudEntity> AREA_EFFECT_CLOUD;
public static final EntityDefinition<ArmadilloEntity> ARMADILLO;
public static final EntityDefinition<ArmorStandEntity> ARMOR_STAND;
public static final EntityDefinition<TippedArrowEntity> ARROW;
public static final EntityDefinition<ArrowEntity> ARROW;
public static final EntityDefinition<AxolotlEntity> AXOLOTL;
public static final EntityDefinition<BatEntity> BAT;
public static final EntityDefinition<BeeEntity> BEE;
@ -130,7 +133,7 @@ public final class EntityDefinitions {
public static final EntityDefinition<ThrownPotionEntity> POTION;
public static final EntityDefinition<PufferFishEntity> PUFFERFISH;
public static final EntityDefinition<RabbitEntity> RABBIT;
public static final EntityDefinition<RaidParticipantEntity> RAVAGER;
public static final EntityDefinition<RavagerEntity> RAVAGER;
public static final EntityDefinition<AbstractFishEntity> SALMON;
public static final EntityDefinition<SheepEntity> SHEEP;
public static final EntityDefinition<ShulkerEntity> SHULKER;
@ -200,7 +203,6 @@ public final class EntityDefinitions {
.type(EntityType.AREA_EFFECT_CLOUD)
.height(0.5f).width(1.0f)
.addTranslator(MetadataType.FLOAT, AreaEffectCloudEntity::setRadius)
.addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.EFFECT_COLOR, entityMetadata.getValue()))
.addTranslator(null) // Waiting
.addTranslator(MetadataType.PARTICLE, AreaEffectCloudEntity::setParticle)
.build();
@ -376,10 +378,10 @@ public final class EntityDefinitions {
.addTranslator(MetadataType.BYTE, AbstractArrowEntity::setArrowFlags)
.addTranslator(null) // "Piercing level"
.build();
ARROW = EntityDefinition.inherited(TippedArrowEntity::new, abstractArrowBase)
ARROW = EntityDefinition.inherited(ArrowEntity::new, abstractArrowBase)
.type(EntityType.ARROW)
.heightAndWidth(0.25f)
.addTranslator(MetadataType.INT, TippedArrowEntity::setPotionEffectColor)
.addTranslator(MetadataType.INT, ArrowEntity::setPotionEffectColor)
.build();
SPECTRAL_ARROW = EntityDefinition.inherited(abstractArrowBase.factory(), abstractArrowBase)
.type(EntityType.SPECTRAL_ARROW)
@ -452,8 +454,7 @@ public final class EntityDefinitions {
EntityDefinition<LivingEntity> livingEntityBase = EntityDefinition.inherited(LivingEntity::new, entityBase)
.addTranslator(MetadataType.BYTE, LivingEntity::setLivingEntityFlags)
.addTranslator(MetadataType.FLOAT, LivingEntity::setHealth)
.addTranslator(MetadataType.INT,
(livingEntity, entityMetadata) -> livingEntity.getDirtyMetadata().put(EntityDataTypes.EFFECT_COLOR, entityMetadata.getValue()))
.addTranslator(MetadataType.PARTICLES, LivingEntity::setParticles)
.addTranslator(MetadataType.BOOLEAN,
(livingEntity, entityMetadata) -> livingEntity.getDirtyMetadata().put(EntityDataTypes.EFFECT_AMBIENCE, (byte) (((BooleanEntityMetadata) entityMetadata).getPrimitiveValue() ? 1 : 0)))
.addTranslator(null) // Arrow count
@ -672,7 +673,7 @@ public final class EntityDefinitions {
SLIME = EntityDefinition.inherited(SlimeEntity::new, mobEntityBase)
.type(EntityType.SLIME)
.heightAndWidth(0.51f)
.addTranslator(MetadataType.INT, SlimeEntity::setScale)
.addTranslator(MetadataType.INT, SlimeEntity::setSlimeScale)
.build();
MAGMA_CUBE = EntityDefinition.inherited(MagmaCubeEntity::new, SLIME)
.type(EntityType.MAGMA_CUBE)
@ -745,9 +746,9 @@ public final class EntityDefinitions {
.type(EntityType.PILLAGER)
.height(1.8f).width(0.6f)
.offset(1.62f)
.addTranslator(null) // Charging; doesn't have an equivalent on Bedrock //TODO check
.addTranslator(MetadataType.BOOLEAN, PillagerEntity::setChargingCrossbow)
.build();
RAVAGER = EntityDefinition.inherited(raidParticipantEntityBase.factory(), raidParticipantEntityBase)
RAVAGER = EntityDefinition.inherited(RavagerEntity::new, raidParticipantEntityBase)
.type(EntityType.RAVAGER)
.height(1.9f).width(1.2f)
.build();
@ -770,6 +771,20 @@ public final class EntityDefinitions {
// Extends ageable
{
ARMADILLO = EntityDefinition.inherited(ArmadilloEntity::new, ageableEntityBase)
.type(EntityType.ARMADILLO)
.height(0.65f).width(0.7f)
.properties(new GeyserEntityProperties.Builder()
.addEnum(
"minecraft:armadillo_state",
"unrolled",
"rolled_up",
"rolled_up_peeking",
"rolled_up_relaxing",
"rolled_up_unrolling")
.build())
.addTranslator(MetadataType.ARMADILLO_STATE, ArmadilloEntity::setArmadilloState)
.build();
AXOLOTL = EntityDefinition.inherited(AxolotlEntity::new, ageableEntityBase)
.type(EntityType.AXOLOTL)
.height(0.42f).width(0.7f)
@ -780,6 +795,9 @@ public final class EntityDefinitions {
BEE = EntityDefinition.inherited(BeeEntity::new, ageableEntityBase)
.type(EntityType.BEE)
.heightAndWidth(0.6f)
.properties(new GeyserEntityProperties.Builder()
.addBoolean("minecraft:has_nectar")
.build())
.addTranslator(MetadataType.BYTE, BeeEntity::setBeeFlags)
.addTranslator(MetadataType.INT, BeeEntity::setAngerTime)
.build();
@ -937,8 +955,7 @@ public final class EntityDefinitions {
LLAMA = EntityDefinition.inherited(LlamaEntity::new, chestedHorseEntityBase)
.type(EntityType.LLAMA)
.height(1.87f).width(0.9f)
.addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.STRENGTH, entityMetadata.getValue()))
.addTranslator(MetadataType.INT, LlamaEntity::setCarpetedColor)
.addTranslator(MetadataType.INT, LlamaEntity::setStrength)
.addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.VARIANT, entityMetadata.getValue()))
.build();
TRADER_LLAMA = EntityDefinition.inherited(TraderLlamaEntity::new, LLAMA)
@ -947,7 +964,7 @@ public final class EntityDefinitions {
.build();
}
EntityDefinition<TameableEntity> tameableEntityBase = EntityDefinition.inherited(TameableEntity::new, ageableEntityBase)
EntityDefinition<TameableEntity> tameableEntityBase = EntityDefinition.<TameableEntity>inherited(null, ageableEntityBase) // No factory, is abstract
.addTranslator(MetadataType.BYTE, TameableEntity::setTameableFlags)
.addTranslator(MetadataType.OPTIONAL_UUID, TameableEntity::setOwner)
.build();
@ -971,6 +988,7 @@ public final class EntityDefinitions {
.addTranslator(MetadataType.BOOLEAN, (wolfEntity, entityMetadata) -> wolfEntity.setFlag(EntityFlag.INTERESTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
.addTranslator(MetadataType.INT, WolfEntity::setCollarColor)
.addTranslator(MetadataType.INT, WolfEntity::setWolfAngerTime)
.addTranslator(MetadataType.WOLF_VARIANT, WolfEntity::setWolfVariant)
.build();
// As of 1.18 these don't track entity data at all

View file

@ -49,9 +49,10 @@ public enum GeyserAttributeType {
ATTACK_KNOCKBACK("minecraft:generic.attack_knockback", null, 1.5f, Float.MAX_VALUE, 0f),
ATTACK_SPEED("minecraft:generic.attack_speed", null, 0f, 1024f, 4f),
MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f),
SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f), // Unused. Do we need this?
// Bedrock Attributes
ABSORPTION(null, "minecraft:absorption", 0f, Float.MAX_VALUE, 0f),
ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f),
EXHAUSTION(null, "minecraft:player.exhaustion", 0f, 5f, 0f),
EXPERIENCE(null, "minecraft:player.experience", 0f, 1f, 0f),
EXPERIENCE_LEVEL(null, "minecraft:player.level", 0f, 24791.00f, 0f),
@ -66,6 +67,10 @@ public enum GeyserAttributeType {
private final float maximum;
private final float defaultValue;
public AttributeData getAttribute() {
return getAttribute(defaultValue);
}
public AttributeData getAttribute(float value) {
return getAttribute(value, maximum);
}

View file

@ -0,0 +1,165 @@
/*
* Copyright (c) 2019-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.properties;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.geysermc.geyser.entity.properties.type.BooleanProperty;
import org.geysermc.geyser.entity.properties.type.EnumProperty;
import org.geysermc.geyser.entity.properties.type.FloatProperty;
import org.geysermc.geyser.entity.properties.type.IntProperty;
import org.geysermc.geyser.entity.properties.type.PropertyType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@EqualsAndHashCode
@ToString
public class GeyserEntityProperties {
private final ObjectArrayList<PropertyType> properties;
private final Object2IntMap<String> propertyIndices;
private GeyserEntityProperties(ObjectArrayList<PropertyType> properties,
Object2IntMap<String> propertyIndices) {
this.properties = properties;
this.propertyIndices = propertyIndices;
}
public NbtMap toNbtMap(String entityType) {
NbtMapBuilder mapBuilder = NbtMap.builder();
List<NbtMap> nbtProperties = new ArrayList<>();
for (PropertyType property : properties) {
nbtProperties.add(property.nbtMap());
}
mapBuilder.putList("properties", NbtType.COMPOUND, nbtProperties);
return mapBuilder.putString("type", entityType).build();
}
public @NonNull List<PropertyType> getProperties() {
return properties;
}
public int getPropertyIndex(String name) {
return propertyIndices.getOrDefault(name, -1);
}
public static class Builder {
private final ObjectArrayList<PropertyType> properties = new ObjectArrayList<>();
private final Object2IntMap<String> propertyIndices = new Object2IntOpenHashMap<>();
public Builder addInt(@NonNull String name, int min, int max) {
if (propertyIndices.containsKey(name)) {
throw new IllegalArgumentException(
"Property with name " + name + " already exists on builder!");
}
PropertyType property = new IntProperty(name, min, max);
this.properties.add(property);
propertyIndices.put(name, properties.size() - 1);
return this;
}
public Builder addInt(@NonNull String name) {
if (propertyIndices.containsKey(name)) {
throw new IllegalArgumentException(
"Property with name " + name + " already exists on builder!");
}
PropertyType property = new IntProperty(name, Integer.MIN_VALUE, Integer.MAX_VALUE);
this.properties.add(property);
propertyIndices.put(name, properties.size() - 1);
return this;
}
public Builder addFloat(@NonNull String name, float min, float max) {
if (propertyIndices.containsKey(name)) {
throw new IllegalArgumentException(
"Property with name " + name + " already exists on builder!");
}
PropertyType property = new FloatProperty(name, min, max);
this.properties.add(property);
propertyIndices.put(name, properties.size() - 1);
return this;
}
public Builder addFloat(@NonNull String name) {
if (propertyIndices.containsKey(name)) {
throw new IllegalArgumentException(
"Property with name " + name + " already exists on builder!");
}
PropertyType property = new FloatProperty(name, Float.MIN_NORMAL, Float.MAX_VALUE);
this.properties.add(property);
propertyIndices.put(name, properties.size() - 1);
return this;
}
public Builder addBoolean(@NonNull String name) {
if (propertyIndices.containsKey(name)) {
throw new IllegalArgumentException(
"Property with name " + name + " already exists on builder!");
}
PropertyType property = new BooleanProperty(name);
this.properties.add(property);
propertyIndices.put(name, properties.size() - 1);
return this;
}
public Builder addEnum(@NonNull String name, List<String> values) {
if (propertyIndices.containsKey(name)) {
throw new IllegalArgumentException(
"Property with name " + name + " already exists on builder!");
}
PropertyType property = new EnumProperty(name, values);
this.properties.add(property);
propertyIndices.put(name, properties.size() - 1);
return this;
}
public Builder addEnum(@NonNull String name, String... values) {
if (propertyIndices.containsKey(name)) {
throw new IllegalArgumentException(
"Property with name " + name + " already exists on builder!");
}
List<String> valuesList = Arrays.asList(values); // Convert array to list
PropertyType property = new EnumProperty(name, valuesList);
this.properties.add(property);
propertyIndices.put(name, properties.size() - 1);
return this;
}
public GeyserEntityProperties build() {
return new GeyserEntityProperties(properties, propertyIndices);
}
}
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2019-2023 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.properties;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import org.cloudburstmc.protocol.bedrock.data.entity.FloatEntityProperty;
import org.cloudburstmc.protocol.bedrock.data.entity.IntEntityProperty;
import org.geysermc.geyser.entity.properties.type.EnumProperty;
import org.geysermc.geyser.entity.properties.type.PropertyType;
import java.util.List;
public class GeyserEntityPropertyManager {
private final GeyserEntityProperties properties;
private final ObjectArrayList<IntEntityProperty> intEntityProperties = new ObjectArrayList<>();
private final ObjectArrayList<FloatEntityProperty> floatEntityProperties = new ObjectArrayList<>();
public GeyserEntityPropertyManager(GeyserEntityProperties properties) {
this.properties = properties;
}
public void add(String propertyName, int value) {
int index = properties.getPropertyIndex(propertyName);
intEntityProperties.add(new IntEntityProperty(index, value));
}
public void add(String propertyName, boolean value) {
int index = properties.getPropertyIndex(propertyName);
intEntityProperties.add(new IntEntityProperty(index, value ? 1 : 0));
}
public void add(String propertyName, String value) {
int index = properties.getPropertyIndex(propertyName);
PropertyType property = properties.getProperties().get(index);
int enumIndex = ((EnumProperty) property).getIndex(value);
intEntityProperties.add(new IntEntityProperty(index, enumIndex));
}
public void add(String propertyName, float value) {
int index = properties.getPropertyIndex(propertyName);
floatEntityProperties.add(new FloatEntityProperty(index, value));
}
public boolean hasFloatProperties() {
return !this.floatEntityProperties.isEmpty();
}
public boolean hasIntProperties() {
return !this.intEntityProperties.isEmpty();
}
public boolean hasProperties() {
return hasFloatProperties() || hasIntProperties();
}
public ObjectArrayList<IntEntityProperty> intProperties() {
return this.intEntityProperties;
}
public void applyIntProperties(List<IntEntityProperty> properties) {
properties.addAll(intEntityProperties);
intEntityProperties.clear();
}
public ObjectArrayList<FloatEntityProperty> floatProperties() {
return this.floatEntityProperties;
}
public void applyFloatProperties(List<FloatEntityProperty> properties) {
properties.addAll(floatEntityProperties);
floatEntityProperties.clear();
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2019-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.properties.type;
import org.cloudburstmc.nbt.NbtMap;
public class BooleanProperty implements PropertyType {
private final String name;
public BooleanProperty(String name) {
this.name = name;
}
@Override
public NbtMap nbtMap() {
return NbtMap.builder()
.putString("name", name)
.putInt("type", 2)
.build();
}
}

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2019-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.properties.type;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType;
import java.util.List;
public class EnumProperty implements PropertyType {
private final String name;
private final List<String> values;
private final Object2IntMap<String> valueIndexMap;
public EnumProperty(String name, List<String> values) {
this.name = name;
this.values = values;
this.valueIndexMap = new Object2IntOpenHashMap<>(values.size());
for (int i = 0; i < values.size(); i++) {
valueIndexMap.put(values.get(i), i);
}
}
@Override
public NbtMap nbtMap() {
return NbtMap.builder()
.putString("name", name)
.putList("enum", NbtType.STRING, values)
.putInt("type", 3)
.build();
}
public int getIndex(String value) {
return valueIndexMap.getOrDefault(value, -1);
}
}

View file

@ -23,34 +23,28 @@
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.item;
package org.geysermc.geyser.entity.properties.type;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.IntTag;
import org.cloudburstmc.nbt.NbtMap;
public interface DyeableLeatherItem {
public class FloatProperty implements PropertyType {
private final String name;
private final float max;
private final float min;
static void translateNbtToBedrock(CompoundTag tag) {
CompoundTag displayTag = tag.get("display");
if (displayTag == null) {
return;
}
IntTag color = displayTag.remove("color");
if (color != null) {
tag.put(new IntTag("customColor", color.getValue()));
}
public FloatProperty(String name, float min, float max) {
this.name = name;
this.max = max;
this.min = min;
}
static void translateNbtToJava(CompoundTag tag) {
IntTag color = tag.get("customColor");
if (color == null) {
return;
}
CompoundTag displayTag = tag.get("display");
if (displayTag == null) {
displayTag = new CompoundTag("display");
}
displayTag.put(color);
tag.remove("customColor");
@Override
public NbtMap nbtMap() {
return NbtMap.builder()
.putString("name", name)
.putFloat("max", max)
.putFloat("min", min)
.putInt("type", 1)
.build();
}
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2019-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.properties.type;
import org.cloudburstmc.nbt.NbtMap;
public class IntProperty implements PropertyType {
private final String name;
private final int max;
private final int min;
public IntProperty(String name, int min, int max) {
this.name = name;
this.max = max;
this.min = min;
}
@Override
public NbtMap nbtMap() {
return NbtMap.builder()
.putString("name", name)
.putInt("max", max)
.putInt("min", min)
.putInt("type", 0)
.build();
}
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2019-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.properties.type;
import org.cloudburstmc.nbt.NbtMap;
public interface PropertyType {
NbtMap nbtMap();
}

View file

@ -25,8 +25,8 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;

View file

@ -25,9 +25,6 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.level.particle.Particle;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.ParticleType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
@ -35,6 +32,11 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.MathUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle;
import java.util.UUID;
@ -51,7 +53,7 @@ public class AreaEffectCloudEntity extends Entity {
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_DURATION, Integer.MAX_VALUE);
// This disabled client side shrink of the cloud
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_RADIUS, 0.0f);
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_RADIUS, 3.0f);
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_CHANGE_RATE, Float.MIN_VALUE);
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, Float.MIN_VALUE);
@ -60,7 +62,7 @@ public class AreaEffectCloudEntity extends Entity {
public void setRadius(FloatEntityMetadata entityMetadata) {
// Anything less than 0.5 will cause the cloud to despawn
float value = Math.max(entityMetadata.getPrimitiveValue(), 0.5f);
float value = MathUtils.clamp(entityMetadata.getPrimitiveValue(), 0.5f, 32.0f);
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_RADIUS, value);
dirtyMetadata.put(EntityDataTypes.WIDTH, 2.0f * value);
}
@ -69,5 +71,9 @@ public class AreaEffectCloudEntity extends Entity {
Particle particle = entityMetadata.getValue();
Registries.PARTICLES.map(particle.getType(), p -> p.levelEventType() instanceof ParticleType particleType ? particleType : null).ifPresent(type ->
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_PARTICLE, type));
if (particle.getData() instanceof EntityEffectParticleData effectParticleData) {
dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, effectParticleData.getColor());
}
}
}

View file

@ -25,21 +25,18 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.item.TippedArrowPotion;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
/**
* Internally this is known as TippedArrowEntity but is used with tipped arrows and normal arrows
*/
public class TippedArrowEntity extends AbstractArrowEntity {
public class ArrowEntity extends AbstractArrowEntity {
public TippedArrowEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
public ArrowEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}

View file

@ -25,24 +25,23 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import lombok.Getter;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket;
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
import lombok.Getter;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class BoatEntity extends Entity {
public class BoatEntity extends Entity implements Tickable {
/**
* Required when IS_BUOYANT is sent in order for boats to work in the water. <br>
@ -58,6 +57,7 @@ public class BoatEntity extends Entity {
private float paddleTimeLeft;
private boolean isPaddlingRight;
private float paddleTimeRight;
private boolean doTick;
/**
* Saved for using the "pick" functionality on a boat.
@ -133,34 +133,16 @@ public class BoatEntity extends Entity {
public void setPaddlingLeft(BooleanEntityMetadata entityMetadata) {
isPaddlingLeft = entityMetadata.getPrimitiveValue();
if (isPaddlingLeft) {
// 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;
if (!this.passengers.isEmpty()) {
// Get the entity by the first stored passenger and convey motion in this manner
Entity entity = this.passengers.get(0);
if (entity != null) {
updateLeftPaddle(session, entity);
}
}
} else {
// Indicate that the row position should be reset
if (!isPaddlingLeft) {
paddleTimeLeft = 0.0f;
dirtyMetadata.put(EntityDataTypes.ROW_TIME_LEFT, 0.0f);
}
}
public void setPaddlingRight(BooleanEntityMetadata entityMetadata) {
isPaddlingRight = entityMetadata.getPrimitiveValue();
if (isPaddlingRight) {
paddleTimeRight = 0f;
if (!this.passengers.isEmpty()) {
Entity entity = this.passengers.get(0);
if (entity != null) {
updateRightPaddle(session, entity);
}
}
} else {
if (!isPaddlingRight) {
paddleTimeRight = 0.0f;
dirtyMetadata.put(EntityDataTypes.ROW_TIME_RIGHT, 0.0f);
}
}
@ -186,29 +168,26 @@ public class BoatEntity extends Entity {
}
}
private void updateLeftPaddle(GeyserSession session, Entity rower) {
@Override
public void tick() {
// Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
doTick = !doTick; // Run every 100 ms
if (!doTick || passengers.isEmpty()) {
return;
}
Entity rower = passengers.get(0);
if (rower == null) {
return;
}
if (isPaddlingLeft) {
paddleTimeLeft += ROWING_SPEED;
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_LEFT, paddleTimeLeft);
session.scheduleInEventLoop(() ->
updateLeftPaddle(session, rower),
100,
TimeUnit.MILLISECONDS
);
}
}
private void updateRightPaddle(GeyserSession session, Entity rower) {
if (isPaddlingRight) {
paddleTimeRight += ROWING_SPEED;
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_RIGHT, paddleTimeRight);
session.scheduleInEventLoop(() ->
updateRightPaddle(session, rower),
100,
TimeUnit.MILLISECONDS
);
}
}

View file

@ -25,12 +25,12 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;

View file

@ -25,7 +25,7 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;

View file

@ -25,8 +25,8 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;

View file

@ -25,7 +25,7 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;

View file

@ -25,13 +25,6 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
@ -42,27 +35,26 @@ import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket;
import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.*;
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.session.GeyserSession;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.geyser.util.MathUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
@Getter
@Setter
@ -126,6 +118,8 @@ public class Entity implements GeyserEntity {
@Setter(AccessLevel.PROTECTED) // For players
private boolean flagsDirty = false;
protected final GeyserEntityPropertyManager propertyManager;
public Entity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
this.session = session;
@ -140,6 +134,8 @@ public class Entity implements GeyserEntity {
this.valid = false;
this.propertyManager = new GeyserEntityPropertyManager(definition.registeredProperties());
setPosition(position);
setAirSupply(getMaxAir());
@ -200,11 +196,9 @@ public class Entity implements GeyserEntity {
/**
* Despawns the entity
*
* @return can be deleted
*/
public boolean despawnEntity() {
if (!valid) return true;
public void despawnEntity() {
if (!valid) return;
for (Entity passenger : passengers) { // Make sure all passengers on the despawned entity are updated
if (passenger == null) continue;
@ -218,7 +212,6 @@ public class Entity implements GeyserEntity {
session.sendUpstreamPacket(removeEntityPacket);
valid = false;
return true;
}
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) {
@ -360,6 +353,23 @@ public class Entity implements GeyserEntity {
}
}
/**
* Sends the Bedrock entity properties to the client
*/
public void updateBedrockEntityProperties() {
if (!valid) {
return;
}
if (propertyManager.hasProperties()) {
SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
entityDataPacket.setRuntimeEntityId(geyserId);
propertyManager.applyIntProperties(entityDataPacket.getProperties().getIntProperties());
propertyManager.applyFloatProperties(entityDataPacket.getProperties().getFloatProperties());
session.sendUpstreamPacket(entityDataPacket);
}
}
public void setFlags(ByteEntityMetadata entityMetadata) {
byte xd = entityMetadata.getPrimitiveValue();
setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire

View file

@ -25,12 +25,12 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
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.EntityDefinitions;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;

View file

@ -72,6 +72,9 @@ public class FireballEntity extends ThrowableEntity {
@Override
public void tick() {
if (removedInVoid()) {
return;
}
moveAbsoluteImmediate(tickMovement(position), getYaw(), getPitch(), getHeadYaw(), false, false);
}
}

View file

@ -25,25 +25,18 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.level.FireworkColor;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.MathUtils;
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalInt;
import java.util.UUID;
@ -58,73 +51,16 @@ public class FireworkEntity extends Entity {
if (item == null) {
return;
}
CompoundTag tag = item.getNbt();
if (tag == null) {
DataComponents components = item.getDataComponents();
if (components == null) {
return;
}
CompoundTag fireworks = tag.get("Fireworks");
if (fireworks == null) {
// Thank you Mineplex very cool
return;
}
// TODO this looked the same, so I'm going to assume it is and (keep below comment if true)
// Translate using item methods to get firework NBT for Bedrock
BedrockItemBuilder builder = new BedrockItemBuilder();
Items.FIREWORK_ROCKET.translateComponentsToBedrock(session, components, builder);
NbtMapBuilder fireworksBuilder = NbtMap.builder();
if (fireworks.get("Flight") != null) {
fireworksBuilder.putByte("Flight", MathUtils.getNbtByte(fireworks.get("Flight").getValue()));
}
List<NbtMap> explosions = new ArrayList<>();
if (fireworks.get("Explosions") != null) {
for (Tag effect : ((ListTag) fireworks.get("Explosions")).getValue()) {
CompoundTag effectData = (CompoundTag) effect;
NbtMapBuilder effectBuilder = NbtMap.builder();
if (effectData.get("Type") != null) {
effectBuilder.putByte("FireworkType", MathUtils.getNbtByte(effectData.get("Type").getValue()));
}
if (effectData.get("Colors") != null) {
int[] oldColors = (int[]) effectData.get("Colors").getValue();
byte[] colors = new byte[oldColors.length];
int i = 0;
for (int color : oldColors) {
colors[i++] = FireworkColor.fromJavaRGB(color);
}
effectBuilder.putByteArray("FireworkColor", colors);
}
if (effectData.get("FadeColors") != null) {
int[] oldColors = (int[]) effectData.get("FadeColors").getValue();
byte[] colors = new byte[oldColors.length];
int i = 0;
for (int color : oldColors) {
colors[i++] = FireworkColor.fromJavaRGB(color);
}
effectBuilder.putByteArray("FireworkFade", colors);
}
if (effectData.get("Trail") != null) {
effectBuilder.putByte("FireworkTrail", MathUtils.getNbtByte(effectData.get("Trail").getValue()));
}
if (effectData.get("Flicker") != null) {
effectBuilder.putByte("FireworkFlicker", MathUtils.getNbtByte(effectData.get("Flicker").getValue()));
}
explosions.add(effectBuilder.build());
}
}
fireworksBuilder.putList("Explosions", NbtType.COMPOUND, explosions);
NbtMapBuilder builder = NbtMap.builder();
builder.put("Fireworks", fireworksBuilder.build());
dirtyMetadata.put(EntityDataTypes.DISPLAY_FIREWORK, builder.build());
}

View file

@ -25,11 +25,10 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import lombok.Getter;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket;
import lombok.Getter;
import org.geysermc.erosion.util.BlockPositionIterator;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
@ -38,6 +37,7 @@ import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.util.BlockUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
@ -133,6 +133,9 @@ public class FishingHookEntity extends ThrowableEntity {
@Override
public void tick() {
if (removedInVoid()) {
return;
}
if (hooked || !isInAir() && !isInWater() || isOnGround()) {
motion = Vector3f.ZERO;
return;

View file

@ -25,8 +25,8 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;

View file

@ -25,16 +25,16 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
import java.util.UUID;

View file

@ -25,8 +25,6 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
@ -37,7 +35,9 @@ import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@ -74,7 +74,7 @@ public class ItemEntity extends ThrowableEntity {
@Override
public void tick() {
if (isInWater()) {
if (removedInVoid() || isInWater()) {
return;
}
if (!isOnGround() || (motion.getX() * motion.getX() + motion.getZ() * motion.getZ()) > 0.00001) {

View file

@ -25,12 +25,7 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import lombok.Getter;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap;
@ -39,12 +34,17 @@ import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
import lombok.Getter;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InventoryUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import java.util.UUID;
@ -148,7 +148,7 @@ public class ItemFrameEntity extends Entity {
}
@Override
public boolean despawnEntity() {
public void despawnEntity() {
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0);
updateBlockPacket.setBlockPosition(bedrockPosition);
@ -161,7 +161,6 @@ public class ItemFrameEntity extends Entity {
session.getItemFrameCache().remove(bedrockPosition, this);
valid = false;
return true;
}
private NbtMap getDefaultTag() {

View file

@ -25,11 +25,11 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;

View file

@ -25,16 +25,6 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute;
import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
@ -55,8 +45,23 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.geyser.util.AttributeUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.Attribute;
import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle;
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType;
import java.util.*;
@ -69,7 +74,7 @@ public class LivingEntity extends Entity {
protected ItemData leggings = ItemData.AIR;
protected ItemData boots = ItemData.AIR;
protected ItemData hand = ItemData.AIR;
protected ItemData offHand = ItemData.AIR;
protected ItemData offhand = ItemData.AIR;
@Getter(value = AccessLevel.NONE)
protected float health = 1f; // The default value in Java Edition before any entity metadata is sent
@ -81,12 +86,58 @@ public class LivingEntity extends Entity {
*/
private boolean isMaxFrozenState = false;
/**
* The base scale entity data, without attributes applied. Used for such cases as baby variants.
*/
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private float scale;
/**
* The scale sent through the Java attributes packet
*/
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private float attributeScale;
public LivingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
public void setHelmet(ItemStack stack) {
this.helmet = ItemTranslator.translateToBedrock(session, stack);
}
public void setChestplate(ItemStack stack) {
this.chestplate = ItemTranslator.translateToBedrock(session, stack);
}
public void setLeggings(ItemStack stack) {
this.leggings = ItemTranslator.translateToBedrock(session, stack);
}
public void setBoots(ItemStack stack) {
this.boots = ItemTranslator.translateToBedrock(session, stack);
}
public void setHand(ItemStack stack) {
this.hand = ItemTranslator.translateToBedrock(session, stack);
}
public void setOffhand(ItemStack stack) {
this.offhand = ItemTranslator.translateToBedrock(session, stack);
}
public void switchHands() {
ItemData offhand = this.offhand;
this.offhand = this.hand;
this.hand = offhand;
}
@Override
protected void initializeMetadata() {
// Initialize here so overriding classes don't have 0 values
this.scale = 1f;
this.attributeScale = 1f;
super.initializeMetadata();
// Matches Bedrock behavior; is always set to this
dirtyMetadata.put(EntityDataTypes.STRUCTURAL_INTEGRITY, 1);
@ -121,6 +172,37 @@ public class LivingEntity extends Entity {
session.sendUpstreamPacket(attributesPacket);
}
// TODO: support all particle types
public void setParticles(ObjectEntityMetadata<List<Particle>> entityMetadata) {
List<Particle> particles = entityMetadata.getValue();
float r = 0f;
float g = 0f;
float b = 0f;
int count = 0;
for (Particle particle : particles) {
if (particle.getType() != ParticleType.ENTITY_EFFECT) {
continue;
}
int color = ((EntityEffectParticleData) particle.getData()).getColor();
r += ((color >> 16) & 0xFF) / 255f;
g += ((color >> 8) & 0xFF) / 255f;
b += ((color) & 0xFF) / 255f;
count++;
}
int result = 0;
if (count > 0) {
r = r / count * 255f;
g = g / count * 255f;
b = b / count * 255f;
result = (int) r << 16 | (int) g << 8 | (int) b;
}
dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, result);
}
public @Nullable Vector3i setBedPosition(EntityMetadata<Optional<Vector3i>, ?> entityMetadata) {
Optional<Vector3i> optionalPos = entityMetadata.getValue();
if (optionalPos.isPresent()) {
@ -135,7 +217,7 @@ public class LivingEntity extends Entity {
protected boolean hasShield(boolean offhand) {
ItemMapping shieldMapping = session.getItemMappings().getStoredItems().shield();
if (offhand) {
return offHand.getDefinition().equals(shieldMapping.getBedrockDefinition());
return this.offhand.getDefinition().equals(shieldMapping.getBedrockDefinition());
} else {
return hand.getDefinition().equals(shieldMapping.getBedrockDefinition());
}
@ -164,6 +246,21 @@ public class LivingEntity extends Entity {
return freezingPercentage;
}
protected void setScale(float scale) {
this.scale = scale;
applyScale();
}
private void setAttributeScale(float scale) {
this.attributeScale = scale;
applyScale();
}
private void applyScale() {
// Take any adjustments Bedrock requires, and compute it alongside the attribute's additional changes
this.dirtyMetadata.put(EntityDataTypes.SCALE, scale * attributeScale);
}
/**
* @return a Bedrock health attribute constructed from the data sent from the server
*/
@ -194,9 +291,9 @@ public class LivingEntity extends Entity {
/**
* Checks to see if a nametag interaction would go through.
*/
// Implementation note for 1.20.5: this code was moved to the NameTag item.
protected final InteractionResult checkInteractWithNameTag(GeyserItemStack itemStack) {
CompoundTag nbt = itemStack.getNbt();
if (nbt != null && nbt.get("display") instanceof CompoundTag displayTag && displayTag.get("Name") instanceof StringTag) {
if (itemStack.getComponent(DataComponentType.CUSTOM_NAME) != null) {
// The mob shall be named
return InteractionResult.SUCCESS;
}
@ -247,7 +344,7 @@ public class LivingEntity extends Entity {
MobEquipmentPacket offHandPacket = new MobEquipmentPacket();
offHandPacket.setRuntimeEntityId(geyserId);
offHandPacket.setItem(offHand);
offHandPacket.setItem(offhand);
offHandPacket.setHotbarSlot(-1);
offHandPacket.setInventorySlot(0);
offHandPacket.setContainerId(ContainerId.OFFHAND);
@ -255,6 +352,15 @@ public class LivingEntity extends Entity {
session.sendUpstreamPacket(offHandPacket);
}
/**
* Called when a SWING_ARM animation packet is received
*
* @return true if an ATTACK_START event should be used instead
*/
public boolean useArmSwingAttack() {
return false;
}
/**
* Attributes are properties of an entity that are generally more runtime-based instead of permanent properties.
* Movement speed, current attack damage with a weapon, current knockback resistance.
@ -299,7 +405,12 @@ public class LivingEntity extends Entity {
case GENERIC_MOVEMENT_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.MOVEMENT_SPEED));
case GENERIC_FOLLOW_RANGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FOLLOW_RANGE));
case GENERIC_KNOCKBACK_RESISTANCE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.KNOCKBACK_RESISTANCE));
case HORSE_JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH));
case GENERIC_JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH));
case GENERIC_SCALE -> {
// Attribute on Java, entity data on Bedrock
setAttributeScale((float) AttributeUtils.calculateValue(javaAttribute));
updateBedrockMetadata();
}
}
}
}

View file

@ -25,9 +25,6 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
@ -35,6 +32,9 @@ import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;

View file

@ -25,13 +25,13 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.packet.AddPaintingPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.level.PaintingType;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
import java.util.UUID;
@ -49,7 +49,7 @@ public class PaintingEntity extends Entity {
// Wait until we get the metadata needed
}
public void setPaintingType(ObjectEntityMetadata<com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType> entityMetadata) {
public void setPaintingType(ObjectEntityMetadata<org.geysermc.mcprotocollib.protocol.data.game.entity.type.PaintingType> entityMetadata) {
PaintingType type = PaintingType.getByPaintingType(entityMetadata.getValue());
AddPaintingPacket addPaintingPacket = new AddPaintingPacket();
addPaintingPacket.setUniqueEntityId(geyserId);

View file

@ -25,13 +25,13 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;

View file

@ -25,14 +25,14 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import net.kyori.adventure.text.Component;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.Optional;
import java.util.UUID;

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@ -34,6 +33,7 @@ import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import java.util.UUID;
@ -55,6 +55,9 @@ public class ThrowableEntity extends Entity implements Tickable {
*/
@Override
public void tick() {
if (removedInVoid()) {
return;
}
moveAbsoluteImmediate(position.add(motion), getYaw(), getPitch(), getHeadYaw(), isOnGround(), false);
float drag = getDrag();
float gravity = getGravity();
@ -170,14 +173,14 @@ public class ThrowableEntity extends Entity implements Tickable {
}
@Override
public boolean despawnEntity() {
public void despawnEntity() {
if (definition.entityType() == EntityType.ENDER_PEARL) {
LevelEventPacket particlePacket = new LevelEventPacket();
particlePacket.setType(LevelEvent.PARTICLE_TELEPORT);
particlePacket.setPosition(position);
session.sendUpstreamPacket(particlePacket);
}
return super.despawnEntity();
super.despawnEntity();
}
@Override
@ -191,4 +194,17 @@ public class ThrowableEntity extends Entity implements Tickable {
moveAbsoluteImmediate(position, yaw, pitch, headYaw, isOnGround, teleported);
lastJavaPosition = position;
}
/**
* Removes the entity if it is 64 blocks below the world.
*
* @return true if the entity was removed
*/
public boolean removedInVoid() {
if (position.getY() < session.getDimensionType().minY() - 64) {
session.getEntityCache().removeEntity(this);
return true;
}
return false;
}
}

View file

@ -25,8 +25,8 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;

View file

@ -25,10 +25,6 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@ -38,6 +34,11 @@ import org.geysermc.geyser.inventory.item.Potion;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents;
import java.util.EnumSet;
import java.util.UUID;
@ -53,21 +54,22 @@ public class ThrownPotionEntity extends ThrowableItemEntity {
public void setItem(EntityMetadata<ItemStack, ?> entityMetadata) {
ItemStack itemStack = entityMetadata.getValue();
if (itemStack == null) {
dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, 0);
dirtyMetadata.put(EntityDataTypes.AUX_VALUE_DATA, (short) 0);
setFlag(EntityFlag.ENCHANTED, false);
setFlag(EntityFlag.LINGERING, false);
} else {
// As of Java 1.19.3, the server/client doesn't seem to care of the item is actually a potion?
if (itemStack.getNbt() != null) {
Tag potionTag = itemStack.getNbt().get("Potion");
if (potionTag instanceof StringTag) {
Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue());
DataComponents components = itemStack.getDataComponents();
if (components != null) {
PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS);
if (potionContents != null) {
Potion potion = Potion.getByJavaId(potionContents.getPotionId());
if (potion != null) {
dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, (int) potion.getBedrockId());
dirtyMetadata.put(EntityDataTypes.AUX_VALUE_DATA, potion.getBedrockId());
setFlag(EntityFlag.ENCHANTED, !NON_ENCHANTED_POTIONS.contains(potion));
} else {
dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, 0);
GeyserImpl.getInstance().getLogger().debug("Unknown java potion: " + potionTag.getValue());
dirtyMetadata.put(EntityDataTypes.AUX_VALUE_DATA, (short) 0);
GeyserImpl.getInstance().getLogger().debug("Unknown java potion: " + potionContents.getPotionId());
}
}

View file

@ -25,7 +25,7 @@
package org.geysermc.geyser.entity.type;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.EntityDefinitions;

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@ -34,6 +33,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;

View file

@ -25,12 +25,11 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
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.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;
@ -44,12 +43,12 @@ public class AgeableEntity extends CreatureEntity {
protected void initializeMetadata() {
super.initializeMetadata();
// Required as of 1.19.3 Java
dirtyMetadata.put(EntityDataTypes.SCALE, getAdultSize());
setScale(getAdultSize());
}
public void setBaby(BooleanEntityMetadata entityMetadata) {
boolean isBaby = entityMetadata.getPrimitiveValue();
dirtyMetadata.put(EntityDataTypes.SCALE, isBaby ? getBabySize() : getAdultSize());
setScale(isBaby ? getBabySize() : getAdultSize());
setFlag(EntityFlag.BABY, isBaby);
setBoundingBoxHeight(definition.height() * (isBaby ? getBabySize() : getAdultSize()));

View file

@ -25,8 +25,6 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@ -36,6 +34,8 @@ import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;

View file

@ -25,10 +25,6 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import lombok.Getter;
import net.kyori.adventure.text.Component;
import org.cloudburstmc.math.vector.Vector3f;
@ -43,6 +39,11 @@ import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.MathUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import java.util.Optional;
import java.util.UUID;
@ -99,11 +100,11 @@ public class ArmorStandEntity extends LivingEntity {
}
@Override
public boolean despawnEntity() {
public void despawnEntity() {
if (secondEntity != null) {
secondEntity.despawnEntity();
}
return super.despawnEntity();
super.despawnEntity();
}
@Override
@ -257,38 +258,38 @@ public class ArmorStandEntity extends LivingEntity {
}
@Override
public void setHelmet(ItemData helmet) {
public void setHelmet(ItemStack helmet) {
super.setHelmet(helmet);
updateSecondEntityStatus(true);
}
@Override
public void setChestplate(ItemData chestplate) {
public void setChestplate(ItemStack chestplate) {
super.setChestplate(chestplate);
updateSecondEntityStatus(true);
}
@Override
public void setLeggings(ItemData leggings) {
public void setLeggings(ItemStack leggings) {
super.setLeggings(leggings);
updateSecondEntityStatus(true);
}
@Override
public void setBoots(ItemData boots) {
public void setBoots(ItemStack boots) {
super.setBoots(boots);
updateSecondEntityStatus(true);
}
@Override
public void setHand(ItemData hand) {
public void setHand(ItemStack hand) {
super.setHand(hand);
updateSecondEntityStatus(true);
}
@Override
public void setOffHand(ItemData offHand) {
super.setOffHand(offHand);
public void setOffhand(ItemStack offHand) {
super.setOffhand(offHand);
updateSecondEntityStatus(true);
}
@ -310,7 +311,7 @@ public class ArmorStandEntity extends LivingEntity {
if (!isInvisible) {
// The armor stand isn't invisible. We good.
setFlag(EntityFlag.INVISIBLE, false);
dirtyMetadata.put(EntityDataTypes.SCALE, getScale());
setScale(getScale());
updateOffsetRequirement(false);
if (secondEntity != null) {
@ -324,9 +325,9 @@ public class ArmorStandEntity extends LivingEntity {
}
boolean isNametagEmpty = nametag.isEmpty();
if (!isNametagEmpty && (!helmet.equals(ItemData.AIR) || !chestplate.equals(ItemData.AIR) || !leggings.equals(ItemData.AIR)
|| !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offHand.equals(ItemData.AIR))) {
|| !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offhand.equals(ItemData.AIR))) {
// Reset scale of the proper armor stand
this.dirtyMetadata.put(EntityDataTypes.SCALE, getScale());
setScale(getScale());
// Set the proper armor stand to invisible to show armor
setFlag(EntityFlag.INVISIBLE, true);
// Update the position of the armor stand
@ -349,7 +350,7 @@ public class ArmorStandEntity extends LivingEntity {
// Guarantee this copy is NOT invisible
secondEntity.setFlag(EntityFlag.INVISIBLE, false);
// Scale to 0 to show nametag
secondEntity.getDirtyMetadata().put(EntityDataTypes.SCALE, 0.0f);
secondEntity.setScale(0f);
// No bounding box as we don't want to interact with this entity
secondEntity.getDirtyMetadata().put(EntityDataTypes.WIDTH, 0.0f);
secondEntity.getDirtyMetadata().put(EntityDataTypes.HEIGHT, 0.0f);
@ -359,7 +360,7 @@ public class ArmorStandEntity extends LivingEntity {
} else if (isNametagEmpty) {
// We can just make an invisible entity
// Reset scale of the proper armor stand
dirtyMetadata.put(EntityDataTypes.SCALE, getScale());
setScale(getScale());
// Set the proper armor stand to invisible to show armor
setFlag(EntityFlag.INVISIBLE, true);
// Update offset
@ -373,7 +374,7 @@ public class ArmorStandEntity extends LivingEntity {
// Nametag is not empty and there is no armor
// We don't need to make a new entity
setFlag(EntityFlag.INVISIBLE, false);
dirtyMetadata.put(EntityDataTypes.SCALE, 0.0f);
setScale(0f);
// As the above is applied, we need an offset
updateOffsetRequirement(!isMarker);

View file

@ -25,11 +25,11 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.UUID;

View file

@ -25,14 +25,15 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@ -49,7 +50,7 @@ public class DolphinEntity extends WaterEntity {
@NonNull
@Override
protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) {
if (!itemInHand.isEmpty() && session.getTagCache().is(ItemTag.FISHES, itemInHand)) {
return InteractiveTag.FEED;
}
return super.testMobInteraction(hand, itemInHand);
@ -58,7 +59,7 @@ public class DolphinEntity extends WaterEntity {
@NonNull
@Override
protected InteractionResult mobInteract(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) {
if (!itemInHand.isEmpty() && session.getTagCache().is(ItemTag.FISHES, itemInHand)) {
// Feed
return InteractionResult.SUCCESS;
}

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
@ -35,6 +34,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;

View file

@ -25,8 +25,6 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import lombok.Getter;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
@ -40,6 +38,8 @@ import org.geysermc.geyser.item.type.SpawnEggItem;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;

View file

@ -25,11 +25,10 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
@ -39,8 +38,8 @@ public class SlimeEntity extends MobEntity {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
public void setScale(IntEntityMetadata entityMetadata) {
dirtyMetadata.put(EntityDataTypes.SCALE, 0.10f + entityMetadata.getPrimitiveValue());
public void setSlimeScale(IntEntityMetadata entityMetadata) {
setScale(0.10f + entityMetadata.getPrimitiveValue());
}
@Override

View file

@ -25,8 +25,6 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@ -36,6 +34,8 @@ import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;

View file

@ -25,15 +25,15 @@
package org.geysermc.geyser.entity.type.living;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@ -62,6 +62,6 @@ public class TadpoleEntity extends AbstractFishEntity {
}
private boolean isFood(GeyserItemStack itemStack) {
return itemStack.asItem() == Items.SLIME_BALL;
return session.getTagCache().is(ItemTag.FROG_FOOD, itemStack);
}
}

View file

@ -25,39 +25,40 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.living.AgeableEntity;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
public class AnimalEntity extends AgeableEntity {
public abstract class AnimalEntity extends AgeableEntity {
public AnimalEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
public final boolean canEat(GeyserItemStack itemStack) {
return canEat(itemStack.asItem());
protected final boolean canEat(GeyserItemStack itemStack) {
ItemTag tag = getFoodTag();
if (tag == null) {
return false;
}
return session.getTagCache().is(tag, itemStack);
}
/**
* @return true if this is a valid item to breed with for this animal.
* @return the tag associated with this animal for eating food. Null for nothing or different behavior.
*/
public boolean canEat(Item item) {
// This is what it defaults to. OK.
return item == Items.WHEAT;
}
protected abstract @Nullable ItemTag getFoodTag();
@NonNull
@Override

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2019-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.living.animal;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.ArmadilloState;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class ArmadilloEntity extends AnimalEntity {
private ArmadilloState armadilloState = ArmadilloState.IDLE;
public ArmadilloEntity(GeyserSession session, int entityId, long geyserId, UUID uuid,
EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
public void setArmadilloState(ObjectEntityMetadata<ArmadilloState> entityMetadata) {
armadilloState = entityMetadata.getValue();
switch (armadilloState) {
case IDLE -> propertyManager.add("minecraft:armadillo_state", "unrolled");
case ROLLING -> propertyManager.add("minecraft:armadillo_state", "rolled_up");
case SCARED -> propertyManager.add("minecraft:armadillo_state", "rolled_up_relaxing");
case UNROLLING -> propertyManager.add("minecraft:armadillo_state", "rolled_up_unrolling");
}
updateBedrockEntityProperties();
}
public void onPeeking() {
// Technically we should wait if not currently scared
if (armadilloState == ArmadilloState.SCARED) {
propertyManager.add("minecraft:armadillo_state", "rolled_up_peeking");
updateBedrockEntityProperties();
// Needed for consecutive peeks
session.scheduleInEventLoop(() -> {
if (armadilloState == ArmadilloState.SCARED) {
propertyManager.add("minecraft:armadillo_state", "rolled_up_relaxing");
updateBedrockEntityProperties();
}
}, 250, TimeUnit.MILLISECONDS);
}
}
@Override
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.ARMADILLO_FOOD;
}
}

View file

@ -25,19 +25,20 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
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.inventory.GeyserItemStack;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@ -60,8 +61,9 @@ public class AxolotlEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return session.getTagCache().isAxolotlTemptItem(item);
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.AXOLOTL_FOOD;
}
@Override

View file

@ -25,16 +25,17 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
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.EntityDefinition;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
@ -57,7 +58,8 @@ public class BeeEntity extends AnimalEntity {
// If the bee has stung
dirtyMetadata.put(EntityDataTypes.MARK_VARIANT, (xd & 0x04) == 0x04 ? 1 : 0);
// If the bee has nectar or not
setFlag(EntityFlag.POWERED, (xd & 0x08) == 0x08);
propertyManager.add("minecraft:has_nectar", (xd & 0x08) == 0x08);
updateBedrockEntityProperties();
}
public void setAngerTime(IntEntityMetadata entityMetadata) {
@ -66,7 +68,8 @@ public class BeeEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return session.getTagCache().isFlower(item);
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.BEE_FOOD;
}
}

View file

@ -25,24 +25,23 @@
package org.geysermc.geyser.entity.type.living.animal;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import java.util.Set;
import java.util.UUID;
public class ChickenEntity extends AnimalEntity {
private static final Set<Item> VALID_FOOD = Set.of(Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS);
public ChickenEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
@Override
public boolean canEat(Item item) {
return VALID_FOOD.contains(item);
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.CHICKEN_FOOD;
}
}

View file

@ -25,8 +25,8 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@ -34,8 +34,10 @@ import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@ -64,4 +66,10 @@ public class CowEntity extends AnimalEntity {
session.playSoundEvent(SoundEvent.MILK, position);
return InteractionResult.SUCCESS;
}
@Override
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.COW_FOOD;
}
}

View file

@ -25,14 +25,15 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.checkerframework.checker.nullness.qual.Nullable;
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.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
@ -55,7 +56,8 @@ public class FoxEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return session.getTagCache().isFoxFood(item);
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.FOX_FOOD;
}
}

View file

@ -25,17 +25,17 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import org.checkerframework.checker.nullness.qual.Nullable;
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.Entity;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import java.util.OptionalInt;
import java.util.UUID;
@ -76,7 +76,8 @@ public class FrogEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return item == Items.SLIME_BALL;
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.FROG_FOOD;
}
}

View file

@ -25,10 +25,8 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
@ -37,7 +35,11 @@ import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@ -94,4 +96,10 @@ public class GoatEntity extends AnimalEntity {
private void setHornCount() {
dirtyMetadata.put(EntityDataTypes.GOAT_HORN_COUNT, (hasLeftHorn ? 1 : 0) + (hasRightHorn ? 1 : 0));
}
@Override
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.GOAT_FOOD;
}
}

View file

@ -25,13 +25,14 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.checkerframework.checker.nullness.qual.Nullable;
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.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;
@ -40,6 +41,8 @@ public class HoglinEntity extends AnimalEntity {
public HoglinEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
dirtyMetadata.put(EntityDataTypes.TARGET_EID, session.getPlayerEntity().getGeyserId());
setFlag(EntityFlag.SHAKING, isShaking());
}
public void setImmuneToZombification(BooleanEntityMetadata entityMetadata) {
@ -54,8 +57,9 @@ public class HoglinEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return item == Items.CRIMSON_FUNGUS;
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.HOGLIN_FOOD;
}
@Override
@ -67,4 +71,9 @@ public class HoglinEntity extends AnimalEntity {
protected boolean isEnemy() {
return true;
}
@Override
public boolean useArmSwingAttack() {
return true;
}
}

View file

@ -25,22 +25,22 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.FlowerItem;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
public class MooshroomEntity extends AnimalEntity {
public class MooshroomEntity extends CowEntity {
private boolean isBrown = false;
public MooshroomEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
@ -77,7 +77,7 @@ public class MooshroomEntity extends AnimalEntity {
} else if (!isBaby && isAlive() && itemInHand.asItem() == Items.SHEARS) {
// Shear items
return InteractionResult.SUCCESS;
} else if (isBrown && session.getTagCache().isSmallFlower(itemInHand) && itemInHand.asItem() instanceof FlowerItem) {
} else if (isBrown && session.getTagCache().is(ItemTag.SMALL_FLOWERS, itemInHand)) {
// ?
return InteractionResult.SUCCESS;
}

View file

@ -25,17 +25,17 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@ -46,8 +46,9 @@ public class OcelotEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return item == Items.COD || item == Items.SALMON;
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.OCELOT_FOOD;
}
@NonNull

View file

@ -25,9 +25,6 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
@ -37,11 +34,13 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@ -62,7 +61,8 @@ public class PandaEntity extends AnimalEntity {
EntityEventPacket packet = new EntityEventPacket();
packet.setRuntimeEntityId(geyserId);
packet.setType(EntityEventType.EATING_ITEM);
packet.setData(session.getItemMappings().getStoredItems().bamboo().getBedrockDefinition().getRuntimeId() << 16);
// As of 1.20.5 - pandas can eat cake
packet.setData(this.hand.getDefinition().getRuntimeId() << 16);
session.sendUpstreamPacket(packet);
}
}
@ -89,8 +89,9 @@ public class PandaEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return item == Items.BAMBOO;
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.PANDA_FOOD;
}
@NonNull

View file

@ -25,18 +25,18 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@ -47,8 +47,9 @@ public class PigEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return item == Items.CARROT || item == Items.POTATO || item == Items.BEETROOT;
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.PIG_FOOD;
}
@NonNull

View file

@ -25,10 +25,11 @@
package org.geysermc.geyser.entity.type.living.animal;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import java.util.UUID;
@ -39,7 +40,8 @@ public class PolarBearEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return false;
@Nullable
protected ItemTag getFoodTag() {
return null;
}
}

View file

@ -25,12 +25,12 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.living.AbstractFishEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;

View file

@ -25,14 +25,14 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.checkerframework.checker.nullness.qual.Nullable;
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.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
@ -67,7 +67,8 @@ public class RabbitEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return item == Items.DANDELION || item == Items.CARROT || item == Items.GOLDEN_CARROT;
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.RABBIT_FOOD;
}
}

View file

@ -25,9 +25,8 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@ -36,8 +35,11 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.DyeItem;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@ -55,6 +57,12 @@ public class SheepEntity extends AnimalEntity {
dirtyMetadata.put(EntityDataTypes.COLOR, (byte) color);
}
@Override
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.SHEEP_FOOD;
}
@NonNull
@Override
protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {

View file

@ -25,9 +25,7 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.SnifferState;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
@ -37,8 +35,11 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.Tickable;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.SnifferState;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import java.util.UUID;
@ -71,8 +72,9 @@ public class SnifferEntity extends AnimalEntity implements Tickable {
}
@Override
public boolean canEat(Item item) {
return session.getTagCache().isSnifferFood(item);
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.SNIFFER_FOOD;
}
public void setSnifferState(ObjectEntityMetadata<SnifferState> entityMetadata) {

View file

@ -25,20 +25,20 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@ -94,8 +94,9 @@ public class StriderEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return item == Items.WARPED_FUNGUS;
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.STRIDER_FOOD;
}
@NonNull

View file

@ -25,14 +25,14 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.google.common.collect.ImmutableList;
import it.unimi.dsi.fastutil.ints.IntList;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import it.unimi.dsi.fastutil.ints.IntList;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.living.AbstractFishEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.List;
import java.util.UUID;

View file

@ -25,13 +25,13 @@
package org.geysermc.geyser.entity.type.living.animal;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;
@ -50,8 +50,9 @@ public class TurtleEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return item == Items.SEAGRASS;
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.TURTLE_FOOD;
}
@Override

View file

@ -25,9 +25,8 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
@ -40,21 +39,16 @@ import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.entity.type.living.animal.AnimalEntity;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.Set;
import java.util.UUID;
public class AbstractHorseEntity extends AnimalEntity {
/**
* A list of all foods a horse/donkey can eat on Java Edition.
* Used to display interactive tag if needed.
*/
private static final Set<Item> DONKEY_AND_HORSE_FOODS = Set.of(Items.GOLDEN_APPLE, Items.ENCHANTED_GOLDEN_APPLE,
Items.GOLDEN_CARROT, Items.SUGAR, Items.APPLE, Items.WHEAT, Items.HAY_BLOCK);
public AbstractHorseEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
@ -124,8 +118,9 @@ public class AbstractHorseEntity extends AnimalEntity {
}
@Override
public boolean canEat(Item item) {
return DONKEY_AND_HORSE_FOODS.contains(item);
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.HORSE_FOOD;
}
@NonNull

View file

@ -25,9 +25,7 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
@ -35,9 +33,11 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.UUID;
@ -90,8 +90,8 @@ public class CamelEntity extends AbstractHorseEntity {
}
@Override
public boolean canEat(Item item) {
return item == Items.CACTUS;
protected @Nullable ItemTag getFoodTag() {
return ItemTag.CAMEL_FOOD;
}
@Override

View file

@ -25,11 +25,11 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;

View file

@ -25,19 +25,24 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import lombok.Getter;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.MobArmorEquipmentPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.MathUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
public class LlamaEntity extends ChestedHorseEntity {
/**
* Used to calculate inventory size
*/
@Getter
private int strength = 1;
public LlamaEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
@ -45,32 +50,13 @@ public class LlamaEntity extends ChestedHorseEntity {
dirtyMetadata.put(EntityDataTypes.CONTAINER_STRENGTH_MODIFIER, 3); // Presumably 3 slots for every 1 strength
}
/**
* Color equipped on the llama
*/
public void setCarpetedColor(IntEntityMetadata entityMetadata) {
// Bedrock treats llama decoration as armor
MobArmorEquipmentPacket equipmentPacket = new MobArmorEquipmentPacket();
equipmentPacket.setRuntimeEntityId(geyserId);
// -1 means no armor
int carpetIndex = entityMetadata.getPrimitiveValue();
if (carpetIndex > -1 && carpetIndex <= 15) {
// The damage value is the dye color that Java sends us, for pre-1.16.220
// The item is always going to be a carpet
equipmentPacket.setChestplate(session.getItemMappings().getCarpets().get(carpetIndex));
} else {
equipmentPacket.setChestplate(ItemData.AIR);
}
// Required to fill out the rest of the equipment or Bedrock ignores it, including above else statement if removing armor
equipmentPacket.setBoots(ItemData.AIR);
equipmentPacket.setHelmet(ItemData.AIR);
equipmentPacket.setLeggings(ItemData.AIR);
session.sendUpstreamPacket(equipmentPacket);
public void setStrength(IntEntityMetadata entityMetadata) {
strength = MathUtils.constrain(entityMetadata.getPrimitiveValue(), 1, 5);
this.dirtyMetadata.put(EntityDataTypes.STRENGTH, strength);
}
@Override
public boolean canEat(Item item) {
return item == Items.WHEAT || item == Items.HAY_BLOCK;
protected @Nullable ItemTag getFoodTag() {
return ItemTag.LLAMA_FOOD;
}
}

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
@ -33,6 +32,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
@ -33,6 +32,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;

View file

@ -25,27 +25,27 @@
package org.geysermc.geyser.entity.type.living.animal.tameable;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
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.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
public class CatEntity extends TameableEntity {
private byte collarColor;
private byte collarColor = 14; // Red - default
public CatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
@ -76,10 +76,7 @@ public class CatEntity extends TameableEntity {
@Override
public void setTameableFlags(ByteEntityMetadata entityMetadata) {
super.setTameableFlags(entityMetadata);
// Update collar color if tamed
if (getFlag(EntityFlag.TAMED)) {
dirtyMetadata.put(EntityDataTypes.COLOR, collarColor);
}
updateCollarColor();
}
public void setCatVariant(IntEntityMetadata entityMetadata) {
@ -101,6 +98,10 @@ public class CatEntity extends TameableEntity {
public void setCollarColor(IntEntityMetadata entityMetadata) {
collarColor = (byte) entityMetadata.getPrimitiveValue();
updateCollarColor();
}
private void updateCollarColor() {
// Needed or else wild cats are a red color
if (getFlag(EntityFlag.TAMED)) {
dirtyMetadata.put(EntityDataTypes.COLOR, collarColor);
@ -108,8 +109,8 @@ public class CatEntity extends TameableEntity {
}
@Override
public boolean canEat(Item item) {
return item == Items.COD || item == Items.SALMON;
protected @Nullable ItemTag getFoodTag() {
return ItemTag.CAT_FOOD;
}
@NonNull

View file

@ -25,8 +25,8 @@
package org.geysermc.geyser.entity.type.living.animal.tameable;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
@ -34,8 +34,10 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.Set;
import java.util.UUID;
@ -49,16 +51,17 @@ public class ParrotEntity extends TameableEntity {
}
@Override
public boolean canEat(Item item) {
return false;
@Nullable
protected ItemTag getFoodTag() {
return null;
}
private boolean isTameFood(Item item) {
return TAMING_FOOD.contains(item);
return session.getTagCache().is(ItemTag.PARROT_FOOD, item);
}
private boolean isPoisonousFood(Item item) {
return item == Items.COOKIE;
return session.getTagCache().is(ItemTag.PARROT_POISONOUS_FOOD, item);
}
@NonNull

View file

@ -25,21 +25,21 @@
package org.geysermc.geyser.entity.type.living.animal.tameable;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import lombok.Getter;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import lombok.Getter;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.living.animal.AnimalEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.Optional;
import java.util.UUID;
public class TameableEntity extends AnimalEntity {
public abstract class TameableEntity extends AnimalEntity {
/**
* Used in the interactive tag manager to track if the session player owns this entity
*/

View file

@ -25,22 +25,31 @@
package org.geysermc.geyser.entity.type.living.animal.tameable;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.item.Enchantment;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.DyeItem;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.geyser.util.ItemUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
@ -54,7 +63,9 @@ public class WolfEntity extends TameableEntity {
Items.PORKCHOP, Items.BEEF, Items.RABBIT, Items.COOKED_PORKCHOP, Items.COOKED_BEEF, Items.ROTTEN_FLESH, Items.MUTTON, Items.COOKED_MUTTON,
Items.COOKED_RABBIT);
private byte collarColor;
private byte collarColor = 14; // Red - default
private boolean isCurseOfBinding = false;
public WolfEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
@ -64,19 +75,27 @@ public class WolfEntity extends TameableEntity {
public void setTameableFlags(ByteEntityMetadata entityMetadata) {
super.setTameableFlags(entityMetadata);
// Reset wolf color
byte xd = entityMetadata.getPrimitiveValue();
boolean angry = (xd & 0x02) == 0x02;
if (angry) {
if (getFlag(EntityFlag.ANGRY)) {
dirtyMetadata.put(EntityDataTypes.COLOR, (byte) 0);
} else if (getFlag(EntityFlag.TAMED)) {
updateCollarColor();
// This fixes tail angle when taming
UpdateAttributesPacket packet = new UpdateAttributesPacket();
packet.setRuntimeEntityId(geyserId);
packet.setAttributes(Collections.singletonList(createHealthAttribute()));
session.sendUpstreamPacket(packet);
}
}
public void setCollarColor(IntEntityMetadata entityMetadata) {
collarColor = (byte) entityMetadata.getPrimitiveValue();
if (getFlag(EntityFlag.ANGRY)) {
return;
if (!getFlag(EntityFlag.ANGRY) && getFlag(EntityFlag.TAMED)) {
updateCollarColor();
}
}
private void updateCollarColor() {
dirtyMetadata.put(EntityDataTypes.COLOR, collarColor);
if (ownerBedrockId == 0) {
// If a color is set and there is no owner entity ID, set one.
@ -92,10 +111,25 @@ public class WolfEntity extends TameableEntity {
dirtyMetadata.put(EntityDataTypes.COLOR, time != 0 ? (byte) 0 : collarColor);
}
// 1.20.5+
public void setWolfVariant(IntEntityMetadata entityMetadata) {
WolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(entityMetadata.getPrimitiveValue());
if (wolfVariant == null) {
wolfVariant = WolfVariant.PALE;
}
dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal());
}
@Override
public boolean canEat(Item item) {
// Cannot be a baby to eat these foods
return WOLF_FOODS.contains(item) && !isBaby();
@Nullable
protected ItemTag getFoodTag() {
return ItemTag.WOLF_FOOD;
}
@Override
public void setChestplate(ItemStack stack) {
super.setChestplate(stack);
isCurseOfBinding = ItemUtils.getEnchantmentLevel(stack.getDataComponents(), Enchantment.JavaEnchantment.BINDING_CURSE) > 0;
}
@Override
@ -112,16 +146,30 @@ public class WolfEntity extends TameableEntity {
if (itemInHand.asItem() == Items.BONE && !getFlag(EntityFlag.TAMED)) {
// Bone and untamed - can tame
return InteractiveTag.TAME;
} else {
if (itemInHand.asItem() instanceof DyeItem item) {
}
if (getFlag(EntityFlag.TAMED) && ownerBedrockId == session.getPlayerEntity().getGeyserId()) {
if (itemInHand.asItem() instanceof DyeItem dyeItem) {
// If this fails, as of Java Edition 1.18.1, you cannot toggle sit/stand
if (item.dyeColor() != this.collarColor) {
if (dyeItem.dyeColor() != this.collarColor) {
return InteractiveTag.DYE;
} else {
return super.testMobInteraction(hand, itemInHand);
}
} else if (getFlag(EntityFlag.TAMED) && ownerBedrockId == session.getPlayerEntity().getGeyserId()) {
// Tamed and owned by player - can sit/stand
return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
}
if (itemInHand.asItem() == Items.WOLF_ARMOR && !this.chestplate.isValid() && !getFlag(EntityFlag.BABY)) {
return InteractiveTag.EQUIP_WOLF_ARMOR;
}
if (itemInHand.asItem() == Items.SHEARS && this.chestplate.isValid()
&& (!isCurseOfBinding || session.getGameMode().equals(GameMode.CREATIVE))) {
return InteractiveTag.REMOVE_WOLF_ARMOR;
}
if (Items.WOLF_ARMOR.isValidRepairItem(itemInHand.asItem()) && getFlag(EntityFlag.SITTING) &&
this.chestplate.isValid() && this.chestplate.getTag() != null &&
this.chestplate.getTag().getInt("Damage") > 0) {
return InteractiveTag.REPAIR_WOLF_ARMOR;
}
// Tamed and owned by player - can sit/stand
return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
}
return super.testMobInteraction(hand, itemInHand);
}
@ -137,4 +185,34 @@ public class WolfEntity extends TameableEntity {
return InteractionResult.PASS;
}
}
// Ordered by bedrock id
public enum WolfVariant {
PALE,
ASHEN,
BLACK,
CHESTNUT,
RUSTY,
SNOWY,
SPOTTED,
STRIPED,
WOODS;
private static final WolfVariant[] VALUES = values();
private final String javaIdentifier;
WolfVariant() {
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT);
}
public static @Nullable WolfVariant getByJavaIdentifier(String javaIdentifier) {
for (WolfVariant wolfVariant : VALUES) {
if (wolfVariant.javaIdentifier.equals(javaIdentifier)) {
return wolfVariant;
}
}
return null;
}
}
}

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.living.merchant;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@ -37,6 +36,7 @@ import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;

View file

@ -25,8 +25,6 @@
package org.geysermc.geyser.entity.type.living.merchant;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
import lombok.Getter;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
@ -38,6 +36,8 @@ import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.type.BlockMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.VillagerData;
import java.util.Optional;
import java.util.UUID;

View file

@ -25,11 +25,13 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
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.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.UUID;
@ -45,5 +47,17 @@ public class AbstractSkeletonEntity extends MonsterEntity {
byte xd = entityMetadata.getPrimitiveValue();
// A bit of a loophole so the hands get raised - set the target ID to its own ID
dirtyMetadata.put(EntityDataTypes.TARGET_EID, ((xd & 4) == 4) ? geyserId : 0);
if ((xd & 4) == 4) {
ItemDefinition bow = session.getItemMappings().getStoredItems().bow().getBedrockDefinition();
setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, this.hand.getDefinition() == bow || this.offhand.getDefinition() == bow);
} else {
setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, false);
}
}
@Override
public boolean useArmSwingAttack() {
return true;
}
}

View file

@ -25,11 +25,14 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
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.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import java.util.UUID;
@ -38,6 +41,16 @@ public class BasePiglinEntity extends MonsterEntity {
public BasePiglinEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
// Both TARGET_EID and BLOCK are needed for melee attack animation
dirtyMetadata.put(EntityDataTypes.BLOCK, session.getBlockMappings().getDefinition(1));
setFlag(EntityFlag.SHAKING, isShaking());
}
@Override
public void setMobFlags(ByteEntityMetadata entityMetadata) {
super.setMobFlags(entityMetadata);
byte xd = entityMetadata.getPrimitiveValue();
dirtyMetadata.put(EntityDataTypes.TARGET_EID, (xd & 4) == 4 ? session.getPlayerEntity().getGeyserId() : 0);
}
public void setImmuneToZombification(BooleanEntityMetadata entityMetadata) {
@ -50,4 +63,9 @@ public class BasePiglinEntity extends MonsterEntity {
protected boolean isShaking() {
return (!isImmuneToZombification && !session.getDimensionType().piglinSafe()) || super.isShaking();
}
@Override
public boolean useArmSwingAttack() {
return true;
}
}

View file

@ -25,11 +25,11 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.UUID;

View file

@ -25,9 +25,6 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
@ -35,8 +32,12 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@ -65,7 +66,7 @@ public class CreeperEntity extends MonsterEntity {
@NonNull
@Override
protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
if (session.getTagCache().isCreeperIgniter(itemInHand.asItem())) {
if (session.getTagCache().is(ItemTag.CREEPER_IGNITERS, itemInHand)) {
return InteractiveTag.IGNITE_CREEPER;
} else {
return super.testMobInteraction(hand, itemInHand);
@ -75,7 +76,7 @@ public class CreeperEntity extends MonsterEntity {
@NonNull
@Override
protected InteractionResult mobInteract(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
if (session.getTagCache().isCreeperIgniter(itemInHand.asItem())) {
if (session.getTagCache().is(ItemTag.CREEPER_IGNITERS, itemInHand)) {
// Ignite creeper - as of 1.19.3
session.playSoundEvent(SoundEvent.IGNITE, position);
return InteractionResult.SUCCESS;

View file

@ -25,23 +25,19 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import lombok.Data;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.ParticleType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket;
import org.cloudburstmc.protocol.bedrock.packet.SpawnParticleEffectPacket;
import org.cloudburstmc.protocol.bedrock.packet.*;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Tickable;
import org.geysermc.geyser.entity.type.living.MobEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.DimensionUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.Optional;
import java.util.Random;
@ -148,11 +144,11 @@ public class EnderDragonEntity extends MobEntity implements Tickable {
}
@Override
public boolean despawnEntity() {
public void despawnEntity() {
for (EnderDragonPartEntity part : allParts) {
part.despawnEntity();
}
return super.despawnEntity();
super.despawnEntity();
}
@Override

View file

@ -25,8 +25,6 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
@ -35,6 +33,8 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;

View file

@ -25,12 +25,12 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.living.FlyingEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;

View file

@ -26,7 +26,6 @@
package org.geysermc.geyser.entity.type.living.monster;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
@ -36,7 +35,11 @@ public class GiantEntity extends MonsterEntity {
public GiantEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
dirtyMetadata.put(EntityDataTypes.SCALE, 6f);
@Override
protected void initializeMetadata() {
super.initializeMetadata();
setScale(6f);
}
}

View file

@ -25,12 +25,12 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;

View file

@ -25,12 +25,11 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.living.FlyingEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
@ -46,7 +45,7 @@ public class PhantomEntity extends FlyingEntity {
setBoundingBoxWidth(boundsScale * definition.width());
setBoundingBoxHeight(boundsScale * definition.height());
dirtyMetadata.put(EntityDataTypes.SCALE, modelScale);
setScale(modelScale);
}
@Override

View file

@ -25,18 +25,24 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
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.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import java.util.UUID;
@ -48,24 +54,72 @@ public class PiglinEntity extends BasePiglinEntity {
public void setBaby(BooleanEntityMetadata entityMetadata) {
boolean isBaby = entityMetadata.getPrimitiveValue();
dirtyMetadata.put(EntityDataTypes.SCALE, isBaby? .55f : 1f);
setScale(isBaby? .55f : 1f);
setFlag(EntityFlag.BABY, isBaby);
updateMountOffset();
}
public void setChargingCrossbow(BooleanEntityMetadata entityMetadata) {
setFlag(EntityFlag.CHARGING, entityMetadata.getPrimitiveValue());
boolean charging = entityMetadata.getPrimitiveValue();
setFlag(EntityFlag.CHARGING, charging);
dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, charging ? (byte) 64 : (byte) 0); // TODO: gradually increase
}
public void setDancing(BooleanEntityMetadata entityMetadata) {
setFlag(EntityFlag.DANCING, entityMetadata.getPrimitiveValue());
}
@Override
public void setHand(ItemStack stack) {
ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow();
boolean toCrossbow = stack != null && stack.getId() == crossbow.getJavaItem().javaId();
if (toCrossbow ^ this.hand.getDefinition() == crossbow.getBedrockDefinition()) { // If switching to/from crossbow
dirtyMetadata.put(EntityDataTypes.BLOCK, session.getBlockMappings().getDefinition(toCrossbow ? 0 : 1));
dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, (byte) 0);
setFlag(EntityFlag.CHARGED, false);
setFlag(EntityFlag.USING_ITEM, false);
updateBedrockMetadata();
if (this.hand.isValid()) {
MobEquipmentPacket mobEquipmentPacket = new MobEquipmentPacket();
mobEquipmentPacket.setRuntimeEntityId(geyserId);
mobEquipmentPacket.setContainerId(ContainerId.INVENTORY);
mobEquipmentPacket.setInventorySlot(0);
mobEquipmentPacket.setHotbarSlot(-1);
mobEquipmentPacket.setItem(ItemData.AIR);
session.sendUpstreamPacket(mobEquipmentPacket);
}
}
super.setHand(stack);
}
@Override
public void updateMainHand(GeyserSession session) {
super.updateMainHand(session);
if (this.hand.getDefinition() == session.getItemMappings().getStoredItems().crossbow().getBedrockDefinition()) {
if (this.hand.getTag() != null && this.hand.getTag().containsKey("chargedItem")) {
dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, Byte.MAX_VALUE);
setFlag(EntityFlag.CHARGING, false);
setFlag(EntityFlag.CHARGED, true);
setFlag(EntityFlag.USING_ITEM, true);
} else if (getFlag(EntityFlag.CHARGED)) {
dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, (byte) 0);
setFlag(EntityFlag.CHARGED, false);
setFlag(EntityFlag.USING_ITEM, false);
}
}
updateBedrockMetadata();
}
@Override
public void updateOffHand(GeyserSession session) {
// Check if the Piglin is holding Gold and set the ADMIRING flag accordingly so its pose updates
setFlag(EntityFlag.ADMIRING, session.getTagCache().shouldPiglinAdmire(session.getItemMappings().getMapping(this.offHand).getJavaItem()));
setFlag(EntityFlag.ADMIRING, session.getTagCache().is(ItemTag.PIGLIN_LOVED, session.getItemMappings().getMapping(this.offhand).getJavaItem()));
super.updateBedrockMetadata();
super.updateOffHand(session);

View file

@ -25,15 +25,15 @@
package org.geysermc.geyser.entity.type.living.monster;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
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.living.GolemEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
import java.util.UUID;

Some files were not shown because too many files have changed in this diff Show more