Files
wireless-docs/content/core.typ
2026-06-22 00:29:22 -04:00

219 lines
7.6 KiB
Typst

#import "/lib.typ": callout, example, note, solution, tip, todo
#let mod4 = $#h(0.5em)&(mod 4)$
= Core Mechanics <core>
== 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 process movement every 4th tick.
However, it would also be wasteful if every 4th tick processed _every_ item, so instead the items
are divided into four groups. Each tick stationary items from only one of the four groups check for
movement.
#callout(kind: "tip", label: "Key Point:")[
Stationary items can only begin to fall when their $"age" + "id"$ is a multiple of $4$.
]
Here is the relevant code path for the optimization:
```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;
...
}
}
```
#note[ `onGround` is only ever updated via `move`, and this branch is the *only* place that
`ItemEntity.move` is called. ]
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 only fall early
if it gains horizontal momentum or is pushed.
#todo[Falling item 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.]
== Observable Drop Delay
We can't control the absolute entity ID a particular item will receive, but we can *compare* ids of
multiple entities. By observing the drop delay for a "reference" item, we can predict the behavior
of other items.
#example[
Suppose we spawn four items in order. For simplicity, spawn them all in the same tick so their
ages are equal, and assume no other entities spawn.
1. Spawn items $A$, $B$, $C$, and $D$ in order in the same tick. Let them settle on a block.
2. At tick $t=0$, remove the supporting blocks.
3. At tick $t=1$, item $B$ begins to fall.
Based on when item $B$ fell, when should we expect the other items to fall?
#solution[
To simplify the arithmetic, orient everything around $t=0$. So we'll let $"age"_0$ to be the
items' ages at $t=0$ and add tick offsets from there. All items spawned in the same tick, so
they all have the same $"age"_0$.
Since $B$ falls at $t=1$, the relation for $"id"^B$ must be
$ "age"_0 + "id"^B + 1 = 0 mod4 $
$A$ spawned right before $B$, so $"id"^A + 1 = "id"^B$. Plug that in to the relation we got for
$"id"^B$.
$ "age"_0 + "id"^A + 1 + 1 = 0 mod4 $
*$A$ must fall at $t=2$.*
$C$ spawned right after $B$, so its id is $"id"^C - 1= "id"^B$. Plug that in.
$ "age"_0 + "id"^C - 1 + 1 = 0 mod4 $
*$C$ must fall at $t=0$.*
$D$ spawned right after $C$, so its id is $"id"^D - 2 = "id"^B$. Plug that in.
#tip[You can freely add or subtract 4 to either side of a mod 4 equality.]
$
"age"_0 + "id"^D - 2 + 1 &= 0 mod4 \
"age"_0 + "id"^D - 1 &= 0 mod4 \
"age"_0 + "id"^D - 1 + 4 &= 0 mod4 \
"age"_0 + "id"^D + 3 &= 0 mod4
$
*$D$ must fall at $t=3$.*
]
#todo[Demonstration]
]
#example[
Consider a variation of the previous example, but where the items do not spawn on the same tick.
Their ages will be different. Again, assume no other entities spawn.
1. Spawn item $A$ at $t=-10$.
2. Spawn items $B$ and $C$ in order at $t=-8$.
3. Spawn item $D$ at $t=-7$. Let them settle on a block.
4. At tick $t=0$, remove the supporting blocks.
5. At tick $t=1$, item $B$ begins to fall.
Based on when item $B$ fell, and accounting for the different item ages, when should we expect the
other items to fall?
#solution[
We'll need to track the item ages separately this time, but still oriented around $t=0$.
Let $"age"^B_0$ be item $B$'s age at $t=0$.
We know item $B$ fell at $t=1$, so we have the relation
$ "age"^B_0 + "id"^B + 1 = 0 mod4 $
Item $A$ spawned just before item $B$, so $"id"^A + 1 = "id"^B$. It spawned 2gt earlier, so $"age"^A_0 - 2= "age"^B_0$. Plug those in.
$ "age"^A_0 - 2 + "id"^A + 1 + 1 = 0 mod4 $
*$A$ must fall at $t=0$.*
Item $C$ spawned just after item $B$, so $"id"^C - 1 = "id"^B$. It spawned in the same tick, so $"age"^C_0 = "age"^B_0$. Plug those in.
$ "age"^C_0 + "id"^C - 1 + 1 = 0 mod4 $
*$C$ must fall at $t=0$.*
Item $D$ spawned just after item $B$, so $"id"^D - 2 = "id"^B$. It spawned 1gt later, so $"age"^D_0 + 1 = "age"^B_0$. Plug those in.
$ "age"^D_0 + 1 + "id"^D - 2 + 1 = 0 mod4 $
*$D$ must fall at $t=0$.*
]
#todo[Demonstration]
]
#example[
Now consider what it means if the pattern is broken. Keep the item ages the same for simplicity,
but this time do *not* assume that no other entities spawn.
1. Spawn items $A$, $B$, and $C$ in order in the same tick. Let them settle on a block.
2. At tick $t=0$, remove the supporting blocks. Item $C$ begins to fall.
3. At tick $t=1$, item $A$ begins to fall.
3. At tick $t=2$, item $B$ begins to fall.
What number of entities must have spawned between items $A$ and $B$? Between $B$ and $C$?
#solution[
Following the same conventions as before, where $x$ is the number of entities between $A$ and
$B$ and $y$ is the number of entities between $B$ and $C$.
The ids of $A$ and $B$ are related by
$ "id"^A + 1 + x = "id"^B $
And we observe the drop delay related by
$ "age"_0 + "id"^A + 1 = 0 mod4 $
$ "age"_0 + "id"^B + 2 = 0 mod4 $
Substitute $"id"^B$ and solve for $x$.
$
"age"_0 + "id"^A + 1 & = "age"_0 + "id"^A + 1 + x + 2 mod4 \
1 & = 3 + x mod4 \
-2 & = x mod4 \
-2 + 4 & = x mod4 \
2 & = x mod4 \
$
*So 2 entities must have spawned between $A$ and $B$.* (Or any number with a remainder of 2, like 6, 10, etc.)
The ids of $B$ and $C$ are related by
$ "id"^B + 1 + y = "id"^C $
And we observe the drop delay related related by
$ "age"_0 + "id"^B + 2 = 0 mod4 $
$ "age"_0 + "id"^C + 0 = 0 mod4 $
Substitute $"id"^C$ and solve for $y$.
$
"age"_0 + "id"^B + 2 & = "age"_0 + "id"^B + 1 + y + 0 mod4 \
2 & = 1 + y mod4 \
1 & = y mod4 \
$
*So 1 entity must have spawned between $B$ and $C$.* (Or any number with a remainder of 1, like 5, 9, etc.)
]
#todo[Demonstration]
]