Skip to content

Instantly share code, notes, and snippets.

@SIsilicon
Created July 10, 2022 17:40
Show Gist options
  • Save SIsilicon/98538704ae9308fef0caafd7f3ac3bac to your computer and use it in GitHub Desktop.
Save SIsilicon/98538704ae9308fef0caafd7f3ac3bac to your computer and use it in GitHub Desktop.
Ideas for achieving piston parity in Minecraft

Problem

Minecraft Java and Bedrock edition's redstone are very similar to each other. The only place where they are clearly not alike are with pistons. The pistons on both versions have pros and cons. Java's pistons can rapid fire and drop blocks, but they are also quirky; especially when it comes to piston update order. Bedrock's pistons can move more kinds of blocks, but they can't drop blocks (since they actually finish extending before retracting), and their update order is random, but in a more predictable way.

If Minecraft will ever have redstone parity, it will not only need to combine the best of both worlds in terms of redstone, but will also need to change pistons in a way that makes them powerful, yet intuitive.

Proposal

I believe to achieve piston parity, firstly piston order needs to be revamped. It must be easy to understand (like Bedrock) but must also be consistent (like Java, to an extent). By making sure any machine involving pistons works the same way, no matter how many times it activates, or wherever it's built, it will make pistons easier to use and undertand, and still remain powerful.

Block splitting proves to be one of the most improtant properties of Java pistons. However, as it relies on a bug/quirk, it will need to be updated so that it's mechanics better fit pistons as an intentional game mechanic.

As for quasi-connectivity, while it's a useful mechanic in its own way, it could do more harm than good, and is not AS useful as the community leads on. Bedrock redstone shows that it's not a feature that's really needed, and could in fact be more trouble than it's worth as it can make it harder to compact machines that use pistons in some shape or form, accidentally powering pistons that shouldn't be powered.

Finally pistons in Java can "cancel" their extending/retracting actions, while Bedrock ones will finish before doing another action. Whether to cancel or not should be up to community consensus, but I personally think the Bedrock way should be kept as it may be less prone to unexpected behaviour (like block spitting). Perhaps it's movement speed could just be increased... 🤔

Ideas

Note: These ideas are meant to not just be powerful, but also balanced, easy to understand, and fit well into the vanilla experience.

  • Smoke: If a piston can't push blocks when activated, it emits smoke and makes a hissing sound, like lava touching water.
    • This can make debugging piston based contraptions easier as it gives visual and auditory cues as to what went wrong.
  • Retraction over extension: Block pulling is processed before block pushing.
    • So if a block were to be pushed and pulled at the same time, it will ALWAYS be pulled rather than pushed.
  • Piston power: The higher the piston power, the more likely the piston(s) will act before other pistons.
    • This value cannot be changed directly by the user.
    • By default, pistons have a piston power value of 1.
    • When multiple pistons push/pull the same blocks in the SAME direction, they act as one piston with a higher piston power
      • Under the hood, one piston moves the blocks while the others do nothing.
      • Each piston adds to the total piston power. Eg: Three pistons pushing together have a piston power value of 3.
    • When multiple pistons push/pull the same blocks in DIFFERENT directions, the group of pistons with the highest piston power move the blocks, including the other pistons if they can be.
      • If multiple pistons have the highest piston power, then none of the blocks will move. I.e. Pistons can't push, or will drop the blocks when retracting (see Piston Conflict).
  • Piston conflict: If a group of pistons affect each other's position when activated at the same time, then the whole group fails to move anything.
    • For example, a circle of pistons facing each other will not fire; even if they push each other indirectly.
    • A conflict can also happen when multiple pistons attempt to extend into the same space, or push/pull the same block(s).
    • This rule does not apply if there's a piston in the group with the highest power (see Piston Power)
  • Piston chaining: If multiple pistons push each other simultaneously, the piston that pushes them all, the base piston, fires first.
    • If the base piston can't extend, then pistons are checked up the chain until ones that CAN extend are found.
  • Controlled block spitting: Pistons can be made "half sticky". This allows intuitive control over block spitting.
    • If a half sticky piston pushed a block on extension, then it will not pull it back on retraction.
    • If it didn't push any blocks on extension, then it will pull any block infront of it on retraction.
    • What a half sticky piston should be is still being thought about. Current ideas:
      • Honey based sticky pistons. Instead of using slime balls you use honey bottles.
        • The original sticky piston may need be renamed to "Slime Piston", and this piston, "Honey Piston".
      • Use an axe on a placed piston to scrape off slime, and a slime ball to add to it.
        • When shaving slime off a sticky piston, it becomes a "Half Sticky Piston". Shaving it again makes it a regular piston.
        • Likewise, adding slime to a regular piston makes it half sticky, and adding more makes it a normal sticky piston.

Pseudocode (WIP)

For each redstone tick:
	Get all pistons in an array (pistons_in_world)
	
	Put all pistons from (pistons_in_world), extended but not activated, in an array (retracting_pistons)
	Create maps (islands (key_block -> [blocks, pistons])) and (pull_map (piston -> blocks))
	
	TODO: Handle cases where one piston may affect a SUBSET of blocks from another piston.
	For each piston in (retracting_pistons):
		If it's sticky, or half sticky and ready to pull:

			Find blocks that are attached to the piston head:
				Create an array (blocks)
				Create a variable (key_block)
				While searching for blocks:
					If it's discovered that these blocks can't be moved in the piston's direction:
						Clear (blocks) and reset (key_block)
						Break out of the block search
					
					Add the block to (blocks)
					If it's a key in (islands):
						Set (key_block) to this block
			
			If (blocks) is not empty:
				If (key_block) does not exist:
					Set (islands)[first (blocks) element] to [(blocks), [the piston]]
				Otherwise:
					Get (islands)[(key_block)]'s pistons array, and add the piston to it
	
	For each blocks array and pistons array in (islands):
		If only one piston is in the pistons array:
			Set (pull_map)[piston] to the blocks array
		Otherwise:
			Create a variable (max_power)
			Create a map (powers (piston -> number))
			Create a copy of the pistons array called (actives)
			
			While going backwards through (actives):
				Get a piston in the array and call it (pistonA)
				Set powers[pistonA] to 1
				While going backways through (active), but starting from behind (pistonA):
					Get a piston in the array and call it (pistonB)
					If (pistonA) and (pistonB) are facing the same direction:
						Increment (powers)[(pistonA)]
						Remove (pistonB) from the actives
						Set (max_power) to the maximum between itself and (powers)[(pistonA)]
			
			For each piston in (actives):
				If the power from (powers)[the piston] is equal to (max_power):
					If (pull_map)[the piston] already exists:
						Remove the piston from (pull_map)
						Break out of the loop
					Otherwise:
						Set (pull_map)[the piston] to the blocks array
	
	For each piston in (retracting_pistons):
		If (pull_map) contains the piston:
			Associate the blocks in (pull_map)[the piston] with the piston
		Set the piston to retract

	TODO: Write details
	Attempt to extend pistons that are not extended but activated

	Process active piston movements
	Finalize pistons that have finished moving
@jrcarl624
Copy link

Wouldn’t this lead to more unnecessary lag, putting all of the pistons in a world on a larger server would seem to cause some issues.

@SIsilicon
Copy link
Author

SIsilicon commented Jul 10, 2022

Wouldn’t this lead to more unnecessary lag, putting all of the pistons in a world on a larger server would seem to cause some issues.

That would a require a lot of pistons firing in the same ticks for that to happen. The most that could happen is a spike, but in theory the lag should be similar to how it already is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment