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.

Cover

Dialog multi-input control design based on bitwise operations and multi-base encoding

Xu Muxian

Xu Muxian

summary

The operation and submission behavior of the dialog are always restricted by the player's permission level. For this reason, command must be used in the click event./trigger, but a scoreboardcommand can only submit one score at a time, which is a limitation for dialogs with multiple input controls. This article uses bitwise operations and multi-digit encoding on the dialog input control, and applies it to the actual developed data pack.

Editor's Note

Use a command/trigger settings set $(input1)$(input2)$(input3)Resolved submission of multiple input controls.

introduction

Permission levels are a set of mechanisms in the game that stipulate what commands a player can use. On the one hand, it can effectively prevent players from committing acts beyond their authority in the game; on the other hand, it will hinder the development of data pack to a certain extent. When developers write commands, they sometimes need to consider whether the execution context meets the permission level requirements and then select the corresponding command. In the command system, most commands require permission level 2, and these commands constitute the main content of data pack development. However, in some cases, developers want to turn off commands for the player, that is, set the player's permission level to 0. This can prevent the player from arbitrarily executing commands and causing certain damage to the data pack or map. If the command is executed in a function, the permission level of the function is usually 2, which can meet the needs of most command executions. If it involves the operation of player submission of content, it needs to be carefully considered. with text componentclick_eventFor example, when the player clicks on the text to execute the command, the text component fragment required is:

snbt
{
  click_event:{
    action:"run_command",
    command:"<命令>"
  }
}

When the player executes a click event in the chat bar, the executor is the player, the execution location is the location of the player, and the execution permission level is the permission level of the player. If the player's permission level is 0, then&lt;命令>A lieutenant general cannot use any command with a permission level greater than 0. The solution is to use command instead/trigger, which requires developers to establish a criterion fortriggerThe score item, and monitor the score changes in the score item at high frequency, thereby establishing the connection between the scoreboard score and the actual required command.

Java 1.21.6 adds a dialog registry to the data pack. Dialog also provides a way for interaction between player, command, and game data, such as in static operations.run_command

json
{
  "action": {
    "command": "<命令>",
    "type": "minecraft:run_command"
  }
}

There are also dynamic operationsdynamic/run_command

json
{
  "action": {
    "template": "<带参数的命令>",
    "type": "minecraft:dynamic/run_command"
  }
}

The permission levels of these contexts are determined by the player that triggers the click event. Therefore, when the player permission level is 0, it also needs to be used in these fragments./trigger. Now review command/triggerSyntax:

mcfunction
trigger <objective>
trigger <objective> add <value>
trigger <objective> set <value>

Executing click events in the chat bar is relatively simple, because the player only needs to submit one piece of data each time, so a/triggercan fully cope with it. For dialog, there is more than one input control, and each input control will generate corresponding data to be submitted. When the operation button is used, these data will be submitted together at the same time, and/triggerOnly one score can be submitted for one scoring item at a time&lt;value&gt;. Because of this problem, it is unrealistic to reduce the input controls on a page to 1.

One solution is to put part of the submission data in the score parameter. exist/triggerIn the syntax of&lt;value&gt;Can accommodate one submission data,&lt;objective&gt;Can also accommodate submission data such as:

json
{
  "action": {
    "template": "trigger tri$(input1) set $(input2)",
    "type": "minecraft:dynamic/run_command"
  }
}

of which$(input1)and$(input2)They are all template parameters, or the corresponding keys of the input control. They can accommodate the actual values ​​from the corresponding keys of the input control. here$(input2)The scoring item score is passed in, and$(input1)The score item name is passed in, which requires traversing$(input1)All possible values, establishing all possible scoring items. when$(input1)When the possible value is not much, this method is not too inefficient. if$(input1)There are many available values, and even if there are more than 2 input control keys and there are many combinations, this method seems a bit cumbersome. Therefore, there is an urgent need for a method that can effectively accommodate multiple input values. To this end, this study proposes a bitwise operation method, which only uses/triggerscore&lt;value&gt;All submission data of one page of dialog can be transferred.

Project case

This research was initially conducted on the AMR Botdata pack, a project developed by CR_019, Alumopper, and others. Since the method described in this article is effective on AMR Bot, it was applied to the production of the parkour map "Leap of Crystal Realm II". Unless otherwise stated, all examples in this article are based on the data pack used in this map development process. This map is not yet complete at the time of writing, so content may differ from actual content after release.

There is a "Settings" dialog in this map, which allows the player to adjust the sound effects, particles, and cutscene options in the map. This dialog type ismulti_action. Each option issingle_optionType input controls, each control has two available values: "on" and "off". input controlinputsThe values ​​of the fields are as follows:

json
"inputs": [
  {
    "label": {
      "bold": true,
      "color": "black",
      "shadow_color": 0,
      "translate": "dialog.leap_of_crystal_realm.settings.sounds"
    },
    "key": "sounds",
    "options": [
      {
        "display": {
          "bold": true,
          "color": "dark_green",
          "shadow_color": 0,
          "translate": "options.on"
        },
        "id": "1"
      },
      {
        "display": {
          "bold": true,
          "color": "red",
          "shadow_color": 0,
          "translate": "options.off"
        },
        "id": "0"
      }
    ],
    "type": "minecraft:single_option"
  },
  {
    "label": {
      "bold": true,
      "color": "black",
      "shadow_color": 0,
      "translate": "dialog.leap_of_crystal_realm.settings.particle"
    },
    "key": "particle",
    "options": [
      {
        "display": {
          "bold": true,
          "color": "dark_green",
          "shadow_color": 0,
          "translate": "options.on"
        },
        "id": "1"
      },
      {
        "display": {
          "bold": true,
          "color": "red",
          "shadow_color": 0,
          "translate": "options.off"
        },
        "id": "0"
      }
    ],
    "type": "minecraft:single_option"
  },
  {
    "label": {
      "bold": true,
      "color": "black",
      "shadow_color": 0,
      "translate": "dialog.leap_of_crystal_realm.settings.animation"
    },
    "key": "animation",
    "options": [
      {
        "display": {
          "bold": true,
          "color": "dark_green",
          "shadow_color": 0,
          "translate": "options.on"
        },
        "id": "1"
      },
      {
        "display": {
          "bold": true,
          "color": "red",
          "shadow_color": 0,
          "translate": "options.off"
        },
        "id": "0"
      }
    ],
    "type": "minecraft:single_option"
  }
]

There are two operation buttons below the input control: "Apply changes" and "Cancel changes and return". After clicking "Apply Modifications", the game will store these three data in the command storage so that they can be called by other parts of the map. The command used is stored asleap_of_crystal_realm:main, the corresponding fields are as follows:

compound root tag
  • compoundsettings:This tag stores options in settings.
    • boolsounds:Whether the sound is turned on.
    • boolparticle:Whether particles are turned on.
    • boolanimation:Whether cutscenes are enabled.

This case has a total of 3 data that need to be entered. The following will introduce how to integrate these 3 data into one/triggerMethods in command.

Methods and principles

Take a closer look at the command template, as described in the "Introduction" section to place partial submission data in&lt;objective&gt;Parameter method, it is not difficult to find that the command template is actually piecing together multiple data to form a command that can be executed. If all the data is stuffed into fractions&lt;value&gt;parameters, then you can use the methods described in this study: bitwise operations and multi-base encoding. Since scoreboard scores are in decimal, the "multiple base encoding" here is actually decimal in this article.

Let's first describe the concept of bitwise operations: For multiple 0 or 1 data, you might as well put them into a data string consisting only of 0 and 1, such as 1011001. In this way, each bit can be used as an independent storage space, and the whole can be regarded as a unique binary value. The core of bitwise operations is each bit in the data, which allows developers to treat a complete value as a set of independent Boolean states.

To do this, developers can map each bit in this string of data to a specific game instance. For the case of this article, 3-bit binary data can be used, and it is specified: the first bit from right to left controlssounds(sound effect), 2nd position controlparticle(particle), third controlanimation(cutscene). For example, the binary data of sound effects on, particles off, and cutscenes on can be expressed as101, the binary data of sound effects off, particles on, and cutscenes on can be expressed as110

However, in this scenario, each bit accepts a number from 0 to 9, which does not necessarily have to be a binary number, and can be a multi-base encoding.

Therefore, the "Apply Modification" action button in the dialog definition can be written in the following form:

json
{
  "action": {
    "template":"trigger leap_of_crystal_realm.dialog.settings set $(animation)$(particle)$(sounds)",
    "type": "minecraft:dynamic/run_command"
  },
  "label": {
    "bold": true,
    "color": "black",
    "shadow_color": 0,
    "translate": "dialog.leap_of_crystal_realm.settings.apply"
  }
}

