2

I'm working on building a custom adventure map (for both Java and Bedrock.) I want this to be easily localized. I understand how resource packs work and the oddities of language files for both Bedrock and Java.

On Bedrock edition, I have a simple behavior pack that runs the following code:

import {world} from "@minecraft/server"
import { ModalFormData } from "@minecraft/server-ui"

world.afterEvents.itemUseOn.subscribe(({block, source:player, itemStack:item}) => {
    if (item.typeId != "minecraft:brush") return
    if (!player.isSneaking) return
    if (!block.getComponent("sign")) return
    const form = new ModalFormData()
    .title("Set Sign Text")
    .textField('Translation Key: ', "")
    .show(player).then(({formValues, canceled}) => {
        if (canceled) return
        const key = formValues[0]
        block.getComponent("sign").setText({translate: key})
    })
})

This allows me to brush a sign while crouching in order to type the translation key on the sign in the game.

My question is how would I do something like this in Java. I'm guessing that it would be a data pack that I would build, but I am unsure how to get the sort of functionality of use-this-tool on-this-block while-crouching to run-this-function/command on-the-targeted-object.

I imagine this sort of thing would be simple to do, but all the tutorials I've found only focus on changing game mechanics (like overriding loot tables or recipes).

Is this something that's possible and/or is there a data pack/mod/add-on that allows for easy, in game access to write translation keys for things like signs and books?

Thank you in advance for your help.

2
  • If I understood the task, you want a "command-less" way to encode a translate JSON text into a sign? For example, I would write on a sign arqade.key, brush it, and then it would get the appropriate translate JSON as the text of the sign? If not, are you looking for a way in-game to register a value for a given translate key for a language? Commented Sep 11 at 15:02
  • Correct. The first option would be perfect. I write arqade.key on the sign, brush it, and it would change the text to the translatable/translate tag. (I already would have the appropriate language JSON files set up in my resource pack in an earlier step of my process.) Commented Sep 11 at 15:45

1 Answer 1

5

1.21.6+

To get the complete functionality you want, we need to resolve two tasks:

  1. run a function in a particular position when a brush... brushes it.
  2. taking text and injecting it into a translate JSON text component in a command

Both of these are solvable in multiple ways in Java edition. Below, I am writing one approach to each task.

I will be using the namespace arqade, so you can expect a file structure as follows:

encoder_datapack
- pack.png
- pack.mcmeta
- data
  + arqade
    > advancement
      ...
    > dialog
      ...
    > function
      ...

1. Using a custom advancement to detect brushing

Advancements run in the background and detect when players do something. They are Minecraft Java's version of subscribers. Incidentally, the name of the trigger is very similar to the event name you used: item_used_on_block. In the advancement folder, the following advancement will detect when brushing is used on a sign:

brush_sign.json:

{
    "criteria": {
        "brush_block": {
            "trigger": "item_used_on_block",
            "conditions": {
                "location": [
                    {
                        "condition": "match_tool",
                        "predicate": {
                            "items": "brush"
                        }
                    },
                    {
                        "condition": "location_check",
                        "predicate": {
                            "block": {
                                "blocks": "#all_signs"
                            }
                        }
                    },
                    {
                        "condition": "entity_properties",
                        "entity": "this",
                        "predicate": {
                            "flags": {
                                "is_sneaking": true
                            }
                        }
                    }
                ]
            }
        }
    },
    "rewards": {
        "function": "arqade:on_brush_sign"
    }
}

The first condition in location checks if the player is using a brush. The second condition checks if the player is using the item on any sign. The third condition checks if the player is sneaking.

Finally, if this is satisfied, the advancement is silently granted (default behavior) and runs the function arqade:on_brush_sign which is a custom function we will define.

In the function folder, we will add the following function definition:

on_brush_sign.mcfunction:

# revoke advancement so it can be triggered again. It is a good idea to show this first
advancement revoke @s only arqade:brush_sign
dialog show @s arqade:get_translate

This is a very basic function that allows the player to trigger the advancement again, and opens a dialog box, where you will input the translation key. I toyed around with a bunch of places from which to take the input text, like directly from the sign or from renaming the brush or another item. Out of all of them, this seems the most reliable and extensible.

The dialog definition is defined in a different file, placed in the dialog folder.

get_translate.json:

