Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* This file is part of ViaBedrock - https://github.com/ViaVersionAddons/ViaBedrock
* Copyright (C) 2023-2026 RK_01
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.raphimc.viabedrock.api.model.entity;

import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes26_3;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import net.raphimc.viabedrock.ViaBedrock;
import net.raphimc.viabedrock.api.util.PacketFactory;
import net.raphimc.viabedrock.protocol.data.enums.java.EntityEvent;
import net.raphimc.viabedrock.protocol.data.generated.java.EntityDataFields;

import java.util.List;
import java.util.UUID;

public class ArmadilloEntity extends MobEntity {

private static final int IDLE = 0;
private static final int ROLLING = 1;
private static final int SCARED = 2;
private static final int UNROLLING = 3;
private static final int ROLL_DURATION_TICKS = 10;

private String bedrockState;
private int javaState = -1;
private int rollingTicks;
private boolean pendingPeek;

public ArmadilloEntity(final UserConnection user, final long uniqueId, final long runtimeId, final String type, final int javaId, final UUID javaUuid) {
super(user, uniqueId, runtimeId, type, javaId, javaUuid, EntityTypes26_3.ARMADILLO);
}

public void translateState(final String state, final List<EntityData> javaEntityData) {
if (state.equals(this.bedrockState)) {
return;
}

final int javaState = switch (state) {
case "unrolled" -> IDLE;
case "rolled_up" -> "unrolled".equals(this.bedrockState) ? ROLLING : SCARED;
case "rolled_up_peeking", "rolled_up_relaxing" -> SCARED;
case "rolled_up_unrolling" -> UNROLLING;
default -> -1;
};
if (javaState == -1) {
ViaBedrock.getPlatform().getLogger().warning("Received unknown armadillo state " + state);
return;
}

this.bedrockState = state;
this.pendingPeek = state.equals("rolled_up_peeking");
this.rollingTicks = javaState == ROLLING ? ROLL_DURATION_TICKS : 0;
if (this.javaState != javaState) {
this.javaState = javaState;
javaEntityData.add(this.stateData());
}
}

@Override
public void tick() {
super.tick();
if (this.rollingTicks > 0 && --this.rollingTicks == 0) {
this.javaState = SCARED;
this.sendEntityData(List.of(this.stateData()));
}
// The client needs the SCARED metadata before it can play the peek animation.
if (this.pendingPeek) {
this.pendingPeek = false;
PacketFactory.sendJavaEntityEvent(this.user, this, EntityEvent.ARMADILLO_PEEK);
}
}

private EntityData stateData() {
return new EntityData(this.getJavaEntityDataIndex(EntityDataFields.ARMADILLO_STATE), VersionedTypes.V26_3.entityDataTypes().armadilloState, this.javaState);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ public void remove() {
public final void updateEntityData(final EntityData[] entityData) {
final List<EntityData> javaEntityData = new ArrayList<>();
this.updateEntityData(entityData, javaEntityData);
this.sendEntityData(javaEntityData);
}

public final void sendEntityData(final List<EntityData> javaEntityData) {
final PacketWrapper setEntityData = PacketWrapper.create(ClientboundPackets26_3.SET_ENTITY_DATA, this.user);
setEntityData.write(Types.VAR_INT, this.javaId); // entity id
setEntityData.write(VersionedTypes.V26_3.entityDataList, javaEntityData); // entity data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.viaversion.viaversion.protocols.v26_2to26_3.packet.ClientboundPackets26_3;
import com.viaversion.viaversion.util.Key;
import net.raphimc.viabedrock.ViaBedrock;
import net.raphimc.viabedrock.api.model.entity.ArmadilloEntity;
import net.raphimc.viabedrock.api.model.entity.ClientPlayerEntity;
import net.raphimc.viabedrock.api.model.entity.CustomEntity;
import net.raphimc.viabedrock.api.model.entity.Entity;
Expand Down Expand Up @@ -94,7 +95,7 @@ public static void register(final BedrockProtocol protocol) {
attributes[i] = new EntityAttribute(name, currentValue, minValue, maxValue);
}
final EntityData[] entityData = wrapper.read(BedrockTypes.ENTITY_DATA_ARRAY); // entity data
wrapper.read(BedrockTypes.ENTITY_PROPERTIES); // entity properties
final EntityProperties entityProperties = wrapper.read(BedrockTypes.ENTITY_PROPERTIES); // entity properties
wrapper.read(BedrockTypes.ENTITY_LINK_ARRAY); // entity links
wrapper.read(BedrockTypes.OPTIONAL_PASSENGER_OF_BLOCKS); // passenger of blocks

Expand Down Expand Up @@ -142,7 +143,14 @@ public static void register(final BedrockProtocol protocol) {
if (entity instanceof LivingEntity livingEntity) {
livingEntity.updateAttributes(attributes);
}
entity.updateEntityData(entityData);
if (entity instanceof ArmadilloEntity) {
final List<EntityData> javaEntityData = new ArrayList<>();
entity.updateEntityData(entityData, javaEntityData);
entity.translateEntityProperties(entityProperties, javaEntityData);
entity.sendEntityData(javaEntityData);
} else {
entity.updateEntityData(entityData);
}
});
protocol.registerClientbound(ClientboundBedrockPackets.ADD_ITEM_ENTITY, ClientboundPackets26_3.ADD_ENTITY, wrapper -> {
final EntityTracker entityTracker = wrapper.user().get(EntityTracker.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.util.Key;
import net.raphimc.viabedrock.ViaBedrock;
import net.raphimc.viabedrock.api.model.entity.ArmadilloEntity;
import net.raphimc.viabedrock.api.model.entity.Entity;
import net.raphimc.viabedrock.api.model.entity.LivingEntity;
import net.raphimc.viabedrock.api.model.entity.properties.EntityProperty;
Expand Down Expand Up @@ -790,6 +791,10 @@ public static void rewriteProperties(final UserConnection user, final Entity ent

ViaBedrock.getPlatform().getLogger().warning("Received int property " + integerProperty.identifier() + " for entity " + entity.type() + " with value " + value);
} else if (property instanceof EntityProperty.EnumProperty enumProperty) {
if (i < 0 || i >= enumProperty.possibleValues().length) {
ViaBedrock.getPlatform().getLogger().warning("Received invalid enum value " + i + " for property " + enumProperty.identifier() + " on entity " + entity.type());
continue;
}
final String value = enumProperty.possibleValues()[i];

switch (enumProperty.identifier()) {
Expand Down Expand Up @@ -871,6 +876,13 @@ public static void rewriteProperties(final UserConnection user, final Entity ent
}
}
}
case "minecraft:armadillo_state" -> {
if (entity instanceof ArmadilloEntity armadillo) {
armadillo.translateState(value, javaEntityData);
} else {
ViaBedrock.getPlatform().getLogger().warning("Received armadillo_state for non-ARMADILLO entity " + entity.type());
}
}
case "minecraft:chest_interaction" -> {
if (entity.javaType().is(EntityTypes26_3.COPPER_GOLEM)) {
final int state = switch (value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ public EntityTracker(final UserConnection user) {

public Entity addEntity(final long uniqueId, final long runtimeId, final String type, final EntityTypes26_3 javaType) {
final UUID javaUuid = UUID.randomUUID();
if (javaType.isOrHasParent(EntityTypes26_3.ABSTRACT_HORSE)) {
if (javaType.is(EntityTypes26_3.ARMADILLO)) {
return this.addEntity(new ArmadilloEntity(this.user(), uniqueId, runtimeId, type, this.getNextJavaEntityId(), javaUuid));
} else if (javaType.isOrHasParent(EntityTypes26_3.ABSTRACT_HORSE)) {
return this.addEntity(new AbstractHorseEntity(this.user(), uniqueId, runtimeId, type, this.getNextJavaEntityId(), javaUuid, javaType));
} else if (javaType.isOrHasParent(EntityTypes26_3.MOB)) {
return this.addEntity(new MobEntity(this.user(), uniqueId, runtimeId, type, this.getNextJavaEntityId(), javaUuid, javaType));
Expand Down