content
This commit is contained in:
@@ -1,5 +1,69 @@
|
||||
#import "/lib.typ": note, tip, todo
|
||||
|
||||
= Core Mechanics
|
||||
|
||||
== Entity IDs
|
||||
|
||||
Entities are the dynamic movable objects in the game. Minecraft tracks every entity with a unique
|
||||
ID number. Whenever an entity is added to the game world, a global counter is incremented
|
||||
and the new entity is assigned the current value.
|
||||
|
||||
A large number of game objects are tracked in this way, and so creating any one of them will increment that global
|
||||
counter. To reiterate, *this is a global counter, shared for all entities in the game*.
|
||||
|
||||
== Stationary Item Optimization
|
||||
|
||||
Typically, item entities fall to the floor and sit stationary soon after being created. Processing
|
||||
movement for these stationary entities would be wasteful, so an optimization was added in 1.14: if
|
||||
an item is sitting stationary on a block, then only check for gravity every 4 ticks.
|
||||
|
||||
Here is the relevant code path for the optimization.
|
||||
|
||||
#note[ `onGround` is only ever updated from `move()`, and this branch is the *only* place that
|
||||
`move()` is called. ]
|
||||
|
||||
```java
|
||||
public class ItemEntity extends Entity {
|
||||
public void tick() {
|
||||
...
|
||||
if (this.onGround() && !(this.getDeltaMovement().horizontalDistanceSqr() > (double)1.0E-5F) && (this.tickCount + this.getId()) % 4 != 0) {
|
||||
...
|
||||
} else {
|
||||
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
public class Entity {
|
||||
public void move(final MoverType moverType, Vec3 delta) {
|
||||
...
|
||||
this.setOnGroundWithMovement(this.verticalCollisionBelow, this.horizontalCollision, movement);
|
||||
...
|
||||
}
|
||||
|
||||
public void setOnGroundWithMovement(final boolean onGround, final boolean horizontalCollision, final Vec3 movement) {
|
||||
this.onGround = onGround;
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
== Observable Drop Delay
|
||||
|
||||
The effect is that if the item is on a block and has negligible horizontal momentum, it *cannot
|
||||
fall* until the condition is satisfied, even if it's no longer on the ground. It can fall early if
|
||||
it gains horizontal momentum or is pushed.
|
||||
|
||||
#tip[ You can rewrite the condition as `(age % 4 == (-id) % 4)` ]
|
||||
|
||||
#todo[ An animation. Spawn a few items, note their ID and age. Let them settle on a block,
|
||||
then remove that supporting block. There will be a few ticks where the item hovers in place before
|
||||
it falls. ]
|
||||
|
||||
For simplicity, suppose we spawn all our items on the same tick. Then `this.tickCount` will be the
|
||||
same for all of them, and we only need to consider the ID.
|
||||
|
||||
The result of this is that if you spawn several item entities, allow them to settle on a block, then
|
||||
remove that block
|
||||
|
||||
@@ -1,7 +1,78 @@
|
||||
#import "/lib.typ": note, tip, todo
|
||||
|
||||
= Interference
|
||||
|
||||
We need precise control over the entity age and ID for this to work, so sources of interference are
|
||||
generally unexpected entity spawns that mess up the ID.
|
||||
|
||||
== Other Entities
|
||||
== Single-Player (before 26.2) <singleplayer>
|
||||
|
||||
Recall that *any* entity spawning will increment the ID counter, and the full list of entities is
|
||||
surprising. An exhaustive list is available at
|
||||
#link("https://minecraft.wiki/w/Entity#Types_of_entities")[The Minecraft Wiki].
|
||||
|
||||
In general, the solution is to spawn our item entities at nearly the same time, so there is no
|
||||
chance for other entities to spawn in-between. For example, by spawning all items with droppers in
|
||||
the same game tick, all the items are created in the same tick phase, so player inputs and world
|
||||
events cannot affect it. See @timing for details.
|
||||
|
||||
== Singleplayer (before 26.2) <singleplayer>
|
||||
|
||||
In singleplayer worlds, there are separate execution threads for the renderer and game world. The
|
||||
game world ("server thread") contains the item entities we care about for the purposes of EID
|
||||
Wireless, as these are the entities we can detect with redstone. However, the renderer ("client
|
||||
thread") *also* tracks some entities.
|
||||
|
||||
In versions before 26.2, there was a bug that caused the client thread and server thread to use the
|
||||
*same* global ID counter. Therefore every entity might increment the counter twice: once when it
|
||||
spawns in the server, and once when the client begins to track it.
|
||||
|
||||
The solution is to either use a dedicated minecraft server, so that the client and servers run in
|
||||
separate processes, or install a mod which patches the game to use a separate counter for the
|
||||
client.
|
||||
|
||||
#todo[Grab links for these mods and figure out exactly which versions they're good for.]
|
||||
|
||||
== Paper Servers <paper>
|
||||
== Lazy Chunks
|
||||
|
||||
#todo[Figure out which versions of Paper broke the thing.]
|
||||
|
||||
Most recent versions of Paper server are compatible with EID Wireless. However, there are old
|
||||
versions of Spigot which include a *different* stationary item optimization which corrupts this. A
|
||||
few versions of Paper erroneously included this old optimization (on top of the mod 4 optimization)
|
||||
which breaks EID Wireless.
|
||||
|
||||
#todo[Show the patch with the busted optimization.]
|
||||
|
||||
== Unloaded Chunks
|
||||
|
||||
When a chunk unloads and reloads, all entities contained within it are destroyed and recreated with
|
||||
new entity IDs. Therefore any information encoded in the ID group offsets is destroyed.
|
||||
|
||||
#tip[ When a chunk containing an EID Wireless receiver is reloaded, every in-progress transmission
|
||||
*MUST* be discarded. ]
|
||||
|
||||
The best thing to do is to use a reload detector and lock the receiver output for one full cycle
|
||||
after a reload.
|
||||
|
||||
#todo[Get links to frost walker and sculk sensor reload detector designs.]
|
||||
|
||||
== Lazy Chunks
|
||||
|
||||
Entities in lazy chunks do not age or move, and their IDs are preserved. However, the redstone
|
||||
circuitry will continue to function. If a chunk becomes lazy while a transmission is being
|
||||
processed, the detection circuits will not observe the right drop delays and so the transmission is
|
||||
corrupted.
|
||||
|
||||
#tip[ When a chunk containing an EID Wireless receiver becomes lazy, every in-progress transmission
|
||||
*MUST* be discarded. ]
|
||||
|
||||
Further, depending on the receiver design, there is a small chance the items become clipped into
|
||||
blocks. When the chunk becomes entity-processing again, the clipped items will fly out of the
|
||||
machine instead of being recycled.
|
||||
|
||||
The best thing to do is to use a chunkloader to prevent the receiver ever being lazy-loaded. If
|
||||
chunkloaders cannot be used, a lazy-chunk detector can be used to lock the outputs while the chunk
|
||||
is lazy-loaded and for one full cycle after it becomes entity-processing.
|
||||
|
||||
#todo[Get links to lazy-chunk detectors.]
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
= Global Ticking Order
|
||||
= Global Ticking Order <timing>
|
||||
|
||||
== Tilesets
|
||||
=== Binary
|
||||
=== Lexicographic
|
||||
=== Mixed Priority Jamming
|
||||
|
||||
== Block Event Delay
|
||||
|
||||
== Single-Priority Loops
|
||||
Reference in New Issue
Block a user