I'm trying to make a dynamical sized integer array in Minecraft 1.14.4. I've already tried different ways, but the problem was with all of those solutions, that I had to summon one entity for each index, and then having two scoreboard, which were holding the integer for every entity and the index for every entity.
Then I had to run something like this:
/execute as @e[type=minecraft:armor_stand,tag=array] if score #index INDEX = @s INDEX store result score #value VALUES run scoreboard players get @s VALUES
where #index
is the index I want to read from, and #value
is the return value. The problem with this is, that if you have around 1000 indexes, the game gets really laggy due to all the entities.
Has someone got an idea of how to do this in a better way? Maybe with the ability of 1.14 nbt arrays, but without the need of iterating through every index (because every command is taking some time to get executed, and I necessarily need the speed)?
PS.: I'm already using a datapack, so it won't be a problem, if the solution depends on functions.
Best Answer
Creating a dynamically sized array in NBT is somewhat easy: Just use a recursive function to loop over a score (which determines the length) and use
/data modify […] append
every time. Here is an example:Setup:
I'm using multiplication by 2 on every iteration to show that you can do arbitrary calculations with the values.
Function "
fabian:fill_array
":Explanation:
The first command copies the scoreboard value of the dummy player "
$value
" to the "value
" NBT tag in storage.The second command appends the current "
value
" tag onto the array. There is no way to directly append a scoreboard value to an NBT array.The rest of the function just does an arbitrary calculation on "
$value
", ticks down "$length
" and loops back to the start as long as "$length
" has not reached 0 yet.Note that this function will still do its calculation once and append that onto the array, even if "
$length
" is already at 0 or below. You should consider that in whatever system you are using this.Now the more complicated part: Reading from an arbitrary index. There are two main ways to do this.
The tedious method: Have a big function with every possibility that might occur in your setup:
Of course this would be infeasible for very long arrays.
The copy+remove method: Something similar was suggested here (archive), but my method does not require writing the index into the NBT array, so you can use it on already existing data (created e.g. by the game or some other datapack).
First, copy the entire array somewhere else:
Then keep removing the first entry of the array as many times as you want (indicated for example by a scoreboard):
Once your loop is over, simply read the value from the first entry that remains:
You can also do this backwards, for example if you want to read the n-th last entry in an array, run
/data remove […] copy[-1]
n-1
times and then/data get […] copy[-1]
.This can also be used for searching. Tick up an index scoreboard every time you remove the first entry and compare the value to a scoreboard like this:
The fake player "
$changed
" will now have a 1 in thearray
scoreboard if the current array value is different than the score you're comparing it to and 0 if it is the same (so you found the value that you were looking for).The ticked up scoreboard then indicates the index. Alternatively, you can get the length of the remaining array like this:
And then you can subtract that from the original length.