Sign Colours Don't Appear Consistently In ChangeSignEvent

Hi everyone the current issue that I am having is that when I try to add colours to a sign’s text in the ChangeSignEvent, the colours don’t always appear. This problem does not occur at any other times, I can set a signs colour perfectly fine any time after the initial creation of a sign(after the ChangeSignEvent occurs).

Here’s what I’ve tried:

  • Offering Keys.SIGN_LINES to the TileEntity. This doesn’t even update to the desired text at all.

  • Using .set(Keys.SIGN_LINES) to the future SignData and then offering that to the TileEntity. This updates the text on the sign but still only shows the colours very infrequently, the colours usually only get shown after creating a sign within the first server restart. After that, they don’t tend to appear.

  • Manually changing the Text elements in the SignData.lines(). This method updates the text but also doesn’t show colours consistently.

I don’t know if I’m doing something wrong or if this is a sponge bug but If someone could help me find a solution that would be awesome. Here’s a basic example of what I’m trying to do, for anyone that didn’t understand what I was trying to accomplish.

@Listener
public void onChangeSignText(ChangeSignEvent event, @First Player ply){
    SignData signD = event.getText();
    Sign sign = event.getTargetTile();

    sign.offer(Keys.SIGN_LINES, Arrays.asList(Text.of(TextColors.DARK_BLUE, "Test"))); //Something like this
    // or
    signD.set(Keys.SIGN_LINES, Arrays.asList(Text.of(TextColors.DARK_BLUE, "Test")));
    sign.offer(signD);
    //Neither of these work consistently for me but I think they should...
     
}

My sponge version is: spongeapi-7.0.0, and my spongeforge version is: spongeforge-1.12.2-2705-7.1.0-BETA-3206. Also, there are no errors that get displayed during run-time. If any more information is needed, let me know. Thank you for your time!

1 Like

Most events run before their actions actually take effect. You’ll need to change the sign lines through the event itself.

If you don’t mind me asking, how exactly would I go about that? In the second example I tried offering the future SignData a List of texts but that still didn’t work, and isn’t that changing the sign lines through the event?

What code did you use for that?

signD.set(Keys.SIGN_LINES, Arrays.asList(Text.of(TextColors.DARK_BLUE, "Test"), Text.EMPTY, Text.EMPTY, Text.EMPTY));
sign.offer(signD);

This code, isn’t that directly changing the SignData that will be assigned to the sign? When I use this the colours on the sign in-game only show usually on the first server restart. Proceeding to create a sign after the first restart almost never results in colours being put on the sign.

EDIT : The first server restart colour change is probably just luck also, but so far this has been the case for me.

Where is signD & sign coming from?

Sorry for the confusion, I was using the variables from the code I posted in the OP.

The full code would look like this

@Listener
public void onChangeSignText(ChangeSignEvent event, @First Player ply){
    SignData signD = event.getText();
    Sign sign = event.getTargetTile();

    signD.set(Keys.SIGN_LINES, Arrays.asList(Text.of(TextColors.DARK_BLUE, "Test"), Text.EMPTY, Text.EMPTY, Text.EMPTY));
    sign.offer(signD);
}

Do you know if this problem is a bug, or am I doing something wrong?

You shouldn’t need to offer it back to the tile entity. Modiying the mutable data in the event should be modifying the end result already.

It’s my assumption something is wrong with the SignD.set() call.

What happens if you just mutate the ListValue returned from signD.getLines in place?

Other then that I’m not sure, and would recommend filing a ticket.

This is how I picture the flow to work for most Sponge events.
image

You may be asking, “What happens to changes to the entity directly?”

That’s implementation specific unfortunately.

If you are modifying the value that the event specifically targets, it will most likely be overwritten once the event is over.

But different events do different things depending on performance / where in the code it’s hooked.

e.g. with a Sign, the entire tile entity might be snapshotted. OR it might only be the sign lines that is snapshotted.

You can only really tell via experimentation what a given implementation might do, for a specific entity, for a specific event. This is one area where Sponge could be a little more consistent, but it would likely come at a lack of flexibility / performance.

Edit:

Noticed a possible error? It might be like this:

image

1 Like

Absolutely nothing, because Values are not live data. A Value must be offered back to a manipulator before anything happens.

2 Likes

Which would happen after the event resolves? Which is why the event exposes the data?

No. When you get a Value from a DataManipulator, you receive a copy of the data. The event exposes the DataManipulator so it can be updated, but updating the Value will not update the DataManipulator.

1 Like