#import "/lib.typ": diorama, example, note, todo = Tilesets The protocols as described are very sensitive to the exact timing that the EID counter is incremented. The fundamental cause for all types of interference is that there is a chance for unexpected entities to spawn in-between the measurement items, which increments the counter and corrupts the data. The solution, then, is to make that window *as short as possible* so the chance for interference is minimized. The fundamental principle is to use the game scheduled tick priority queue to do this. A *tile sequence* is a chain of redstone components that all update in the scheduled tick phase. A *tile set* is a system of constructing tile sequences that enforces a particular global ordering. #show raw.where(lang: "mc-diorama"): it => diorama(autoplay: true, loop: true, theta: 160, phi: 20, it.text) ```mc-diorama p 0 -1 0 smooth_stone_slab type=top p 1 -1 0 smooth_stone_slab type=top p 2 -1 0 smooth_stone_slab type=top p 3 -1 0 smooth_stone_slab type=top p 4 -1 0 smooth_stone_slab type=top p 0 0 0 repeater facing=west powered=false locked=false delay=1 p 1 0 0 observer facing=west powered=false p 2 0 0 repeater facing=west powered=false locked=false delay=2 p 3 0 0 comparator facing=west powered=false mode=compare p 4 0 0 repeater facing=west powered=false locked=false delay=1 t 2 p 0 0 0 powered=true t 4 p 0 0 0 powered=false p 1 0 0 powered=true t 6 p 1 0 0 powered=false t 8 p 2 0 0 powered=true t 10 p 3 0 0 powered=true t 12 p 2 0 0 powered=false p 4 0 0 powered=true t 14 p 3 0 0 powered=false t 16 p 4 0 0 powered=false t 20 p 0 0 0 ``` == The Scheduled Tick Priority Queue There are two aspects that affect a scheduled tick's placement in the queue: its _priority_ and its _delay_. Scheduled ticks with higher (more negative) priority update first in a given game tick. Scheduled ticks with equal priority update in the order they were scheduled. See @block-priority for a list of priorities. The most important point is that repeaters have higher priority than other components. == Binary Tilesets The simplest (and generally most useful) tilesets use only two priorities. This allows us to identify each tile sequence with a binary value and easily read the update order and carve up the the full tile set for different systems. Typically we use comparators (or observers) and 2gt repeaters. We identify the higher priority (repeater) with `0`, since it sorts/updates earlier, and identify the lower priority (observer/comparator) with `1`. Then we can read off the elements of the tile sequence to form a binary number. Components that activate later in the sequence have a stronger effect on the order, so to match our left-to-right reading convention, we diagram tile sequences so the signal flows right-to-left. Consider this 4gt tileset. #show raw.where(lang: "mc-diorama"): it => diorama( autoplay: true, loop: true, theta: 90, phi: 90, speed: 0.33, radius: 8, orbit: false, it.text, ) ```mc-diorama p 0 -1 0 smooth_stone_slab type=top p 1 -1 0 smooth_stone_slab type=top p 2 -1 0 smooth_stone_slab type=top p 3 -1 0 smooth_stone_slab type=top p 4 -1 0 smooth_stone_slab type=top p 5 -1 0 smooth_stone_slab type=top p 6 -1 0 smooth_stone_slab type=top p 7 -1 0 smooth_stone_slab type=top p 0 0 0 redstone_wire east=side west=none south=side power=0 p 1 0 0 redstone_wire east=side west=side south=side power=0 p 2 0 0 redstone_wire east=side west=side south=side power=0 p 3 0 0 redstone_wire east=side west=side south=side power=0 p 4 0 0 redstone_wire east=side west=side south=side power=0 p 5 0 0 redstone_wire east=side west=side south=side power=0 p 6 0 0 redstone_wire east=side west=side south=side power=0 p 7 0 0 redstone_wire east=none west=side south=side power=0 p 0 0 1 repeater facing=north delay=1 powered=false locked=false p 1 0 1 comparator facing=north mode=compare powered=false p 2 0 1 repeater facing=north delay=1 powered=false locked=false p 3 0 1 comparator facing=north mode=compare powered=false p 4 0 1 repeater facing=north delay=1 powered=false locked=false p 5 0 1 comparator facing=north mode=compare powered=false p 6 0 1 repeater facing=north delay=1 powered=false locked=false p 7 0 1 comparator facing=north mode=compare powered=false p 0 0 2 repeater facing=north delay=1 powered=false locked=false p 1 0 2 repeater facing=north delay=1 powered=false locked=false p 2 0 2 comparator facing=north mode=compare powered=false p 3 0 2 comparator facing=north mode=compare powered=false p 4 0 2 repeater facing=north delay=1 powered=false locked=false p 5 0 2 repeater facing=north delay=1 powered=false locked=false p 6 0 2 comparator facing=north mode=compare powered=false p 7 0 2 comparator facing=north mode=compare powered=false p 0 0 3 repeater facing=north delay=1 powered=false locked=false p 1 0 3 repeater facing=north delay=1 powered=false locked=false p 2 0 3 repeater facing=north delay=1 powered=false locked=false p 3 0 3 repeater facing=north delay=1 powered=false locked=false p 4 0 3 comparator facing=north mode=compare powered=false p 5 0 3 comparator facing=north mode=compare powered=false p 6 0 3 comparator facing=north mode=compare powered=false p 7 0 3 comparator facing=north mode=compare powered=false t 0 p 0 0 0 power=15 p 1 0 0 power=15 p 2 0 0 power=15 p 3 0 0 power=15 p 4 0 0 power=15 p 5 0 0 power=15 p 6 0 0 power=15 p 7 0 0 power=15 t 1 p 0 0 1 powered=true p 2 0 1 powered=true p 4 0 1 powered=true p 6 0 1 powered=true t 2 p 1 0 1 powered=true p 3 0 1 powered=true p 5 0 1 powered=true p 7 0 1 powered=true t 3 p 0 0 0 power=0 p 1 0 0 power=0 p 2 0 0 power=0 p 3 0 0 power=0 p 4 0 0 power=0 p 5 0 0 power=0 p 6 0 0 power=0 p 7 0 0 power=0 t 4 p 0 0 2 powered=true p 4 0 2 powered=true t 5 p 1 0 2 powered=true p 5 0 2 powered=true t 6 p 2 0 2 powered=true p 6 0 2 powered=true t 7 p 3 0 2 powered=true p 7 0 2 powered=true t 8 p 0 0 1 powered=false p 2 0 1 powered=false p 4 0 1 powered=false p 6 0 1 powered=false t 9 p 0 0 3 powered=true t 10 p 1 0 3 powered=true t 11 p 2 0 3 powered=true t 12 p 3 0 3 powered=true t 13 p 1 0 1 powered=false p 3 0 1 powered=false p 5 0 1 powered=false p 7 0 1 powered=false t 14 p 4 0 3 powered=true t 15 p 5 0 3 powered=true t 16 p 6 0 3 powered=true t 17 p 7 0 3 powered=true t 18 p 0 0 2 powered=false p 4 0 2 powered=false t 19 p 1 0 2 powered=false p 5 0 2 powered=false t 20 p 2 0 2 powered=false p 6 0 2 powered=false t 21 p 3 0 2 powered=false p 7 0 2 powered=false t 22 p 0 0 3 powered=false t 23 p 1 0 3 powered=false t 24 p 2 0 3 powered=false t 25 p 3 0 3 powered=false t 26 p 4 0 3 powered=false t 27 p 5 0 3 powered=false t 28 p 6 0 3 powered=false t 29 p 7 0 3 powered=false t 30 p 0 0 0 ``` We can express the same tileset numerically like so: ``` 000 = 0 001 = 1 010 = 2 011 = 3 100 = 4 101 = 5 110 = 6 111 = 7 ``` Using the same pattern, we can generate a tile sequence for an arbitrary value of arbitrary bit-length. For example, the 8-bit tileset for `150` is: 10010110 #show raw.where(lang: "mc-diorama"): it => diorama( theta: 90, phi: 90, speed: 0.33, radius: 5, orbit: false, it.text, ) ```mc-diorama p 0 -1 0 smooth_stone_slab type=top p 0 -1 1 smooth_stone_slab type=top p 0 -1 2 smooth_stone_slab type=top p 0 -1 3 smooth_stone_slab type=top p 0 -1 4 smooth_stone_slab type=top p 0 -1 5 smooth_stone_slab type=top p 0 -1 6 smooth_stone_slab type=top p 0 -1 7 smooth_stone_slab type=top p 0 0 0 repeater facing=north powered=false locked=false delay=1 p 0 0 1 comparator facing=north powered=false mode=compare p 0 0 2 comparator facing=north powered=false mode=compare p 0 0 3 repeater facing=north powered=false locked=false delay=1 p 0 0 4 comparator facing=north powered=false mode=compare p 0 0 5 repeater facing=north powered=false locked=false delay=1 p 0 0 6 repeater facing=north powered=false locked=false delay=1 p 0 0 7 comparator facing=north powered=false mode=compare ``` To break this down: the bottom two (AA, AB) end in repeaters, so they must come first. Among those, (AA) comes first. Among the top two (BA, BB), (BA) comes first. It's standard alphabetizing. Just as the order of the alphabet creates an ordering over all words, the ordering of the comparator and repeater creates an ordering of all tilesets. The 6gt tileset. There are now eight options. ``` <--------- ... ``` As the tilesets get larger, it's less useful to lay out the entire tileset and more useful to find the next and previous lanes. For example, take this 7-diode tileset. ``` cmp rep rep cmp rep cmp cmp <-------------------------- B A A B A B B ``` We can easily find the next lane by thinking of this not as a *word* but as a *number*. We have two options, and one is greater than the other. ``` cmp rep rep cmp rep cmp cmp <-------------------------- B A A B A B B 1 0 0 1 0 1 1 ``` We can think of this tileset as a 7-bit binary number, in this case the value 75. We can find the next lane by simply incrementing by one. ``` 1 0 0 1 0 1 1 (75) + 1 1 0 0 1 1 0 0 (76) <-------------------------- cmp rep rep cmp cmp rep rep ``` // So the full picture involves arbitrary components and priorities. As long as all the tilesets // have // the same total delay and end at the same time, we can determine a global ordering. However the // general picture is hard to reason about, we basically have to simulate the priority queue to make // predictions. If we restrict the design of the tilesets a bit, there are two simplifications we could take to make things easier to reason about. == Permutation Tilesets #todo[describe the mixed delay permutation tilesets and the alphabetization procedure] == Lexicographic Tilesets == Jamming == Observer Bug == Tables === Block Tick Priorities #table( columns: 4, table.cell(rowspan: 3)[Repeater], [Facing diode (that is not facing it)], [`EXTREMELY_HIGH`], [-3], [Powering off], [`VERY_HIGH`], [-2], [Powering on], [`HIGH`], [-1], table.cell(rowspan: 2)[Comparator], [Facing diode (that is not facing it)], [`HIGH`], [-1], [Otherwise], [`NORMAL`], [0], table.cell(colspan: 2)[All other components], [`NORMAL`], [0], ) === Block Tick Delays #table( columns: 2, [Repeater], [2gt, 4gt, 6gt, 8gt], [Comparator], table.cell(rowspan: 4)[2gt], [Redstone Torch], [Falling Blocks], [Observer (see @observer-bug)], [Dispenser], table.cell(rowspan: 3)[4gt], [Dropper], [Redstone Lamp], [Iron Pressure Plate], table.cell(rowspan: 4)[10gt], [Gold Pressure Plate], [Tripwire Hook], [Tripwire], [Stone Button], table.cell(rowspan: 3)[20gt], [Stone Pressure Plate], [Detector Rail], [Wooden Button], table.cell(rowspan: 2)[30gt], [Wooden Pressure Plate], ) === Fluid Tick Delays #table( columns: 2, [Water], [5gt], [Nether Lava], [10gt], [Lava], [30gt], )