simon816 / Command-Block-Assembly

Compile high-level code into Minecraft commands
https://www.simon816.com/minecraft/assembler
MIT License
272 stars 29 forks source link

how do you run the tetris example #18

Closed godmar closed 4 years ago

godmar commented 4 years ago

This is a newbie question. I've created a superflat 1.14.4 world and loaded the tetris datapack in it.

I used this .dpd file:

[Datapack]
namespace=tetris
place location=300 4 300
description = Tetris
generate cleanup=true

then built with python mcc.py examples/tetris.cbl examples/tetris.dpd.

When I tp to 300 4 300 and run /reload I see 3 command blocks placed, which makes me think the datapack was loaded. When I run /function tetris:main it says: 6127 commands executed, but nothing in the world appears to have changed.

May I ask how to make this example do whatever it is supposed to be doing?

CorneliaXaos commented 4 years ago

The tetris example is looking for a lever and some buttons in some very particular coordinates:

(206, 57, -9) : a lever : controls if the game is running or not (204, 57, -9) : a stone button : moves the current tetrimino to the left (206, 57, -11) : a stone button : rotates the current tetrimino (208, 57, -9) : a stone button : moves the current tetrimino to the right

godmar commented 4 years ago

Thank you! I think I posted too fast. I just noticed the same. That said, when I placed those buttons, then run tetris:main, I see a rectangle of black wool and a single tile before it says: ...executed this many commands. When I push any of the buttons, the tile doesn't move.

godmar commented 4 years ago

It looks like this image

CorneliaXaos commented 4 years ago

You need to up the maxCommandChainLength:

/gameRule maxCommandChainLength 99999999

That should be more than enough.

CorneliaXaos commented 4 years ago

It would be nice if CBL would determine how many commands it needs to run in one swoop and set that value for you, potentially verifying that it never lowers the maxCommandChainLength.

godmar commented 4 years ago

This (changing maxCommandChainLength) doesn't appear to make a difference. The function still completes after 9027 commands, placing the tile only. Also note on the picture that there's some black wool on the ground. What should happen? Should the function just keep running in some way? In other words, the number of commands completed not be printed?

CorneliaXaos commented 4 years ago

The only other thing I can say is to make sure you have the gamerule for command blocks enabled and that the command blocks are in loaded chunks. If those don't solve the problem, I'm not familiar with what is wrong; I only know that, so far, you've run into issues that I hit when I compiled and ran the tetris c file.

godmar commented 4 years ago

Which command blocks? I've been running the tetris:main function from the command line once. If I place the function in a repeating command block and activate it, I see an armor stand placing new tiles, but they don't move. The black wool comes down encroaching. I think this example could use a map to reproduce it.

simon816 commented 4 years ago

heh, I never really explained or documented the tetris example (I made it just as a demonstration really, not as a playable game). It was made on a world with the "redstone ready" preset, which has a ground level of 56, hence the strange y-position (and the x/z is probably near where the spawn point for this world was). Here's the gif I made: https://i.imgur.com/JdZXi02.gifv

The lever at (206, 57, -9) should be powered, you should see redstone dust particles emitting from it. The buttons should be face-up.

I probably should add some code to spawn these buttons as it wouldn't be hard to do.

If it starts rendering black wool outside the 10x20 display (happened to me when testing once), kill all armor stands and reload the datapack.

godmar commented 4 years ago

Thank you. I still can't get it working. I'm using 1.14.4 with the redstone preset and arranged it as shown on the video. What do you have in the command block under the lever? I tried adding the function tetris:main call there with an Impulse, Unconditional, Needs Redstone command block.

I'm very very intrigued by CBL, but I am inexperienced when it comes to MC's execution model. Is it like JavaScript where you can do chunks of work, then must schedule time for the main event loop to run, and then schedule the execution of continuations in the future ("next tick?")

If so, how/when exactly should the tetris:main function be run - would it be "running" while the game is played, or is it run repeatedly, multiple times?

simon816 commented 4 years ago

What do you have in the command block under the lever?

I think it was just to invoke function tetris:main. It's not needed, you can call /function tetris:main from the chat once the lever is activated.

I just tested in-game, turns out the problem is with the place location. I haven't investigated the root cause, it's likely that the chunks for that position aren't loaded. In my testing, I use position 0 56 0, try that instead.

I am inexperienced when it comes to MC's execution model

You're correct in that it's like JavaScript. The game has a main loop, each iteration is a "tick" in which everything updates. There's a brief explanation on the Minecraft Wiki: https://minecraft.gamepedia.com/Tick I don't remember the exact ordering (you can decompile the game to find out exactly how it works), but it's something like this:

while true:
    for each world:
        for each entity in world:
            update entity
        for each block entity in world:
           update block entity
    for each function tagged "minecraft:tick":
         run function
    (etc)

The amount of commands you can run in a single tick is bound by the value in the maxCommandChainLength gamerule (https://minecraft.gamepedia.com/Commands/gamerule). The compiler doesn't change this value from the default (I may do this in the future), I'll normally set it to something large to avoid issues.

The game runs smoothly at 20 ticks per second (TPS), so each tick is 50ms. If you run too many commands in a single tick it'll take over 50ms and the game slows down (relative to wallclock time).

I offer await Game.tick(); as a way to yield to the rest of the game tick. In the tetris example, I call this 5 times (so the tetris game updates every 5 minecraft ticks) https://github.com/simon816/Command-Block-Assembly/blob/63d1a2bb8bc6452faf4c2981046e0e3feef4ed24/examples/tetris.cbl#L361-L365

Conceptually, the main() function is running the entire time the tetris game is playing - this is how it looks in the code. In reality, the generated function tetris:main only runs until the first Game.tick() at which point it finishes. Just before finishing, it sets a command block (initially spawned when the datapack loads) to execute another function on the next tick (we could call this function tetris:main_continued). The game loop will execute this continuation on the next tick.

One of the benefits of CBL is to hide this detail behind async/await just like you'd do in JavaScript, though there isn't the concept of a Promise so it's limited to just yielding to the game tick at the moment.

godmar commented 4 years ago

Thank you! With changing the place_loc to 0 56 0 I get the game going. It's too fast to play though, but at least it works. This is very interesting.

I'll check your project out more!