Version 1.19 - Forge 41.0.63
I want to create a wolf entity that I can ride, so far it seems to be working, but the problem is that when I get on the wolf, I can’t control it. I then discovered that the issue is that the server doesn’t detect that I’m riding the wolf, so I’m struggling with synchronization. However, it seems to not be working properly. As I understand it, the server receives the packet but doesn’t register it correctly. I’m a bit new to Java, and I’ll try to provide all the relevant code and prints
*The comments and prints are translated by chatgpt since they were originally in Spanish*
Thank you very much in advance
No player is mounted, or the passenger is not a player.
No player is mounted, or the passenger is not a player.
No player is mounted, or the passenger is not a player.
No player is mounted, or the passenger is not a player.
No player is mounted, or the passenger is not a player.
MountableWolfEntity
package com.vals.valscraft.entity;
import com.vals.valscraft.network.MountSyncPacket;
import com.vals.valscraft.network.NetworkHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.animal.Wolf;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.network.PacketDistributor;
public class MountableWolfEntity extends Wolf {
private boolean hasSaddle;
private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(MountableWolfEntity.class, EntityDataSerializers.BYTE);
public MountableWolfEntity(EntityType<? extends Wolf> type, Level level) {
super(type, level);
this.hasSaddle = false;
}
@Override
protected void defineSynchedData() {
super.defineSynchedData();
this.entityData.define(DATA_ID_FLAGS, (byte)0);
}
public static AttributeSupplier.Builder createAttributes() {
return Wolf.createAttributes()
.add(Attributes.MAX_HEALTH, 20.0)
.add(Attributes.MOVEMENT_SPEED, 0.3);
}
@Override
public InteractionResult mobInteract(Player player, InteractionHand hand) {
ItemStack itemstack = player.getItemInHand(hand);
if (itemstack.getItem() == Items.SADDLE && !this.hasSaddle()) {
if (!player.isCreative()) {
itemstack.shrink(1);
}
this.setSaddle(true);
return InteractionResult.SUCCESS;
} else if (!level.isClientSide && this.hasSaddle()) {
player.startRiding(this);
MountSyncPacket packet = new MountSyncPacket(true); // 'true' means the player is mounted
NetworkHandler.CHANNEL.sendToServer(packet); // Ensure the server handles the packet
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
@Override
public void travel(Vec3 travelVector) {
if (this.isVehicle() && this.getControllingPassenger() instanceof Player) {
System.out.println("The wolf has a passenger.");
System.out.println("The passenger is a player.");
Player player = (Player) this.getControllingPassenger(); // Ensure the player is the controller
this.setYRot(player.getYRot());
this.yRotO = this.getYRot();
this.setXRot(player.getXRot() * 0.5F);
this.setRot(this.getYRot(), this.getXRot());
this.yBodyRot = this.getYRot();
this.yHeadRot = this.yBodyRot;
float forward = player.zza;
float strafe = player.xxa;
if (forward <= 0.0F) {
forward *= 0.25F;
}
this.flyingSpeed = this.getSpeed() * 0.1F;
this.setSpeed((float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 1.5F);
this.setDeltaMovement(new Vec3(strafe, travelVector.y, forward).scale(this.getSpeed()));
this.calculateEntityAnimation(this, false);
} else {
// The wolf does not have a passenger or the passenger is not a player
System.out.println("No player is mounted, or the passenger is not a player.");
super.travel(travelVector);
}
}
public boolean hasSaddle() {
return this.hasSaddle;
}
public void setSaddle(boolean hasSaddle) {
this.hasSaddle = hasSaddle;
}
@Override
protected void dropEquipment() {
super.dropEquipment();
if (this.hasSaddle()) {
this.spawnAtLocation(Items.SADDLE);
this.setSaddle(false);
}
}
@SubscribeEvent
public static void onServerTick(TickEvent.ServerTickEvent event) {
if (event.phase == TickEvent.Phase.START) {
MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer();
if (server != null) {
for (ServerPlayer player : server.getPlayerList().getPlayers()) {
if (player.isPassenger() && player.getVehicle() instanceof MountableWolfEntity) {
MountableWolfEntity wolf = (MountableWolfEntity) player.getVehicle();
System.out.println("Tick: " + player.getName().getString() + " is correctly mounted on " + wolf);
}
}
}
}
}
private boolean lastMountedState = false;
@Override
public void tick() {
super.tick();
if (!this.level.isClientSide) { // Only on the server
boolean isMounted = this.isVehicle() && this.getControllingPassenger() instanceof Player;
// Only print if the state changed
if (isMounted != lastMountedState) {
if (isMounted) {
Player player = (Player) this.getControllingPassenger(); // Verify the passenger is a player
System.out.println("Server: Player " + player.getName().getString() + " is now mounted.");
} else {
System.out.println("Server: The wolf no longer has a passenger.");
}
lastMountedState = isMounted;
}
}
}
@Override
public void addPassenger(Entity passenger) {
super.addPassenger(passenger);
if (passenger instanceof Player) {
Player player = (Player) passenger;
if (!this.level.isClientSide && player instanceof ServerPlayer) {
// Send the packet to the server to indicate the player is mounted
NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(true));
}
}
}
@Override
public void removePassenger(Entity passenger) {
super.removePassenger(passenger);
if (passenger instanceof Player) {
Player player = (Player) passenger;
if (!this.level.isClientSide && player instanceof ServerPlayer) {
// Send the packet to the server to indicate the player is no longer mounted
NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(false));
}
}
}
@Override
public boolean isControlledByLocalInstance() {
Entity entity = this.getControllingPassenger();
return entity instanceof Player;
}
@Override
public void positionRider(Entity passenger) {
if (this.hasPassenger(passenger)) {
double xOffset = Math.cos(Math.toRadians(this.getYRot() + 90)) * 0.4;
double zOffset = Math.sin(Math.toRadians(this.getYRot() + 90)) * 0.4;
passenger.setPos(this.getX() + xOffset, this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset(), this.getZ() + zOffset);
}
}
}
MountSyncPacket
package com.vals.valscraft.network;
import com.vals.valscraft.entity.MountableWolfEntity;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class MountSyncPacket {
private final boolean isMounted;
public MountSyncPacket(boolean isMounted) {
this.isMounted = isMounted;
}
public void encode(FriendlyByteBuf buffer) {
buffer.writeBoolean(isMounted);
}
public static MountSyncPacket decode(FriendlyByteBuf buffer) {
return new MountSyncPacket(buffer.readBoolean());
}
public void handle(NetworkEvent.Context context) {
context.enqueueWork(() -> {
ServerPlayer player = context.getSender(); // Get the player from the context
if (player != null) {
// Verifies if the player has dismounted
if (!isMounted) {
Entity vehicle = player.getVehicle();
if (vehicle instanceof MountableWolfEntity wolf) {
// Logic to remove the player as a passenger
wolf.removePassenger(player);
System.out.println("Server: Player " + player.getName().getString() + " is no longer mounted.");
}
}
}
});
context.setPacketHandled(true); // Marks the packet as handled
}
}
networkHandler
package com.vals.valscraft.network;
import com.vals.valscraft.valscraft;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.network.simple.SimpleChannel;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class NetworkHandler {
private static final String PROTOCOL_VERSION = "1";
public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel(
new ResourceLocation(valscraft.MODID, "main"),
() -> PROTOCOL_VERSION,
PROTOCOL_VERSION::equals,
PROTOCOL_VERSION::equals
);
public static void init() {
int packetId = 0;
// Register the mount synchronization packet
CHANNEL.registerMessage(
packetId++,
MountSyncPacket.class,
MountSyncPacket::encode,
MountSyncPacket::decode,
(msg, context) -> msg.handle(context.get()) // Get the context with context.get()
);
}
}