diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a42a750..8e59b0e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,12 +19,21 @@ That compiles the modules, runs the tests and builds the Javadoc. An incomplete fails the build, so a green `./gradlew build` is also the documentation check. **A build from source needs OneLiteFeather Maven credentials.** Falco compiles against Minestom and -the internal `mycelium-bom`, which are served from an authenticated endpoint, so `./gradlew build` -fails with a 401 without them. This affects only work on Falco itself — the published artefacts are -served without authentication and a build that consumes them needs no credentials. The names the -credentials are read under are in +the internal `mycelium-bom` through `https://repo.onelitefeather.dev/onelitefeather`, which answers +`401` to an anonymous request, so `./gradlew build` fails without them. This affects only work on +Falco itself. The names the credentials are read under are in [Installation](https://github.com/OneLiteFeatherNET/Falco/wiki/Installation#building-from-source). +**Consuming Falco needs no credentials from this release onwards, and did need them before it.** The +jars were always served without authentication, but a POM is resolved as well as a jar, and up to +2.1.0 every module's POM imported `net.onelitefeather:mycelium-bom:1.7.2` in its +`dependencyManagement`. That version is on neither `https://repo.onelitefeather.dev/releases` — which +carries 1.8.3 and up — nor Maven Central, so a consumer without credentials got +`Could not find net.onelitefeather:mycelium-bom:1.7.2` and no Minestom version to constrain against. +The bump to 1.8.5 is what closes that: measured against a clean Gradle home with only `mavenCentral()` +and the public `releases` endpoint declared, the 1.8.5 import resolves and brings Minestom +`2026.08.28-26.2` with it, where the same probe against 1.7.2 fails. + Running a single test class, building the benchmark jar and starting the two demo servers are further commands, listed under [Working on this](https://github.com/OneLiteFeatherNET/Falco/wiki/Contributing#working-on-this). diff --git a/README.md b/README.md index 0374206..888df9f 100644 --- a/README.md +++ b/README.md @@ -363,6 +363,14 @@ chunk from its own. The reasoning is in Measured, not asserted. Every timing below comes from a JMH benchmark in this repository and is quoted with the condition it was measured under. +One condition is missing from all of them and is worth naming here rather than leaving implied: the +Minestom version. The rows that quote a factor compare Falco against the loader Minestom ships, so +the Minestom under test is part of the measurement, and no provenance line below records it — the +run commit is not recorded either, so it cannot be recovered after the fact. Every figure below was +taken before this repository moved to Minestom `2026.08.28-26.2`, and none has been re-run against +it. Read the comparison rows as unverified on 26.2 until a baseline is taken there; the jol count is +unaffected, being a count of objects on a heap rather than a comparison. + One claim is not a timing and is marked as such where it appears: **a chunk allocates its sections when something writes into them**, which takes a fresh chunk from 192 objects and 6 848 bytes to 25 and 840. That comes from jol rather than from JMH — it is a count of objects on a heap, it has no diff --git a/falco-archunit/src/test/java/net/onelitefeather/falco/architecture/ForeignCouplingTest.java b/falco-archunit/src/test/java/net/onelitefeather/falco/architecture/ForeignCouplingTest.java index 027a809..057075a 100644 --- a/falco-archunit/src/test/java/net/onelitefeather/falco/architecture/ForeignCouplingTest.java +++ b/falco-archunit/src/test/java/net/onelitefeather/falco/architecture/ForeignCouplingTest.java @@ -126,7 +126,8 @@ class ForeignCouplingTest { /** * F3a — {@code Section} is a record whose {@code clone()} ({@code instance/Section.java:26-33} - * of Minestom {@code 2026.06.20-26.1.2}) calls {@code Light.sky()}/{@code Light.block()} + * of Minestom {@code 2026.08.28-26.2}, at the same lines and with the same body as in + * {@code 2026.06.20-26.1.2}) calls {@code Light.sky()}/{@code Light.block()} * directly and copies existing light objects only via {@code set(array())}. A foreign * {@code Light} implementation is therefore silently replaced by the built-in one on the next * chunk copy — light looks right locally and disappears later. The prototype that carried a diff --git a/falco-archunit/src/test/java/net/onelitefeather/falco/architecture/ForeignWritePathTest.java b/falco-archunit/src/test/java/net/onelitefeather/falco/architecture/ForeignWritePathTest.java index d815495..9d5cefe 100644 --- a/falco-archunit/src/test/java/net/onelitefeather/falco/architecture/ForeignWritePathTest.java +++ b/falco-archunit/src/test/java/net/onelitefeather/falco/architecture/ForeignWritePathTest.java @@ -44,9 +44,11 @@ * has to be rewritten, and the decision not to override {@code setBlock} has to be taken again". * *
Verified against Minestom {@code 2026.06.20-26.1.2} with {@code javap} before the rules were - * written: {@code UNSAFE_setBlock} is {@code private synchronized} at {@code InstanceContainer:149}, - * and the four call sites are in {@code setBlock} ({@code :135}), {@code placeBlock} ({@code :223}), - * {@code breakBlock} ({@code :250}) and {@code executeNeighboursBlockPlacementRule} ({@code :756}). + * written, and read again against {@code 2026.08.28-26.2} when this repository moved to it: the + * shape is the same and only the line numbers moved. On 26.2 {@code UNSAFE_setBlock} is + * {@code private synchronized} at {@code InstanceContainer:161}, and the four call sites are in + * {@code setBlock} ({@code :147}), {@code placeBlock} ({@code :235}), {@code breakBlock} + * ({@code :262}) and {@code executeNeighboursBlockPlacementRule} ({@code :779}). * The rules assert exactly that, so all four were green on their first run and each had to be proved * to bite on its own: W1 by pointing {@link #UNSAFE_SET_BLOCK} at {@code setBlock}, which is neither * private nor synchronised; W2 by swapping {@code breakBlock} for {@code loadChunk} in diff --git a/falco-demo/README.md b/falco-demo/README.md index aadb56c..fdb714d 100644 --- a/falco-demo/README.md +++ b/falco-demo/README.md @@ -47,11 +47,11 @@ Then connect to **`localhost:25565`**. Stop the server with ctrl-c. | | | | --- | --- | -| **Minecraft client** | **26.1.2** | -| Protocol | 775 | +| **Minecraft client** | **26.2** | +| Protocol | 776 | | Authentication | **offline mode** — no Mojang login, any username is accepted | -The version follows from the Minestom this repository builds against, `2026.06.20-26.1.2`: the part +The version follows from the Minestom this repository builds against, `2026.08.28-26.2`: the part after the dash is the Minecraft version it speaks. A client on any other version is turned away during the handshake, which is by far the most likely reason a connection fails. The server prints both numbers on startup, so after a Minestom upgrade believe the log rather than this table. diff --git a/falco-instance/src/main/java/net/onelitefeather/falco/instance/FalcoChunk.java b/falco-instance/src/main/java/net/onelitefeather/falco/instance/FalcoChunk.java index ac33dca..f7323e1 100644 --- a/falco-instance/src/main/java/net/onelitefeather/falco/instance/FalcoChunk.java +++ b/falco-instance/src/main/java/net/onelitefeather/falco/instance/FalcoChunk.java @@ -940,9 +940,12 @@ public ChunkSnapshot updateSnapshot(SnapshotUpdater updater) { } final var entities = instance.getEntityTracker().chunkEntities(chunkX, chunkZ, EntityTracker.Target.ENTITIES); final int[] entityIds = ArrayUtils.mapToIntArray(entities, Entity::getEntityId); + // The biome registry is passed in rather than read from a static: since 26.2 the snapshot + // record holds the registry it resolves biome ids against, so a snapshot answers with the + // registry of the instance it was taken from instead of the one of the running server. return new SnapshotImpl.Chunk(minSection, chunkX, chunkZ, clonedSections, this.entries.clone(), entityIds, updater.reference(instance), - tagHandler().readableCopy()); + instance.registries().biome(), tagHandler().readableCopy()); } /** diff --git a/falco-instance/src/test/java/net/onelitefeather/falco/instance/FalcoInstanceUnloadTest.java b/falco-instance/src/test/java/net/onelitefeather/falco/instance/FalcoInstanceUnloadTest.java index 28d8a93..87ca3f9 100644 --- a/falco-instance/src/test/java/net/onelitefeather/falco/instance/FalcoInstanceUnloadTest.java +++ b/falco-instance/src/test/java/net/onelitefeather/falco/instance/FalcoInstanceUnloadTest.java @@ -120,7 +120,7 @@ void testTheInstanceManagerAloneStillLeaksTheChunks(Env env) { manager.unregisterInstance(instance); - // Pinned against Minestom 2026.06.20-26.1.2: the manager only unloads chunks for an + // Pinned against Minestom 2026.08.28-26.2: the manager only unloads chunks for an // InstanceContainer, which is why FalcoInstance#unregister exists. If this ever starts to // fail, Minestom has learned to clean up foreign instances and the own path can shrink. assertFalse(instance.isRegistered()); diff --git a/falco-instance/src/test/java/net/onelitefeather/falco/instance/FalcoSharedInstanceResendTest.java b/falco-instance/src/test/java/net/onelitefeather/falco/instance/FalcoSharedInstanceResendTest.java index e64ae42..5545ea3 100644 --- a/falco-instance/src/test/java/net/onelitefeather/falco/instance/FalcoSharedInstanceResendTest.java +++ b/falco-instance/src/test/java/net/onelitefeather/falco/instance/FalcoSharedInstanceResendTest.java @@ -2,6 +2,8 @@ import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.Player; +import net.minestom.server.event.EventFilter; +import net.minestom.server.event.player.PlayerChunkUnloadEvent; import net.minestom.server.instance.InstanceContainer; import net.minestom.server.network.packet.server.play.ChunkDataPacket; import net.minestom.server.network.packet.server.play.UnloadChunkPacket; @@ -16,7 +18,6 @@ import java.util.UUID; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertSame; /** @@ -40,12 +41,25 @@ * direct US-4.01 statement in this file, not a decorative one. *
*- * {@code UpdateViewPositionPacket} and {@code UnloadChunkPacket} are asserted next to it because - * they leave {@code Player#spawnPlayer} unconditionally under {@code updateChunks == true}, + * {@code UpdateViewPositionPacket} and {@code PlayerChunkUnloadEvent} are asserted next to it + * because they leave {@code Player#spawnPlayer} unconditionally under {@code updateChunks == true}, * independently of how chunk bodies are delivered. They keep the file honest if a future Cyano * stops overriding {@code sendChunk} — at which point the chunk counter would silently drop to zero * on both paths, and the control's {@code assertCount(25)} would say so instead of hiding it. *
+ *+ * Up to Minestom 26.1.2 the old view left {@code spawnPlayer} as one {@code UnloadChunkPacket} per + * chunk, and this file asserted those packets. Since 26.2 the packet is withheld for a chunk that + * is also in the new view: the client of 26.2 drops a chunk it receives an unload and a data packet + * for within the same frame (MC-310041), and Minestom carries the workaround with a + * {@code TODO(26.3)} to revert it once the client is fixed. The control below transfers to the same + * position, so every one of its 25 chunks is in the new view and not a single packet is sent — the + * per-chunk unload is still there, as the event that fires beside the suppressed packet. Asserting + * the event keeps the marker measuring what it was written to measure across both behaviours, and + * {@code unloads.assertEmpty()} states the 26.2 suppression itself, so the revert in 26.3 fails + * here rather than passing unnoticed. + *
* * @author TheMeinerLP * @version 1.0.0 @@ -78,12 +92,17 @@ void testTheFastPathSendsNothing(Env env) { final Collector* Every expectation is derived from the source of Minestom {@code 2026.06.20-26.1.2} before it is - * run, not corrected afterwards until the bar turns green. The dimension is the overworld: twenty-four + * run, not corrected afterwards until the bar turns green, and every one of them survived the move + * to {@code 2026.08.28-26.2} unchanged. The dimension is the overworld: twenty-four * sections, world Y from {@code -64} to {@code 319}, so {@code Heightmap#minHeight} is {@code -65} and * a column scan that finds nothing walks to the floor. *
diff --git a/settings.gradle.kts b/settings.gradle.kts index 6996fab..6e1421c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -31,7 +31,7 @@ dependencyResolutionManagement { } versionCatalogs { create("libs") { - version("bom", "1.7.2") + version("bom", "1.8.5") version("slf4j", "2.0.18") version("annotations", "26.1.0") version("jmh", "1.37")