Last active
July 31, 2022 11:45
-
-
Save Kas-tle/becc11f99e7ce7614bc741b3bac85f7b to your computer and use it in GitHub Desktop.
Replace heads in world and generate resource pack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# sudo mca2nbt *.mca | |
# rm *.mca | |
# sudo chown -R jdcastle:jdcastle * | |
# sudo chmod 775 * | |
mkdir -p scratch | |
mkdir -p target/rp | |
mkdir -p target/datapack/replace_heads/data/replace_heads/functions/replacements | |
mkdir -p target/animatronics | |
mkdir -p target/shops | |
unzip rp.zip -d target/rp | |
mkdir -p target/rp/assets/mega/models/heads | |
mkdir -p target/rp/assets/mega/textures/heads | |
arr=($(find . -type f -name "*.nbt")) | |
for f in ${arr[@]}; do nbt2json -b -i "${f}" -o "${f::-4}.json"; done | |
jq -s -r ' | |
([ | |
.[] | .nbt? | .[]? | .value? | .[]? | .value? | .list? | .[]? | |
| select(.[]? | .name? == "HandItems") | |
| select(.[]? | .value? | .list? |.[]? | .[]? | .value? | .[]? | .name? == "SkullOwner") | |
| select(.[]? | .value? | .list? |.[]? | .[]? | .value? | .[]? | .value? | .[]? | .value? | .[]? | .name? == "textures") | |
| select(.[]? | .value? | .list? |.[]? | .[]? | .value? | .[]? | .value? | .[]? | .value? | .[]? | .value? | .list? | .[]? | .[]? | .name? == "Value") | |
| del(..| objects | select(.name == "ArmorItems")) | |
] + [ | |
.[] | .nbt? | .[]? | .value? | .[]? | .value? | .list? | .[]? | |
| select(.[]? | .name? == "ArmorItems") | |
| select(.[]? | .value? | .list? |.[]? | .[]? | .value? | .[]? | .name? == "SkullOwner") | |
| select(.[]? | .value? | .list? |.[]? | .[]? | .value? | .[]? | .value? | .[]? | .value? | .[]? | .name? == "textures") | |
| select(.[]? | .value? | .list? |.[]? | .[]? | .value? | .[]? | .value? | .[]? | .value? | .[]? | .value? | .list? | .[]? | .[]? | .name? == "Value") | |
| del(..| objects | select(.name == "HandItems")) | |
] | |
| map( | |
(.[]? | .value? | .list?) as $armor_items | | |
(.[]? | select(.value? | .list? | .[]? | .[]? | .value? | .[]? | .name? == "SkullOwner") | .name?) as $slot_type | | |
($armor_items? | to_entries? | .[]? | select(.value? | .[]? | .[]? | .[]? | .name? == "SkullOwner") | .key?) as $slot_index | | |
($armor_items? | .[]? | .[]? | .value? | .[]? | select(.name? == "SkullOwner") | .value? | .[]? | .value? | .[]? | select(.name? == "textures") | .value? | .list? | .[]? | .[]? | select(.name? == "Value") | .value?) as $skin_data | | |
{ | |
"value": ($skin_data), | |
"pos": (.[]? | select(.name? == "Pos") | .value? | .list?), | |
"slot_type": ($slot_type), | |
"slot_index": ($slot_index) | |
})) as $head_data | |
| ([($head_data | .[]? | .value)] | unique) as $unique_heads | |
| (($unique_heads | to_entries) | map({(.value): (.key + 1)}) | add) as $head_index | |
| $head_data | map( | |
.value as $value | |
| { | |
"head_index": ($head_index | .[$value]), | |
"skin_data": (.value), | |
"slot_type": (.slot_type), | |
"slot_index": (.slot_index), | |
"chunk": (.pos | map(. | floor)), | |
"pos": (.pos) | |
} | |
) | unique | |
' **/*.json > scratch/heads.json | |
jq -n ' | |
{ | |
"textures": { | |
"0": "minecraft:block/white_concrete", | |
"particle": "minecraft:block/white_concrete" | |
}, | |
"elements": [ | |
{ | |
"name": "head", | |
"from": [0.5, 0.5, 0.5], | |
"to": [15.5, 15.5, 15.5], | |
"rotation": {"angle": 0, "axis": "y", "origin": [8, -23.5, 8]}, | |
"faces": { | |
"north": {"uv": [4, 4, 8, 8], "texture": "#0"}, | |
"east": {"uv": [0, 4, 4, 8], "texture": "#0"}, | |
"south": {"uv": [12, 4, 16, 8], "texture": "#0"}, | |
"west": {"uv": [8, 4, 12, 8], "texture": "#0"}, | |
"up": {"uv": [8, 4, 4, 0], "texture": "#0"}, | |
"down": {"uv": [8, 0, 12, 4], "texture": "#0"} | |
} | |
}, | |
{ | |
"name": "headwear", | |
"from": [0, 0, 0], | |
"to": [16, 16, 16], | |
"rotation": {"angle": 0, "axis": "y", "origin": [8, -23.5, 8]}, | |
"faces": { | |
"north": {"uv": [4, 12, 8, 16], "texture": "#0"}, | |
"east": {"uv": [0, 12, 4, 16], "texture": "#0"}, | |
"south": {"uv": [12, 12, 16, 16], "texture": "#0"}, | |
"west": {"uv": [8, 12, 12, 16], "texture": "#0"}, | |
"up": {"uv": [8, 12, 4, 8], "texture": "#0"}, | |
"down": {"uv": [8, 8, 12, 12], "texture": "#0"} | |
} | |
} | |
], | |
"display": { | |
"thirdperson_righthand": { | |
"rotation": [75, 45, 0], | |
"translation": [0, 2.5, 0], | |
"scale": [0.375, 0.375, 0.375] | |
}, | |
"thirdperson_lefthand": { | |
"rotation": [75, 45, 0], | |
"translation": [0, 2.5, 0], | |
"scale": [0.375, 0.375, 0.375] | |
}, | |
"firstperson_righthand": { | |
"rotation": [0, 45, 0], | |
"scale": [0.4, 0.4, 0.4] | |
}, | |
"firstperson_lefthand": { | |
"rotation": [0, 225, 0], | |
"scale": [0.4, 0.4, 0.4] | |
}, | |
"ground": { | |
"translation": [0, 3, 0], | |
"scale": [0.25, 0.25, 0.25] | |
}, | |
"gui": { | |
"rotation": [30, 225, 0], | |
"scale": [0.625, 0.625, 0.625] | |
}, | |
"fixed": { | |
"scale": [0.5, 0.5, 0.5] | |
} | |
}, | |
"groups": [ | |
{ | |
"name": "head", | |
"origin": [0, 24, 0], | |
"color": 0, | |
"children": [0] | |
}, | |
{ | |
"name": "headwear", | |
"origin": [0, 24, 0], | |
"color": 0, | |
"children": [1] | |
} | |
] | |
} | |
' > target/rp/assets/mega/models/heads/head_template.json | |
jq -n ' | |
{ | |
"parent": "minecraft:item/generated", | |
"textures": { | |
"layer0": "minecraft:item/gold_ingot" | |
}, | |
"overrides": [] | |
} | |
' > target/rp/assets/minecraft/models/item/gold_ingot.json | |
jq -n ' | |
{ | |
"pack": { | |
"pack_format": 5, | |
"description": "Convert armor stand heads" | |
} | |
} | |
' > target/datapack/replace_heads/pack.mcmeta | |
jq -r '[.[] | [.head_index, .skin_data]] | unique | .[] | @tsv | gsub("\\t";",")' scratch/heads.json > scratch/heads_resource.csv | |
while IFS=, read -r head_index skin_data; do | |
SKIN_URL=$(echo "${skin_data}" | base64 -d | jq -r .textures.SKIN.url) | |
echo "Downloading head ${head_index}: ${SKIN_URL}" | |
wget -O "scratch/scratchhead.png" "${SKIN_URL}" -q --show-progress | |
convert "scratch/scratchhead.png" -crop 32x16+0+0 "scratch/scratchhead_1.png" | |
convert "scratch/scratchhead.png" -crop 32x16+32+0 "scratch/scratchhead_2.png" | |
convert -append scratch/scratchhead_*.png "target/rp/assets/mega/textures/heads/customhead_${head_index}.png" | |
rm scratch/scratchhead_*.png && rm "scratch/scratchhead.png" | |
jq -n --arg head_index "${head_index}" ' | |
{ | |
"parent": "mega:heads/head_template", | |
"textures": { | |
"0": ("mega:heads/customhead_" + $head_index), | |
"particle": ("mega:heads/customhead_" + $head_index) | |
} | |
} | |
' > "target/rp/assets/mega/models/heads/customhead_${head_index}.json" | |
jq --arg head_index "${head_index}" ' | |
.overrides += [{"predicate": {"custom_model_data": ($head_index | tonumber)}, "model": ("mega:heads/customhead_" + $head_index)}] | |
' target/rp/assets/minecraft/models/item/gold_ingot.json | sponge target/rp/assets/minecraft/models/item/gold_ingot.json | |
done < scratch/heads_resource.csv | |
jq -r '[.[] | [.head_index, .slot_type, .slot_index, .chunk[0], .chunk[2], .pos[0], .pos[1], .pos[2]]] | .[] | @tsv | gsub("\\t";",")' scratch/heads.json > scratch/heads_replace.csv | |
counter=0 | |
while IFS=, read -r head_index slot_type slot_index chunk_x chunk_z pos_x pos_y pos_z; do | |
# NOTE: | |
counter=$(( $counter + 1 )) | |
next_counter=$(( $counter + 1 )) | |
echo "execute in minecraft:overworld run forceload add $(( $chunk_x - 2 )) $(( $chunk_z - 2 )) $(( $chunk_x + 2 )) $(( $chunk_z + 2 ))" >> target/datapack/replace_heads/data/replace_heads/functions/replacements/start.mcfunction | |
cat <<EOF >> target/datapack/replace_heads/data/replace_heads/functions/replacements/${counter}.mcfunction | |
execute in minecraft:overworld run data modify entity @e[type=armor_stand,limit=1,sort=nearest,x=${pos_x},y=${pos_y},z=${pos_z},distance=..1] ${slot_type}[${slot_index}] set value {id:"minecraft:gold_ingot",Count:1b,tag:{CustomModelData:${head_index}}} | |
execute in minecraft:overworld run forceload remove ${chunk_x} ${chunk_z} | |
schedule function replace_heads:replacements/${next_counter} 5t append | |
EOF | |
done < scratch/heads_replace.csv | |
echo "schedule function replace_heads:replacements/1 10s append" >> target/datapack/replace_heads/data/replace_heads/functions/replacements/start.mcfunction | |
echo 'execute in minecraft:overworld run forceload remove all' >> target/datapack/replace_heads/data/replace_heads/functions/replacements/${counter}.mcfunction | |
echo 'execute in minecraft:overworld run say Done with heads' >> target/datapack/replace_heads/data/replace_heads/functions/replacements/${counter}.mcfunction | |
yq -r -s '[.[]? | .Animatronic | .[]? | .clothes? | .[]? | select(.. ."meta-type"? == "SKULL") |.. .internal?] - [null] | unique[]' animatronics/*.anima > scratch/anima_nbt.csv | |
jq -n '{}' > scratch/anima_nbt_index.json | |
while IFS=, read -r base_64_nbt; do | |
base_64_skin_data=$(echo "${base_64_nbt}" | base64 --decode | nbt2json -b | jq -r '.nbt? | .[0]? | .value[0]? | .value[]? | select(.name? == "Properties") | .value[0]? | .value? | .list[0]?[]? | select(.name? == "Value") | .value?') | |
jq --arg base_64_nbt "${base_64_nbt}" --arg base_64_skin_data "${base_64_skin_data}" '. += {($base_64_nbt): ($base_64_skin_data)}' scratch/anima_nbt_index.json | sponge scratch/anima_nbt_index.json | |
done < scratch/anima_nbt.csv | |
for f in animatronics_2/*.anima; do | |
yq -y --slurpfile head_slurp_file scratch/heads.json --slurpfile nbt_slurp_file scratch/anima_nbt_index.json ' | |
($head_slurp_file | .[]? | map ({(.skin_data): (.head_index)}) | add) as $head_index | | |
($nbt_slurp_file | .[]?) as $nbt_index | | |
(.Animatronic | keys[0]) as $anima_key | (.Animatronic | .[($anima_key)].clothes) | |
|= map_values(if (.meta? | .["meta-type"]? == "SKULL") then ( | |
.type |= "GOLD_INGOT" | | |
.meta |= { | |
"==": "ItemMeta", | |
"meta-type": "UNSPECIFIC", | |
"custom-model-data": ((.internal as $index | $nbt_index | .[$index]) as $head_base_64 | $head_index | .[$head_base_64] // 1) | |
} | |
) elif (.[]? | .meta? | .["meta-type"]? == "SKULL") then ( | |
map_values( | |
if (.meta? | .["meta-type"]? == "SKULL") then ( | |
.type |= "GOLD_INGOT" | | |
.meta |= { | |
"==": "ItemMeta", | |
"meta-type": "UNSPECIFIC", | |
"custom-model-data": ((.internal as $index | $nbt_index | .[$index]) as $head_base_64 | $head_index | .[$head_base_64] // 1) | |
} | |
) else . end | |
) | |
) else . end) | |
' ${f} > "target/animatronics/${f##*/}" | |
done | |
for f in shops/*.yml; do | |
yq -y --slurpfile head_slurp_file scratch/heads.json ' | |
($head_slurp_file | .[]? | map ({(.skin_data): (.head_index)}) | add) as $head_index | | |
keys[0] as $key | (.[$key] | .items?) |= map_values(if (.item?.material? == "PLAYER_HEAD") then | |
(.item?.skin? as $skin | |
| .item?.material? |= "GOLD_INGOT" | |
| .item?.model? |= ($head_index | .[$skin] // 1) | |
| del(.item?.skin?) | |
) else | |
. end) | |
' ${f} > "target/shops/${f##*/}" | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment