wip content
This commit is contained in:
@@ -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
133
content/core.typ
Normal 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
|
||||
@@ -1,4 +1,4 @@
|
||||
= Transport Protocols
|
||||
= Data Protocols
|
||||
|
||||
== Mod 4 Binary
|
||||
== Mod 2 Binary
|
||||
@@ -6,4 +6,3 @@
|
||||
== Transceivers
|
||||
== Logical Operations
|
||||
== Transport Protocol Catalog
|
||||
|
||||
@@ -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)
|
||||
@@ -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, ???]
|
||||
@@ -1,8 +1,11 @@
|
||||
= Global Ticking Order <timing>
|
||||
= Preventing Interference <timing>
|
||||
|
||||
== Tilesets
|
||||
|
||||
=== Binary
|
||||
|
||||
=== Lexicographic
|
||||
|
||||
=== Mixed Priority Jamming
|
||||
|
||||
== Block Event Delay
|
||||
@@ -1,5 +1,9 @@
|
||||
#import "/lib.typ": todo
|
||||
|
||||
= Network Protocols
|
||||
|
||||
#todo["Network Protocol" is inaccurate]
|
||||
|
||||
== Collision Prevention
|
||||
=== Checkbit
|
||||
=== Queue
|
||||
32
lib.typ
32
lib.typ
@@ -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")
|
||||
|
||||
19
main.typ
19
main.typ
@@ -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")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[tools]
|
||||
tinymist = "latest"
|
||||
tinymist = "0.15.0"
|
||||
typst = "0.15.0"
|
||||
|
||||
[tasks.watch-bundle]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user