{
    "type": "confirmation",
    "title": "Set sign text",
    "inputs": [{
        "type": "text",
        "key": "translate_key",
        "label": "Translation key: "
    }],
    "yes": {
        "label": {"translate": "gui.ok"},
        "action": {
            "type": "dynamic/run_command",
            "template": "function arqade:on_dialog_success {translate_key:\"$(translate_key)\"}"
        }
    },
    "no": {
        "label": {"translate": "gui.cancel"}
    }
}

This defines the text field with the labels you showed in your behavior pack. I had to add a cancel button to ensure ESC will also cancel the operation and not lock you in.

2. Running a function to modify sign data with the translation key as a macro argument

If you press OK in this dialog, a command with the translation key will be sent, which will carry over this data to the sign. This function runs as the player who ran the command, and at his position. Therefore, the function on_dialog_success needs to find the position of the sign.

on_dialog_success.mcfunction:

# run the function "arqade:encode_translate" as the brushing player at the location of the sign.
# Use a brute force search on the player's right-clicking range in 0.5 block spacing.
$execute anchored eyes positioned ^ ^ ^ if block ~ ~ ~ #minecraft:all_signs run function arqade:encode_translate {translate_key:$(translate_key)}
$execute anchored eyes positioned ^ ^ ^.5 if block ~ ~ ~ #minecraft:all_signs run function arqade:encode_translate {translate_key:$(translate_key)}
$execute anchored eyes positioned ^ ^ ^1 if block ~ ~ ~ #minecraft:all_signs run function arqade:encode_translate {translate_key:$(translate_key)}
$execute anchored eyes positioned ^ ^ ^1.5 if block ~ ~ ~ #minecraft:all_signs run function arqade:encode_translate {translate_key:$(translate_key)}
$execute anchored eyes positioned ^ ^ ^2 if block ~ ~ ~ #minecraft:all_signs run function arqade:encode_translate {translate_key:$(translate_key)}
$execute anchored eyes positioned ^ ^ ^2.5 if block ~ ~ ~ #minecraft:all_signs run function arqade:encode_translate {translate_key:$(translate_key)}
$execute anchored eyes positioned ^ ^ ^3 if block ~ ~ ~ #minecraft:all_signs run function arqade:encode_translate {translate_key:$(translate_key)}
$execute anchored eyes positioned ^ ^ ^3.5 if block ~ ~ ~ #minecraft:all_signs run function arqade:encode_translate {translate_key:$(translate_key)}
$execute anchored eyes positioned ^ ^ ^4 if block ~ ~ ~ #minecraft:all_signs run function arqade:encode_translate {translate_key:$(translate_key)}
$execute anchored eyes positioned ^ ^ ^4.5 if block ~ ~ ~ #minecraft:all_signs run function arqade:encode_translate {translate_key:$(translate_key)}
$execute anchored eyes positioned ^ ^ ^5 if block ~ ~ ~ #minecraft:all_signs run function arqade:encode_translate {translate_key:$(translate_key)}

This can be done more elegantly with some recursion, but the limited interaction range of the player allows us to brute force the same command a few times.

Finally, after the translation key was carried for a few commands, we can finally use the macro argument from the dialog in a data command:

encode_translate.mcfunction:

$data modify block ~ ~ ~ front_text.messages[0] set value {translate:"$(translate_key)"}

This datapack implementation is very extensible. You can add additional arguments in the dialog to include translation keys for the other rows, add substitution arguments to the with JSON component, more stuff for the back of the sign, etc.

Important note on dialogs in datapacks: using /reload is not enough to update a dialog, you need to exit and rejoin the world.

5
  • Just finished trying this out. This is AWESOME!!! Thank you. I made a couple of tweaks to this since it would only update the first line of a sign (no big deal), but was wondering if there was a way of doing loops, and/or if there was a way of adding if/then logic (i.e. if translate_key length >1, then update, else do nothing). Commented Sep 12 at 13:04
  • 1
    in minecraft commands, you don't have if/else, but you do have if clauses using execute if and execute unless link. You also don't have explicit while/for loops, but you can do "loops" via recursion - you can use function to run the same file the command calls (i.e you have function foo:bar in file bar.mcfunction) link Commented Sep 12 at 14:22
  • If you have a moment, could you add a comment or edit your answer with an example of an if/unless example that uses a variable $(translate_key). For some reason I am not understanding how this works and MC does not like my argument/syntax. Commented Sep 13 at 15:21
  • It might be worth asking this as a separate question since that way there is no character limit for the answer, plus more people might find the question/answer useful Commented Sep 13 at 16:57
  • New question asked. Thank you for your help: gaming.stackexchange.com/questions/413399/… Commented Sep 13 at 17:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.