Skip to content

Translation notice

This page was translated with machine translation and may contain inaccuracies. If you can help improve it, please open an issue or submit a pull request.

"Big Villa" and dialog chat

Dahesor

Dahesor

Abstract

This article records and discusses the difficulties, interesting stories, and their final solutions that several authors encountered when researching the new versiondialog and making the "Big Villa" data pack.

Content

  1. Transfer information to remote entities
  2. Handle the problem of forced loading
  3. We need a self-destruct mark
  4. Read the SNBT input by the player
  5. Process the user's multi-line text input

What is dialog, what is "Big Villa"

**dialog is **Java The new data pack component in 1.21.6 can present a simple dialog window to the user to display notifications or receive user input.
See Wiki for details: dialog

"Big Villa" (DaBsu, Dialog Batch Spawner Utils) was made by me last month. It allows map authors to conveniently and visually edit and manage a large number of monster spawners' data packs, using a large number of dialogs.
This article is not entirely about dialog, but also includes discussions on some other issues.
To learn about "The Big Villa" or use it, please watch the demonstration video:The Big Villa

Transmit information to distant entities

In the big villa, users can choose any number of monster spawners to edit together, including unloaded chunks or monster spawners in other dimensions.
Each registered monster spawner will store its own information—such as location, type, dimension, etc.—in storageDimensionDown. When a monster spawner is selected, this information will be copied toSelectedmiddle. In other words, the selection of a monster spawner is completely recorded by storage, so how do we notify the marked entity in the unloaded chunk that it has been selected?

You may find that we don't need to notify them that they are selected at all. However, "Grand Villa" will cause the selected monster spawner to blink - that is, a glowing display entity will be generated every two seconds that lasts for one second - so each monster spawner's marker entity must know whether it is selected.

Obviously, it is impossible for us toforceloadAll monster spawners and modify their data. Then we more or less have only two ways:

First, we can use storage. Each marked entity in the loading chunk can find out whether it exists inSelectedIn the multi-level list, if it is, it proves that you have been selected. This eliminates the need to do extra work when selecting - after all, only monster spawners in loaded chunks may be highlighted.
However, it is obviously unwise to waste this energy and computing power on the function of flashing the selected monster spawner - we need to make a judgment at least every two seconds, and a larger CTM map has at least thousands of monster spawners, and there may be hundreds of monster spawners loaded at the same time. It is somewhat inelegant to determine whether you exist in a multi-layered list that may contain thousands of items.

In this case, there is only the second method, which is to modify the score of the marked entity on the scoreboard. In this way, the entity only needs to do oneif score @s selected matches ...You can check to see if you are selected.
Some people may have doubts. Since entities are in unloaded chunks, how do we modify their scores?
In fact, the scoreboard and entity are not bound at all. we often mention假玩家, that is, there is no scoring target corresponding to an entity on the scoreboard. However, it is somewhat inaccurate to say this, because in fact all scoring goals on the scoreboard are假玩家.

When we use the target selector in the scoreboard command, if the target is a player, the playerID will be used as the name of the scoring target, and if the target is other entities, their UUID will be used. As long as you know the playerID or entity's hexadecimal hyphenated UUID, you can update their scores even if the entity cannot be found (offline, or not loaded). Therefore, it is only necessary to record and calculate the hyphenated UUIDs of entities when they are created, and then even if they are unloaded, their scores can be updated directly using the UUID + macro.

  • Currently, the stable way to obtain the hexadecimal UUID string of any entity is to take the array UUID and then calculate the hexadecimal format. There are ready-made libraries, such as gu to help you do this. *

Handle the problem of forced loading

After forgetting which version,/forceloadThe command can no longer be completed within the context. This means that operations on that chunk immediately after /forceload will almost never succeed.
Actually, now version/forceloadThe time required for complete completion is uncertain. even inforceloadAfter a delay of 3 ticks, there is a high probability that the chunk is not fully loaded and the entity cannot be selected.

So how to stably edit blocks and entities in unloaded chunks? Fortunately,execute if loadedCommand can determine whether the chunk to which any coordinate belongs is fully loaded. So in the current version, what you need to do is execute/forceloadJudge once every momentexecute if loadeduntil passed.

We need self-destructing markers

One of the features of "Big Villa" is visual quick editing in the world. After selecting a monster spawner, the user can see various data drawn using the display entity, such as the generation range.
Users can choose to drag the display entity directly to modify its corresponding data.

When modifying the generation range, the user can change this value to a large value, such as 96. This means that the far end of the display entity is 96 blocks away from the monster spawner, and almost 200 blocks away from the other end - which is entirely possible beyond the loading distance of the game.
So if the user swipes and drags the range to 96, and the simulation distance is very small, it's all over, and the entity is lost.
In the future, the player may see the display entity suspended in the air.

Take a closer look at what we need to implement:

Screenshot of quick editing of the big villa

shows that entities are divided into two categories. One is blue, a dotted line used to show the range. These entities do not actually need to change position when the scope changes, they just need to be adjustedtranslationThat’s it. Therefore, they are actually always located in the monster spawner, so they are not afraid of being lost.

What I am really afraid of losing is the second category, which is the four small green cubes in the picture. The user can drag them to change the size of the entire range. They must be selected where they are displayed because the player's line of sight needs to be detected. Once the range is too large they may be dropped.

Of course, we can also use these small green cubestranslationAdjust the position, and then use marker entities to detect player sight instead of where they appear visually...but these marker entities may still be lost.

So is there an entity that is not afraid of losing? Is there anything that will self-destruct if there is no data pack update? Yes, please Regional Effect Cloud.