Only used hereleap_of_crystal_realm.dialog.settingsThe criterion for this scoring item istrigger

After the player makes corresponding adjustments in the settings dialog and clicks "Apply Modifications", itleap_of_crystal_realm.dialog.settingsThe fraction on will be set to a fraction with a length of 3 digits, each digit being 0 or 1. Minecraft's command system does not directly provide bitwise operations. So now we need to design a certain algorithm to process this data.

In this case, the number of input digits is 3, which means that all possible combinations are2×2×2=8One can consider exhaustively all possible setting combinations. However, in order to add more setting inputs in the future, an exhaustive method will not be used here.

First you need to create atickfunction, high frequency detectionleap_of_crystal_realm.dialog.settingsFractionally, this function has all the cuts relative to the source file:

mcfunction
execute as @a unless score @s leap_of_crystal_realm.dialog.settings matches -1 run function leap_of_crystal_realm:dialog/settings/trigger

The conditional command here determinesleap_of_crystal_realm.dialog.settingsThe score is not -1, -1 is set as the initial value of the score. When all 3 inputs are 0, 0 is also valid data and therefore cannot be used as an initial value.

Next writeleap_of_crystal_realm:dialog/settings/triggerfunction:

mcfunction
#判断输入内容
scoreboard players operation #settings leap_of_crystal_realm.var = @s leap_of_crystal_realm.dialog.settings
scoreboard players set #bit leap_of_crystal_realm.var 0
function leap_of_crystal_realm:dialog/settings/bitwise/main

#重置分数
scoreboard players set @s leap_of_crystal_realm.dialog.settings -1
scoreboard players enable @s leap_of_crystal_realm.dialog.settings

Now the data has been converted to#settingsexistleap_of_crystal_realm.varThe score on is unique for each data combination. Need to write belowleap_of_crystal_realm:dialog/settings/bitwise/mainThe function extracts each digit in the corresponding data.

Here is a brief introduction to the writing ideas and mathematical principles of this function: for this decimal dataN=(b2b1b0)10,inbi{0,1,2,3,4,5,6,7,8,9}

butNcan bebiExpressed as

N=b0100+b1101+b2102=i=02bi10i

First generalNDivide by 10, that is

N10=b010+b1100+b2101

rightNDivide by 10 and take modulo (%=) operation, in the above formulab010is the decimal part, the modulo result isb0, therefore, the step of dividing by 10 modulo is to obtain the rightmost bit of the binary corresponding to this data.

The integer part is correctNThe operation of dividing by 10 and rounding (/=), the result is

N=b1100+b2101

This is the original dataNThe result with the rightmost digit removed(b2b1)10. Next, you only need to repeat the above process to extract the data on each bit from right to left until all bits are extracted. so,leap_of_crystal_realm:dialog/settings/bitwise/mainNeeds to be a recursive function.

mcfunction
#从低位到高位提取
scoreboard players operation #temp leap_of_crystal_realm.var = #settings leap_of_crystal_realm.var
scoreboard players operation #temp leap_of_crystal_realm.var %= #10 constant
scoreboard players operation #settings leap_of_crystal_realm.var /= #10 constant

#读取这一位的数据
function leap_of_crystal_realm:dialog/settings/bitwise/read

#读取下一位:
scoreboard players add #bit leap_of_crystal_realm.var 1
execute if score #bit leap_of_crystal_realm.var matches ..2 run function leap_of_crystal_realm:dialog/settings/bitwise/main

in#10existconstantThe score on is 10, which is a constant.#bitexistleap_of_crystal_realm.varThe score on is the number of digits extracted by the current loop. It is placed in the function to control the recursion termination and prevent the command chain length from exceedingmaxCommandChainLengthto affect the execution of subsequent commands.

functionleap_of_crystal_realm:dialog/settings/bitwise/readUsed to read the data on each fixed bit and store it in command storage:

mcfunction
#第0位:声音
execute if score #bit leap_of_crystal_realm.var matches 0 store result storage leap_of_crystal_realm:main settings.sounds byte 1.0 run return run scoreboard players get #temp leap_of_crystal_realm.var
#第1位:粒子
execute if score #bit leap_of_crystal_realm.var matches 1 store result storage leap_of_crystal_realm:main settings.particle byte 1.0 run return run scoreboard players get #temp leap_of_crystal_realm.var
#第2位:过场动画
execute if score #bit leap_of_crystal_realm.var matches 2 store result storage leap_of_crystal_realm:main settings.animation byte 1.0 run return run scoreboard players get #temp leap_of_crystal_realm.var

