wip content

This commit is contained in:
2026-06-20 20:51:44 -04:00
parent 742b2d9fef
commit 8fc002cda1
14 changed files with 202 additions and 94 deletions

View File

@@ -1,70 +0,0 @@
#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 only 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

133
content/core.typ Normal file
View File

@@ -0,0 +1,133 @@
#import "/lib.typ": callout, example, note, solution, tip, todo
= 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. ]
== 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 only fall early
if it gains horizontal momentum or is pushed.
This means if we know the remainder of $"id" slash 4$, we can predict which ages allow it to fall.
And the inverse: if we know which age allowed an item to fall, we can deduce the remainder of
$"id" / 4$.
#table(
columns: (auto, auto),
$"age"$, $"id"$,
[0], [0],
[1], [3],
[2], [2],
[3], [1],
)
This means if we know the remainder of $"age" / 4$, we can
#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.]
#example[
Consider this timeline. We spawn a few items, give them time to settle on the ground, then remove
their support. We observe when item $O$ begins to fall, and infer when we should expect the other
items to fall.
- `t+0`, spawn item $O$
- `t+1`, spawn item $A$
- `t+4`, spawn item $B$
- `t+4`, spawn item $C$
- `t+20`, remove support
- `t+22`, item $O$ begins to fall
Assuming no other entities spawn in this time period; these are the only things which increment
the counter.
At what ticks should we expect items $A$, $B$, and $C$ to begin to fall?
#solution[
Item $O$ falls when its age is $22 = 2 (mod 4)$, so its id must be $-2 (mod 4)$
Item $A$ spawns next, so its id must be $-1 (mod 4)$.
It can only fall when its age is $1 (mod 4)$.
It checks on ticks `t+2`, `t+6`, `t+10`, `t+14`, `t+18`, but is supported for all these.
On tick `t+22`, it will no longer be supported and will begin to fall.
Item $B$ spawns next, so its id must be $0 (mod 4)$.
It can only fall when its age is $0 (mod 4)$.
These are ticks `t+4`, `t+8`, `t+12`, `t+16`, `t+20`. So it falls immediately when the support
is removed.
Item $C$ spawns next, so its id must be $1 (mod 4)$.
It can only fall when its age is $-1 = 3 (mod 4)$.
These are ticks `t+7`, `t+11`, `t+15`, `t+19`, `t+23`.
- `t+20` remove support, item $B$ falls
- `t+22` items $O$ and $A$ fall
- `t+23` item $C$ 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

View File

@@ -1,4 +1,4 @@
= Transport Protocols
= Data Protocols
== Mod 4 Binary
== Mod 2 Binary
@@ -6,4 +6,3 @@
== Transceivers
== Logical Operations
== Transport Protocol Catalog

View File

@@ -1,4 +1,4 @@
#import "/lib.typ": warn
#import "/lib.typ": callout, warn
#title()
@@ -14,4 +14,8 @@ Everything I know about Entity ID Wireless Redstone (EID Wireless) for Minecraft
It does not work with any version of Bedrock Edition.
]
#callout(kind: "todo", label: "TODO LIST")[
#outline(title: none, target: figure.where(kind: "todo"))
]
#outline(title: [Outline], depth: 2)

View File

@@ -1,6 +1,6 @@
#import "/lib.typ": note, tip, todo
= Interference
= Causes of 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.
@@ -33,18 +33,19 @@ The solution is to either use a dedicated minecraft server, so that the client a
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.]
#todo[Singleplayer patch links][Grab links for these mods and figure out exactly which versions
they're good for.]
== Paper Servers <paper>
#todo[Figure out which versions of Paper broke the thing.]
#todo[Paper compatibility list][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.]
#todo[Broken Paper/Spigot code][Show the patch with the busted optimization.]
== Unloaded Chunks
@@ -57,7 +58,7 @@ new entity IDs. Therefore any information encoded in the ID group offsets is des
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.]
#todo[Reload detector designs][frost walker, sculk sensor, ???]
== Lazy Chunks
@@ -77,4 +78,4 @@ The best thing to do is to use a chunkloader to prevent the receiver ever being
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.]
#todo[Lazy chunk detector designs][falling entity, ???]

View File

@@ -1,8 +1,11 @@
= Global Ticking Order <timing>
= Preventing Interference <timing>
== Tilesets
=== Binary
=== Lexicographic
=== Mixed Priority Jamming
== Block Event Delay

View File

@@ -1,5 +1,9 @@
#import "/lib.typ": todo
= Network Protocols
#todo["Network Protocol" is inaccurate]
== Collision Prevention
=== Checkbit
=== Queue

32
lib.typ
View File

@@ -33,7 +33,35 @@
}
}#let note = callout.with(kind: "note", label: "Note:")
#let note = callout.with(kind: "note", label: "Note:")
#let warn = callout.with(kind: "warn", label: "Warning:")
#let tip = callout.with(kind: "tip", label: "Tip:")
#let todo = callout.with(kind: "todo", label: "TODO:")
// #let todo = callout.with(kind: "todo", label: "TODO:")
#let todo(caption, ..args) = callout(kind: "todo", label: "TODO:", {
show figure: none
(
caption,
figure(kind: "todo", supplement: "TODO", caption: caption, none),
..args.pos(),
).join(parbreak())
})
#let example = callout.with(kind: "eg", label: "For example:")
#let details(body, label: "Details") = {
context if target() == "html" {
html.details({
html.summary(strong[Click for #label])
body
})
} else {
[
#strong(label):
#body
]
}
}
#let solution = details.with(label: "Solution")

View File

@@ -87,13 +87,14 @@
it
}
rawdoc("index.html", include "content/00-index.typ")
doc("core.html", include "content/01-core.typ")
doc("interference.html", include "content/02-interference.typ")
doc("timing.html", include "content/03-timing.typ")
doc("design.html", include "content/04-design.typ")
doc("channels.html", include "content/05-channels.typ")
doc("transport.html", include "content/06-transport.typ")
doc("bulk.html", include "content/07-bulk.typ")
doc("network.html", include "content/08-network.typ")
rawdoc("index.html", include "content/index.typ")
doc("core.html", include "content/core.typ")
doc("data-protocols.html", include "content/data-protocols.typ")
doc("interference-causes.html", include "content/interference-causes.typ")
doc("interference-fixes.html", include "content/interference-fixes.typ")
doc("design.html", include "content/design.typ")
doc("channels.html", include "content/channels.typ")
doc("bulk.html", include "content/bulk.typ")
doc("network-protocols.html", include "content/network.typ")
}

View File

@@ -1,5 +1,5 @@
[tools]
tinymist = "latest"
tinymist = "0.15.0"
typst = "0.15.0"
[tasks.watch-bundle]

View File

@@ -48,7 +48,7 @@
}
}
h1, h2, h3, h4, h5, h6, nav {
h1, h2, h3, h4, h5, h6, nav, details > summary {
font-family: Mojangles, monospace;
}
@@ -65,7 +65,7 @@ nav > ol {
}
body {
max-width: 88ch;
max-width: 68ch;
margin: 40px auto;
padding: 0 10px;
}
@@ -105,3 +105,8 @@ header p + h1 {
.callout h6 + p {
display: inline;
}
.callout *:last-child {
margin-block-end: 0;
padding-block-end: 0;
}