Regional effect cloud hasDurationandAgetag controls its survival time. So we only need to use the area effect cloud for line of sight detection.
All normally loaded regional effect clouds will be updated by the data pack at all timesAgeThe tag ensures that it does not expire, and the timestamp is always updated to prove that it has been loaded. However, once it is in an unloaded area, its timestamp will no longer be equal to the current one when it is loaded again.gametime, data pack can determine and delete it. If the data pack is unloaded before it is loaded again, it will expire within a few seconds and disappear naturally.

reads the SNBT input by the player

1.21.6-pre2, all string inputs to the dialog will be escaped for special characters. This means we can no longer directly usedynamic/run_commandCompound tags are accepted directly. For example:

mcfunction
#dynamic/run_command
data merge storage foo:bar $(input)

Before pre-2, as long as the user entered a legal compound tag in the text box, no matter what it was,dataThe commands can be assembled and run correctly.
However, after this, all single and double quotes and backslashes will be escaped with a backslash (' " \\' \" \\), and newlines will be converted to\n.
This prevents us from accepting compound tags directly, because it is assumed that the user input is{string:"yes"}, then the command will become:

mcfunction
data merge storage foo:bar {string:\"yes\"}

And this is illegal.

We can only store the entire compound tag into a string first:

mcfunction
#dynamic/run_command
data modify storage foo:bar input set value {input:"$(input)"}

will become:

mcfunction
data modify storage foo:bar input set value {input:"{string:\"yes\"}"}

and then run the macro again:

mcfunction
function string_to_object with storage foo:bar input

#> function string_to_object
$data modify storage foo:bar input set value $(input)

can convert the input into a composite tag.

At this time you may have questions, what if the player enters single and double quotation marks at the same time? For example, the input is{string:"haha'hehehe"} At this time, the combined command will become:

mcfunction
data modify storage foo:bar input set value {input:"{string:\"haha\'hehehe\"}"}

What should I do? There are no single quotes outside but the single quotes inside are escaped.
——Not much. This is legal in Minecraft. As long as there are quotation marks on the outside, the internal quotation marks can be escaped regardless of whether they are single or double. It's just that the same one must be escaped, and the different one is free.
The following four commands are equivalent:

mcfunction
data merge storage foo:bar {string:"单' \"双"}
data merge storage foo:bar {string:"单\' \"双"}
data merge storage foo:bar {string:'单\' "双'}
data merge storage foo:bar {string:'单\' \"双'}

handles multi-line text input from users

pre-2 also causes more trouble than the above. A bug has appeared since this version, MC-298893. Simply put, the text input of dialog allows multiple lines, andmax_linesThis parameter specifies the maximum number of lines.

Theoretically, it stipulates how many line breaks the user can enter, that is, how many times they can press Enter - this was true before pre-2 - but after this version, it suddenly became a visual limit to how many lines there are.
That is, if we specifymax_linesIf it is 1, then the user can no longer enter any string that cannot fit in the width of the text box. If there was no such vulnerability, the text should automatically move to the next line on the display.

What does this mean? "Big Villa" allows users to edit the NBT data of the monster spawner directly in the dialog. If there is this BUG, ​​then either we want to accept SNBT tag input of any length, we mustmax_linesThe adjustment is very large, which means that the string entered by the user may be randomly filled in.\n, and this is disastrous.

So can Mojang fix this vulnerability? Of course not. The vulnerability I reported was successfully won't fixed (acknowledged its existence but did not fix it.)

won't fix emoticon package

Now I have to find a way by myself. We need to put all the characters in the string entered by the user\nRemove. This requires us to split the string into characters one by one, judge it again and then put it back together.
Splitting a string is very simple, there aredata string, so how to combine strings?

Using macros to directly splice sounds very simple, and String Lib does it directly. However, we are dealing with an SNBT string. This means that there is a high probability that there will be various characters that need to be escaped, such as single and double quotes and backslashes. Using macros to splice directly in this way will almost certainly lead to errors.

After much deliberation, we can do this:

First, scan the string character by character from beginning to end, discarding all\n, and separate all characters that need to be escaped,'and\. Split the string into a list like this:

  • {st\nring:"yes'ha\nha''grat"}
  • ["{string:"yes","'","haha","'","","'","grat"}"]

In this way, we can calculate how many macros each string needs to go through if we want to put such a list together several by one. We can also calculate how many backslashes need to be added before each character that needs to be escaped:

mcfunction
#> function dnt:private/concat/get_slash/loop

$data modify storage dnt:ram concat.escape set value "$(escape)$(escape)$(escape)$(escape)\\"
scoreboard players remove $slash_count calc.dnt 1
execute if score $slash_count calc.dnt matches 1.. run function dnt:private/concat/get_slash/loop with storage dnt:ram concat

above$slash_countRepresents the number of times that needs to be escaped.

so that we can$(escape)is added before each character that needs to be escaped, and finally the input is obtained through macro splicing and all the characters are removed.\nversion:

  • {string:"yes'haha''grat"}

The same system can also be used to concatenate arbitrary strings. I organized this system into the DNT (Dahesor NBT Transformer) library, which was separated from "Big Villa" for use by other people with similar needs:

  • Github
  • Redstone Relay "Big Villa" also has a function that can convert the NBT configuration data of the trial monster spawner into an equivalent JSON structured string, which is also implemented by the DNT library.

Summary

These are some of the most interesting problems I encountered while making "La Grande". There may be other troubles, but they have been forgotten. Solving them is also really the most fun part of the production.

Powered by VitePress and GitHub Pages