At this point, the entire system for bitwise operations has been roughly written.

There are only 3 input data in this case. If you increase the amount of input data, when there arem1m9mZ+) input, you can usemBits of decimal dataNN=(bm1bm2b1b0)10, among whichbi{0,1,2,3,4,5,6,7,8,9}. but

N=b0100+b1101++bm110m1=i=0m1bi10i

WillNDivide by 10, that is

N10=b010+b1100++bm110m2

The result of the modulo operation isb0, the rounded result isb1100++bm110m2, the value after rounding

N=b1100++bm110m2

This is the original dataNThe result with the rightmost digit removed. Repeat the above process for new data to extract the results for each bitbi. According to this principle, functionleap_of_crystal_realm:dialog/settings/bitwise/readThe content can be

mcfunction
#从低位到高位提取
scoreboard players operation #temp leap_of_crystal_realm.var = #settings leap_of_crystal_realm.var
scoreboard players operation #temp leap_of_crystal_realm.var %= 10 constant
scoreboard players operation #settings leap_of_crystal_realm.var /= 10 constant

#读取这一位的数据
function leap_of_crystal_realm:dialog/settings/bitwise/read

#读取下一位:
scoreboard players add #bit leap_of_crystal_realm.var 1
execute if score #bit leap_of_crystal_realm.var matches ..<m-1> run function leap_of_crystal_realm:dialog/settings/bitwise/main

Pay attention to the function&lt;m-1&gt;, this parameter is the abovem1m1To prevent overflowmaxCommandChainLengthThe number of bits used recursively limits. For any within the specified rangemValue, you can use the above function to extract the data on each bit.

Prospects and shortcomings

It is stipulated abovemLimitations of this parameter:mCan only be an integer between 1 and 9 (inclusive), this is because scoreboard scores use 32-bit signed integers, which have an upper limit of 2147483647 (2321), the criterion for storing pseudo-binary or multi-ary data istriggerWhen using the scoreboard, it will occupy the number of digits of 2147483647. Although 2147483647 has 10 digits, the number of digits that can completely use the numbers between 0 and 9 is only the 9 digits on the right. If the 10th digit is used, this bit can only accommodate two values ​​​​0 and 1 in a strict sense. When it is 2, the maximum available value of each bit will be limited. Reflected on the dialog, a page can contain up to 10 input controls. In order for bitwise operations to work properly, one of the controls must only contain two available values. If it contains three, the number of available values ​​for other controls will be limited, and the position used by this control is the 10th position.

Because the valueNEach bit can only hold at most integers from 0 to 9 (including endpoints), so a dialog input control can only accept up to 10 available real values.booleanThere are always only two available real values ​​for type input controls, and there are no restrictions;number_rangeandsingle_optionType input controls must strictly limit their number of available real values ​​to 10 or less;textThis type of input control is uncontrollable, so this research method cannot be used for this type of input control.

In addition, scoreboard supports signed integers, while the method described in this article does not use negative numbers. Negative numbers require adding a before the number`

  • , which can actually be passed into the command template as the real value used by an input control, thereby adding an available input control. However, this input control can only support 2 available values. When it needs to be a positive number, the real value of the control should be empty."id": "". But there is a problem with using negative numbers: when the digital part is 0, the 0 and digits of the positive number are
  • `A conflict of 0 will occur and this conflict must be considered.

It can be seen that although this research method omits the process of complete exhaustion or partial exhaustion, it still limits the number of input controls in the dialog and the number of available values ​​for each input control, and it does not support it at all.texttype of input control. Those beyond this range still need to exhaustively enumerate the names of scoring items. Future research directions could be the combination of exhaustive and bitwise operations.

Acknowledgments

Leather Sword provided the mathematical calculation basis and original code for this study.

References

[1] <https://zh.minecraft.wiki/w/对话框定义格式&gt;

[2] <https://zh.minecraft.wiki/w/命令/trigger&gt;

[3] <https://zh.minecraft.wiki/w/文本组件&gt;

[4] <https://www.cnblogs.com/LuckyWinty/p/7050510.html&gt;

Powered by VitePress and GitHub Pages