So, I've come up with a way to create custom NBT arrays, with a way to iterate through them. I have used this to store player UUID, and compare them to activate code to specific players on a list. The important note here is that is doesn't matter how long the array is, and because it's NBT data, you can store pretty much any data. You do have to create this on a per-array basis.
Setup
You need the following score values, they don't have to be per-array, as they are reset / overwritten during each check:
scoreboard objectives add arr_loop_start dummy scoreboard objectives add arr_index dummy scoreboard objectives add arr_current dummy scoreboard objectives add arr_result dummy scoreboard objectives add arr_UUIDMost dummy scoreboard objectives add arr_UUIDLeast dummy
I have set them up to be in a folder located datapack:array. You will have to alter this to your array.
It works by manipulating nbt data on an item. Therefore, you need an entity that can hold an item. I am going to use an armor stand, and the ArmorItems[0] slot for array manipulation.
Run this as the Armor_Stand:
data modify entity @s ArmorItems[0] set value {id:"minecraft:paper",Count:1b,tag:{CustomArray:{Array:[{UUIDLeast:0L,UUIDMost:0L,index:0}],Count:1},UUIDComp:{UUIDMost:0L,UUIDLeast:0L}} execute as @s run scoreboard players set @s arr_loop_start -1
Yes, a default value in the array is required, but you can easily filter this out when comparing the result.
Array Manipulation:
Append a new value:
Create a file called append.mcfunction
Run this as the Armor_Stand, and replace @p with the selector for your player, or store whatever data you are using nested inside of the Array[-1] tag. Make sure to limit the player selector to 1 player.
#Create new array item execute as @s run data modify entity @s ArmorItems[0].tag.CustomArray.Array append value {UUIDLeast:0L,UUIDMost:0L,index:0} #Store data in item execute as @s at @s run data modify entity @s ArmorItems[0].tag.CustomArray.Array[-1].UUIDLeast set from entity @p UUIDLeast execute as @s at @s run data modify entity @s ArmorItems[0].tag.CustomArray.Array[-1].UUIDMost set from entity @p UUIDMost #Store index count of new array item execute as @s run data modify entity @s ArmorItems[0].tag.CustomArray.Array[-1].index set from entity @s ArmorItems[0].tag.CustomArray.Count #Add 1 to Count - IMPORTANT TO DO AFTER STORING COUNT execute as @s store result score @s arr_current run data get entity @s ArmorItems[0].tag.CustomArray.Count scoreboard players add @s arr_current 1 execute as @s store result entity @s ArmorItems[0].tag.CustomArray.Count int 1 run scoreboard players get @s arr_current
What this does is append a new, blank item to the array. Because we state "append", it appears at the end of the list, and we can use Array[-1] to target it.
Looping through the array:
I am going to show how to loop through the array by doing a "contains" function. What it will do is loop through the array looking for the UUID of the player, and if it successfully matches, retrieve the index tag value from the array. I will also show you how to call a function as this player during the loop.
This requires 4 .mcfunction files:
contains.mcfunction _startcontainsloop.mcfunction _containsloop.mcfunction _containsloopmain.mcfunction
I will explain these in the order that they call each other.
contains.mcfunction
Run this as the Armor_Stand.
execute as @s run function datapack:array/_startcontainsloop execute as @s if score @s arr_result matches 1.. run function IS_IN_ARRAY execute as @s if score @s arr_result matches 0 run function NOT_IN_ARRAY
This is the mcfunction file you call to start the loop. It starts the loop. You can replace the IS_IN_ARRAY and NOT_IN_ARRAY with function that run if the player selector is not/is in the array. Because we test for arr_result matching 0, the default/empty array item is filtered out of the array naturally.
_startcontainsloop.mcfunction
This is run from contains.mcfunction.
scoreboard players set @s arr_result 0 scoreboard players set @s arr_index -1 execute as @s store result score @s arr_loop_start run data get entity @s ArmorItems[0].tag.CustomArray.Array[0].index execute as @s run function datapack:array/_containsloop execute as @s run scoreboard players set @s arr_loop_start -1
This resets the variables, then gets the index tag value of the first item in the array. This is used so that the loop knows when to stop looping.
_containsloop.mcfunction
This is the actual function that loops itself. It is run from _startcontainsloop.mcfunction.
#Shift array by 1 #Copy Array[0] to end execute as @s run data modify entity @s ArmorItems[0].tag.CustomArray.Array append from entity @s ArmorItems[0].tag.CustomArray.Array[0] #Delete Array[0] execute as @s run data remove entity @s ArmorItems[0].tag.CustomArray.Array[0] #Find new Array[0] index tag value execute as @s store result score @s arr_index run data get entity @s ArmorItems[0].tag.CustomArray.Array[0].index #Test if result has been found yet execute as @s if score @s arr_result matches 0 run function datapack:array/_containsloopmain #Restart Loop execute as @s unless score @s arr_index = @s arr_loop_start run function datapack:array/_containsloop
The looping works different from normal code, because you can't change the index value within the command. So instead, I figured out how to keep the index value the same, but instead shift the entire array.
It works by copying the first value to the end of the array, then deleting the original one from the beginning. It's a bit of an odd way of doing it, but because you cannot alter the array index to a score inside commands, this is the only way I could come up with.
If you want to simply iterate over every value without returning a result, then you can remove all if / unless / score set utilising the arr_result score.
_containsloopmain.mcfunction
This is the function to run for every value in the array. It is run from _containsloop.mcfunction.
So this can basically be anything, as you can access all of the array item data using ArmorItems[0].tag.CustomArray.Array[0]. The example below is how to compare player UUID and match them. Remember to change the @p to the appropriate selector for your player.
#Check for player UUIDLeast and UUIDMost scoreboard players set @s arr_UUIDMost 1 scoreboard players set @s arr_UUIDLeast 1 #Copy over UUID from PLAYERS execute as @s run data modify entity @s ArmorItems[0].tag.UUIDCompare.UUIDMost set from entity @p UUIDMost execute as @s run data modify entity @s ArmorItems[0].tag.UUIDCompare.UUIDLeast set from entity @p UUIDLeast #Attempt copy of UUIDMost from array item. 1 means they don't match, 0 means a match execute as @s at @s store success score @s arr_UUIDMost run data modify entity @s ArmorItems[0].tag.UUIDCompare.UUIDMost set from entity @s ArmorItems[0].tag.CustomArray.Array[0].UUIDMost #Same as above but with UUIDLeast, and it only gets run if UUIDMost succeeds execute as @s at @s if score @s arr_UUIDMost matches 0 store success score @s arr_UUIDLeast run data modify entity @s ArmorItems[0].tag.UUIDCompare.UUIDLeast set from entity @s ArmorItems[0].tag.CustomArray.Array[0].UUIDLeast #If arr_UUIDLeast is 0, both UUID match, and so your selected player is in the array execute if score @s arr_UUIDLeast matches 0 store result score @s arr_result run data get entity @s ArmorItems[0].tag.CustomArray.Array[0] execute if score @s arr_UUIDLeast matches 0 as @p run say Matches! execute if score @s arr_UUIDLeast matches 1 as @p run say Doesn't Match!
The way this compares UUID is if you try to copy a UUIDLeast/UUIDMost value to a tag value, but that tag is already equal to the UUID, then the command fails. We can test for this failure, and store the success of each in arr_UUIDMost and arr_UUIDLeast. The test for UUIDLeast is only tested if UUIDMost succeeds, which means that if arr_UUIDLeast is equal to 0, your player is in the array.
You can replace the "say Matches!" with a function that gets run if the player is in the array. Keep in mind that "say Doesn't Match!" does not mean that your player is not in the array, but it just doesn't match the current UUID comparison test.
The part utilising arr_result stores the index tag value of the array item (not the index of the array item, the index tagvalue). Because we require the default/empty array value, which has an index tag of value 0, we can compare if the arr_result matches 1.. to see if the player is in the array (shown in contains.mcfunction)
Conclusion:
So using these functions you can store an array of players, and enact command mayhem upon those whom are or are not in said array.
For example, I am using it to give mining fatigue to any player not in the array, and passing in for all plays within 30 blocks. I'm sure other people can come up with better ideas.
Comment what you think below, a I love to hear feedback on how to improve things, I'm sure there are ways.
Any mistakes I have made, please tell me. I have converted the path navigation, and most of the variable names for easier understanding, so please say if I missed any.
Thanks for reading this far!
1
Yes, the range of effect is 64 blocks in all directions forming a cubic area of effect.
That said, the system does not actually add light to caves, it merely eliminates all mobs that try to spawn within its area of effect.
Hope this clarifies things!
1
I'm trying to detect when the player is wearing a chestplate with the tag: TradePackArmor and tried doing that with the following command:
I'm not sure why this isn't working. Can someone explain this?
Edit:
Of course I think of checking entity data right after this. In case you care to know the command, here you go:
1
Got it. Yeah, this system should work fine as long as beds are disabled. Also, with the commands I laid out, there is no need for the darkroom if you are only using it for /spreadplayers.
Also, I wouldn't worry about the number of commands, with that few, there should be no noticeable impact on the game whatsoever.
1
Good to hear! Let me know if you need anything else.
Edit: Recently made some changes. Not sure if they were necessary, but if you have any issues please just recopy the commands above. Cheers!
1
NOTE: X, Y, and Z when seen in the following code represents the coordinates for world spawn
Command Block Activated By New Player:
Repeating Command Block in Spawn Chunks:
Chain Command Blocks (Unconditional):
Command 1:
Command 2:
Command 3:
Command 4:
Command 5:
If you want, I can give you code that will prevent players from having their spawn points set too close to each other. Hope this is what you're looking for!
- John
1
The Modular Function Framework is a system that I've been developing since December 2018 which is designed to make installing compatible datapacks easier. Why is this necessary? Currently, I have plans for a variety of functions that are all meant to be compatible with each other, however, my concern was that it might get more difficult to tell if the functions were installed correctly as the number of functions increase. My solution to this problem was MFF Core.
MFF Core is a combination of function files which run whenever you launch your Minecraft world and which loop in the background of your game while you play and serve the purpose of running any MFF Modules you download. That said, MFF Core is more useful in that it is designed to give the player feedback whenever you run the command /reload. That feedback is designed to give you information about which modules have been initialized and which modules are actively running in the background. These sections are denoted by "Initializing Modules..." and "Loading Modules..." respectively as seen in the spoiler below.
The Core is also set up to display additional details about the installed modules (upcoming feature). When the /reload function finished, you will see some text saying "Extra Details:" followed by a link saying [Click]. By following that link, you will be given a brief overview of all pertinent information about the functionality of the modules as well as a link to the project's individual page for further reference.
Credits:
TheRedEngineer
Requirements:
Required By:
Details:
Biome Detection is a standalone module which controls a scoreboard objective called "PlayerBiome"
and was originally developed by TheRedEngineer. For the purposes of integrating it into the framework, I have made
some minor naming changes while retaining the base code he developed. On its own, it has no impact on the
environment and simply returns the numeric value for the player's current biome in the objective listed above.
For a list of all Biome IDs please reference the following page on the Minecraft Wiki: Biome
Credits:
dio_brando
Requirements:
Required By:
Details:
This datapack adds a multiblock structure to Minecraft which eliminates the need for torch-spam to get rid of those annoying zombies and was made at the request of dio_brando. The Megatorch functions similarly to the Magnum Torch from Extra Utilities in that it has no effect on mobs that spawn outside its range while preventing mobs from spawning inside its area-of-effect. The multiblock itself is a 3x3x3 structure made up of Smooth Stone, Cobblestone Stairs, Glowstone, Light Gray Stained Glass, and an Iron Block and has an effective range of 64 blocks from the center.
Forum Page:
Megatorch [Spawn-Proofing Without Light] [MFF]
Credits:
Vechs
Requirements:
Required By:
Details:
This module was my main motivation for creating the framework and was inspired by Vech's temperature mechanics from his latest Super Hostile Map entitled "Iceolation" (not available for download at the time of posting). Although it functions in a fundamentally different way, the project was undoubtedly started as a result of Vechs work. It is designed to change the player's temperature based on what biome the player is in, what blocks they are standing on, and whether they are swimming in water or lava. If the player gets too hot or cold debuffs will be applied. The effect the environment has on the player can be negated by armor and varies based on the amount of armor the player has equipped.
Planet Minecraft Page:
Temperature in Minecraft
Requirements:
Required By:
Details:
This alone creates a two-second clock which can be utilized by other modules. Furthermore, it is the foundation for any module which necessitates the creation of a clock which does not run on a two-second interval so that no unnecessary scoreboard objectives are created.
If you don't want to bother with downloading each component module and setting them up individually, this section is for you. Just follow the given instructions for installing each pack and please report any issues you come across with installation down below in the comments.
Latest Version:
Mediafire Download
Older Versions:
Screenshots:
Latest Version:
MediaFire Download
Older Versions:
Screenshots:
Installing an MFF datapack is very similar to downloading a Minecraft world. The only difference is that instead of pasting the datapack into Minecraft's 'save' folder you have to place the extracted datapack into the save's 'datapack' folder. For a more detailed walkthrough, please reference the spoiler below:
Step One:
Download the MFF Pack you wish to install and extract the zip file.
Step Two:
Navigate to the game file you wish to install the MFF Pack into and select Edit.
Step Three:
Select Open World Folder
Step Four:
Open your datapacks folder.
Step Five:
Paste the extracted file into your datapacks folder.
You are now done and your chosen MFF Pack should now be installed!
1
So this can actually be done by a single repeating command block running the following command:
After testing, it does appear that the damage tag is still recognized, I can't say exactly why you were having difficulty, but in any case, this should do what you're looking for. Hope this helps!
-John
1
dio_brando
Requirements:
Required By:
Details:
This datapack adds a multiblock structure to Minecraft which eliminates the need for torch-spam to get rid of those annoying zombies and was made at the request of dio_brando. The Megatorch functions similarly to the Magnum Torch from Extra Utilities in that it has no effect on mobs that spawn outside its range while preventing mobs from spawning inside its area-of-effect (see spoiler for visuals of active Megatorch). The multiblock itself is a 3x3x3 structure made up of Smooth Stone, Cobblestone Stairs, Glowstone, Light Gray Stained Glass, and an Iron Block and has an effective range of 64 blocks from the center.
Multiblock Details:
To form the multiblock, build the structure shown in the below spoiler and throw a diamond onto the glowstone block in the center. You will be able to tell that the multiblock has formed when the glowstone block begins emitting white particle effects. To remove the structure, simply break any part of the structure (this includes placing a block in any of the open air spaces).
Step One:
Download the MFF Pack extract the zip file.
Step Two:
Navigate to the game file you wish to install the MFF Pack into and select Edit.
Step Three:
Select Open World Folder
Step Four:
Open your datapacks folder.
Step Five:
Paste the extracted file into your datapacks folder.
You are now done and your MFF Pack should now be installed!
1
You can get around the one entity limit by using /execute like so:
1
Fixed!