From 98e9869daa84036067d2f0d94c6e69f85defcaeb Mon Sep 17 00:00:00 2001 From: Darto KLoning Date: Sat, 3 Oct 2026 10:02:46 +0700 Subject: [PATCH] Update Handcrafted v4.0.9 --- PORTING-NOTES.md | 7 +++ compile.bat | 4 +- compile.sh | 3 +- gradle.properties | 2 +- .../common/blocks/base/SittableBlock.java | 14 +++--- .../handcrafted/common/entities/Seat.java | 44 ++++++++++++------- 6 files changed, 50 insertions(+), 24 deletions(-) diff --git a/PORTING-NOTES.md b/PORTING-NOTES.md index 416687b..f680cd5 100644 --- a/PORTING-NOTES.md +++ b/PORTING-NOTES.md @@ -1,3 +1,10 @@ +## 4.0.9 — Seat synchronization fix +- Compared the Fabric 26.2 port directly against the original 1.21.x seating implementation. +- The current debug log proves server-side mounting already succeeds: the client reports `Received passengers for unknown entity`. This means the failure is no longer the chair/bench/couch interaction callback; the invisible `Seat` vehicle is not known client-side when the passenger update arrives. +- Removed the legacy custom `ClientboundAddEntityPacket`/`recreateFromPacket` override from `Seat` so Minecraft 26.2 uses its native entity spawn/tracking packet path. +- Kept one-passenger acceptance and the 26.2 passenger attachment implementation. +- `compile.bat` and `compile.sh` now read both `mod_version` and `archives_base_name` from `gradle.properties` when detecting an already-built JAR. Existing-JAR Compile/Git-only behavior and first-time Git guidance are preserved. + # Handcrafted Fabric 26.2 port Target: Minecraft 26.2 / Fabric only / Java 25. diff --git a/compile.bat b/compile.bat index 9fde14c..31617a9 100644 --- a/compile.bat +++ b/compile.bat @@ -31,13 +31,15 @@ for /f "usebackq tokens=1,* delims==" %%A in ("%GRADLE_PROPERTIES%") do ( if "%%A"=="mod_version" set "MOD_VERSION=%%B" if "%%A"=="minecraft_version" set "MINECRAFT_VERSION=%%B" if "%%A"=="maven_group" set "MAVEN_GROUP=%%B" + if "%%A"=="archives_base_name" set "ARCHIVES_BASE_NAME=%%B" ) if not defined MOD_VERSION set "MOD_VERSION=unknown" if not defined MINECRAFT_VERSION set "MINECRAFT_VERSION=26.2" if not defined MAVEN_GROUP set "MAVEN_GROUP=id.dartokloning" -set "JAR_PATH=%CD%\build\libs\handcrafted-fabric-26.2-%MOD_VERSION%.jar" +if not defined ARCHIVES_BASE_NAME set "ARCHIVES_BASE_NAME=handcrafted" +set "JAR_PATH=%CD%\build\libs\%ARCHIVES_BASE_NAME%-%MOD_VERSION%.jar" echo ============================================ echo Handcrafted - Fabric %MINECRAFT_VERSION% Build diff --git a/compile.sh b/compile.sh index 7d25bef..5c1a2c5 100644 --- a/compile.sh +++ b/compile.sh @@ -28,7 +28,8 @@ get_prop() { sed -n "s/^$1=//p" "$GRADLE_PROPERTIES" | tail -n 1 | tr -d '\r'; } MOD_VERSION="$(get_prop mod_version)"; MOD_VERSION="${MOD_VERSION:-unknown}" MINECRAFT_VERSION="$(get_prop minecraft_version)"; MINECRAFT_VERSION="${MINECRAFT_VERSION:-26.2}" MAVEN_GROUP="$(get_prop maven_group)"; MAVEN_GROUP="${MAVEN_GROUP:-id.dartokloning}" -JAR_PATH="$PWD/build/libs/handcrafted-fabric-26.2-$MOD_VERSION.jar" +ARCHIVES_BASE_NAME="$(get_prop archives_base_name)"; ARCHIVES_BASE_NAME="${ARCHIVES_BASE_NAME:-handcrafted}" +JAR_PATH="$PWD/build/libs/$ARCHIVES_BASE_NAME-$MOD_VERSION.jar" echo "============================================" echo " Handcrafted - Fabric $MINECRAFT_VERSION Build" diff --git a/gradle.properties b/gradle.properties index 586c24a..a7877c3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx4G org.gradle.parallel=true org.gradle.caching=true -mod_version=4.0.6-fabric-26.2 +mod_version=4.0.9 maven_group=earth.terrarium.handcrafted archives_base_name=handcrafted diff --git a/src/main/java/earth/terrarium/handcrafted/common/blocks/base/SittableBlock.java b/src/main/java/earth/terrarium/handcrafted/common/blocks/base/SittableBlock.java index aaaf9f9..7d077c2 100644 --- a/src/main/java/earth/terrarium/handcrafted/common/blocks/base/SittableBlock.java +++ b/src/main/java/earth/terrarium/handcrafted/common/blocks/base/SittableBlock.java @@ -19,11 +19,15 @@ public interface SittableBlock { if (!Seat.SITTING_POSITIONS.get(level.dimension()).contains(pos)) { Seat entity = Seat.of(level, pos, dir); if (level.addFreshEntity(entity)) { - if (player.startRiding(entity)) { - Seat.SITTING_POSITIONS.put(level.dimension(), pos.immutable()); - return true; - } - entity.removeSeat(); + // Do not mount in the same server tick in which the invisible + // Seat is spawned. In 26.2 the passenger packet can otherwise + // reach the client before the entity-spawn packet, producing + // "Received passengers for unknown entity" and an immediate + // client/server mount desync. Queue the rider and let Seat.tick() + // mount it after the entity has entered normal tracking. + Seat.SITTING_POSITIONS.put(level.dimension(), pos.immutable()); + entity.queueRider(player); + return true; } else { entity.removeSeat(); } diff --git a/src/main/java/earth/terrarium/handcrafted/common/entities/Seat.java b/src/main/java/earth/terrarium/handcrafted/common/entities/Seat.java index 4ebc826..1a7875b 100644 --- a/src/main/java/earth/terrarium/handcrafted/common/entities/Seat.java +++ b/src/main/java/earth/terrarium/handcrafted/common/entities/Seat.java @@ -8,12 +8,8 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; -import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceKey; -import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.util.Mth; @@ -35,6 +31,8 @@ public class Seat extends Entity { private AABB shape; private boolean remove; private boolean canRotate; + private Entity pendingRider; + private int mountDelayTicks; public Seat(EntityType entityType, Level level) { super(entityType, level); @@ -66,16 +64,9 @@ public class Seat extends Entity { return new AABB(aabb.minX, aabb.minY, aabb.minZ, aabb.maxX, aabb.maxY, aabb.maxZ); } - @Override - public Packet getAddEntityPacket(ServerEntity serverEntity) { - return new ClientboundAddEntityPacket(this, serverEntity, canRotate ? 1 : 0); - } - - @Override - public void recreateFromPacket(ClientboundAddEntityPacket packet) { - super.recreateFromPacket(packet); - this.canRotate = packet.getData() == 1; - } + // Use Minecraft's native entity spawn packet on 26.2. + // The old custom ClientboundAddEntityPacket path from 1.21.x can race the + // passenger packet, leaving the client with an unknown vehicle entity. @Override public boolean hurtServer(ServerLevel level, DamageSource source, float damage) { @@ -122,11 +113,32 @@ public class Seat extends Entity { return super.getDismountLocationForPassenger(passenger); } + public void queueRider(Entity rider) { + this.pendingRider = rider; + // One complete entity tick is enough for ServerEntity tracking to send + // the add-entity packet before we generate a passengers packet. + this.mountDelayTicks = 1; + } + @Override public void tick() { super.tick(); - if (!level().isClientSide() && (!(this.level().getBlockState(this.blockPosition()).getBlock() instanceof SittableBlock) || remove)) { - removeSeat(); + if (!level().isClientSide()) { + if (!(this.level().getBlockState(this.blockPosition()).getBlock() instanceof SittableBlock) || remove) { + removeSeat(); + return; + } + + if (pendingRider != null) { + if (mountDelayTicks-- <= 0) { + Entity rider = pendingRider; + pendingRider = null; + if (!rider.isRemoved() && rider.level() == this.level() && rider.startRiding(this)) { + return; + } + removeSeat(); + } + } } }