mcpq / mcpq-python

Python library for communicating with and controlling Minecraft servers via MCPQ plugin
https://mcpq.github.io/mcpq-python/
Other
3 stars 1 forks source link

How to place and write text on signs using mcpq, similar to mcpi's mc.setSign()? #2

Open javier-cantu opened 3 weeks ago

javier-cantu commented 3 weeks ago

I have successfully managed to place blocks and get a list of available blocks. However, I'm struggling with placing signs and writing text on them. In mcpi, there was a method mc.setSign() that allowed us to do this easily.

Is there an equivalent way to place a sign and add text to it using mcpq? Any guidance or examples would be greatly appreciated. Thanks in advance!

icezyclon commented 2 weeks ago

Hi there :wave:

The function setSign is not natively supported at the moment, as this would involve setting block nbt data, which is on the todo list for the features of the next version of the protocol!

At the moment I would recommend to set the nbt data with a /-command explicitly, like this:

from mcpq import Minecraft, Vec3, NBT
mc = ...
pos = ...

def write_on_sign(
    world, pos: Vec3, messages: list[str], glowing: bool = False, color: str = "black"
):
    assert (
        len(messages) == 4
    ), "Must provide exactly 4 lines for sign (use empty string for empty line)"
    pos = pos.floor()
    nbt = NBT()
    front = nbt.get_or_create_nbt("front_text")
    front["has_glowing_text"] = 1 if glowing else 0
    front["color"] = color
    front_msg = front.get_or_create_list("messages")
    for msg in messages:
        front_msg.append(f'{{"text": "{msg}"}}')
    # you could also do the same for "back_text"
    world.runCommand(f"data merge block {pos.x} {pos.y} {pos.z} {nbt}")

mc.setBlock("acacia_sign", pos)
write_on_sign(mc, pos, ["Line 1", "Line 2", "", "Line 4"], glowing=True, color="green")

The function requires that there is already a sign at pos and will merge the nbt data onto it. It uses the NBT class as a helper, the class is currently undocumented as I am still thinking about a better of using nbt data and Minecraft is switching a lot of nbt data to components from version 1.20.5+, which I still have not looked into.

Please note, this code works and was tested for version 1.20.1! Signs have changed quite a bit over time, for example, prior to 1.20 signs did only support one side for writing and require a different format for writing it!

PS: You can read the nbt data of a block with the in-game command /data get block <x> <y> <z>, which allows you to then construct the nbt in a way you want, or you can use a tool like mcstacker (or minecraft tools for older signs prior to 1.20)

javier-cantu commented 2 weeks ago

Thank you very much, I will give it a try!