9
0
mirror of https://github.com/Kas-tle/java2bedrock.sh.git synced 2025-12-20 15:19:16 +00:00

Use Geyser mappings; smart texture atlasing

This commit is contained in:
Kas-tle
2022-07-30 11:46:03 +00:00
committed by GitHub
parent aa2781c660
commit 290fe51147
2 changed files with 82 additions and 109 deletions

3
.gitignore vendored
View File

@@ -9,3 +9,6 @@ parents.json
*.csv *.csv
*.temp *.temp
spritesheet.json spritesheet.json
item_mappings.json
item_texture.json
spritesheet/

View File

@@ -130,79 +130,28 @@ status_message process "Iterating through all vanilla associated model JSONs to
if test -d "./assets/minecraft/models/item"; then confarg1="./assets/minecraft/models/item/*.json"; fi if test -d "./assets/minecraft/models/item"; then confarg1="./assets/minecraft/models/item/*.json"; fi
if test -d "./assets/minecraft/models/block"; then confarg2="./assets/minecraft/models/block/*.json"; fi if test -d "./assets/minecraft/models/block"; then confarg2="./assets/minecraft/models/block/*.json"; fi
# Download geyser mappings
status_message process "Downloading the latest geyser item mappings"
printf "\e[3m\e[37m"
echo
wget -nv --show-progress -O item_mappings.json https://raw.githubusercontent.com/GeyserMC/mappings/master/items.json
echo
wget -nv --show-progress -O item_texture.json https://raw.githubusercontent.com/Kas-tle/java2bedrockMappings/main/item_texture.json
echo
printf "${C_CLOSE}"
jq -n '[inputs | {(input_filename | sub("(.+)/(?<itemname>.*?).json"; .itemname)): .overrides?[]?}] | jq --slurpfile item_texture item_texture.json --slurpfile item_mappings item_mappings.json -n '[inputs | {(input_filename | sub("(.+)/(?<itemname>.*?).json"; .itemname)): .overrides?[]?}] |
def maxdur($input): def maxdur($input):
({ ($item_mappings[] |
"carrot_on_a_stick": 25, [to_entries | map(.key as $key | .value | .java_identifer = $key) | .[] | select(.max_damage)]
"golden_axe": 32, | map({(.java_identifer | split(":") | .[1]): (.max_damage)})
"golden_hoe": 32, | add
"golden_pickaxe": 32, | .[$input] // 1)
"golden_shovel": 32, ;
"golden_sword": 32,
"wooden_axe": 59, def bedrocktexture($input):
"wooden_hoe": 59, ($item_texture[] | .[$input] // {"icon": "camera", "frame": 0})
"wooden_pickaxe":59,
"wooden_shovel":59,
"wooden_sword": 59,
"fishing_rod": 64,
"flint_and_steel": 64,
"warped_fungus_on_a_stick": 100,
"sparkler": 100,
"glow_stick": 100,
"stone_axe": 131,
"stone_hoe": 131,
"stone_pickaxe":131,
"stone_shovel":131,
"stone_sword": 131,
"shears": 238,
"iron_axe": 250,
"iron_hoe": 250,
"iron_pickaxe": 250,
"iron_shovel": 250,
"iron_sword": 250,
"trident": 250,
"crossbow": 326,
"shield": 336,
"bow": 384,
"elytra": 432,
"diamond_axe": 1561,
"diamond_hoe": 1561,
"diamond_pickaxe": 1561,
"diamond_shovel": 1561,
"diamond_sword": 1561,
"netherite_axe": 2031,
"netherite_hoe": 2031,
"netherite_pickaxe": 2031,
"netherite_shovel": 2031,
"netherite_sword": 2031,
"leather_helmet": 55,
"leather_chestplate": 80,
"leather_leggings": 75,
"leather_boots": 65,
"gold_helmet": 77,
"gold_chestplate": 112,
"gold_leggings": 105,
"gold_boots": 91,
"chainmail_helmet": 165,
"chainmail_chestplate": 240,
"chainmail_leggings": 225,
"chainmail_boots": 195,
"iron_helmet": 165,
"iron_chestplate": 240,
"iron_leggings": 225,
"iron_boots": 195,
"diamond_helmet": 363,
"diamond_chestplate": 528,
"diamond_leggings": 495,
"diamond_boots": 429,
"netherite_helmet": 407,
"netherite_chestplate": 592,
"netherite_leggings": 555,
"netherite_boots": 481,
"turtle_helmet": 275
} | .[$input] // 1)
; ;
def namespace: def namespace:
@@ -215,6 +164,7 @@ if contains(":") then sub("\\:(.+)"; "") else "minecraft" end
| (if .value.predicate.custom_model_data then .value.predicate.custom_model_data else null end) as $custom_model_data | | (if .value.predicate.custom_model_data then .value.predicate.custom_model_data else null end) as $custom_model_data |
{ {
"item": .key, "item": .key,
"bedrock_icon": bedrocktexture(.key),
"nbt": ({ "nbt": ({
"Damage": $damage, "Damage": $damage,
"Unbreakable": $unbreakable, "Unbreakable": $unbreakable,
@@ -375,9 +325,6 @@ jq -nc '
"padding": 8, "padding": 8,
"num_mip_levels": 4, "num_mip_levels": 4,
"texture_data": { "texture_data": {
"gmdl_atlas": {
"textures": "textures/geyser/geyser_custom/gmdl_atlas"
}
} }
} }
' | sponge ./target/rp/textures/terrain_texture.json ' | sponge ./target/rp/textures/terrain_texture.json
@@ -454,6 +401,12 @@ fi
# generate a fallback texture # generate a fallback texture
convert -size 16x16 xc:\#FFFFFF ./assets/minecraft/textures/0.png convert -size 16x16 xc:\#FFFFFF ./assets/minecraft/textures/0.png
# make sure we crop all mcmeta associated png files
status_message process "Cropping animated textures"
for i in $(find ./assets/**/textures -type f -name "*.mcmeta" | sed 's/\.mcmeta//'); do
convert ${i} -set option:distort:viewport "%[fx:min(w,h)]x%[fx:min(w,h)]" -distort affine "0,0 0,0" ${i}
done
status_message completion "Initial pack setup complete\n" status_message completion "Initial pack setup complete\n"
jq -r '.[] | select(.parent != null) | [.path, .geyserID, .parent] | @tsv | gsub("\\t";",")' config.json | sponge pa.csv jq -r '.[] | select(.parent != null) | [.path, .geyserID, .parent] | @tsv | gsub("\\t";",")' config.json | sponge pa.csv
@@ -541,12 +494,6 @@ do
done < pa.csv done < pa.csv
# make sure we crop all mcmeta associated png files
status_message process "Cropping animated textures"
for i in $(find ./assets/**/textures -type f -name "*.mcmeta" | sed 's/\.mcmeta//'); do
convert ${i} -set option:distort:viewport "%[fx:min(w,h)]x%[fx:min(w,h)]" -distort affine "0,0 0,0" ${i}
done
status_message process "Compiling final model list" status_message process "Compiling final model list"
# get our final 3d model list from the config # get our final 3d model list from the config
model_list=( $(jq -r '.[] | select(.generated == "false") | .path' config.json) ) model_list=( $(jq -r '.[] | select(.generated == "false") | .path' config.json) )
@@ -554,18 +501,40 @@ model_list=( $(jq -r '.[] | select(.generated == "false") | .path' config.json)
# get our final texture list to be atlased # get our final texture list to be atlased
# get a bash array of all texture files in our resource pack # get a bash array of all texture files in our resource pack
status_message process "Generating an array of all model PNG files to crosscheck with our atlas" status_message process "Generating an array of all model PNG files to crosscheck with our atlas"
jq -n '$ARGS.positional' --args $(find ./assets/**/textures -type f -name '*.png') | sponge textures1.temp jq -n '$ARGS.positional' --args $(find ./assets/**/textures -type f -name '*.png') | sponge all_textures.temp
# get bash array of all texture files listed in our models # get bash array of all texture files listed in our models
status_message process "Generating an array for the master texture atlas" status_message process "Generating union atlas arrays for all model textures"
jq -s 'def namespace: if contains(":") then sub("\\:(.+)"; "") else "minecraft" end; [.[].textures[]?] | unique | map("./assets/" + (. | namespace) + "/textures/" + (. | sub("(.*?)\\:"; "")) + ".png")' ${model_list[@]} | sponge textures2.temp jq -s '
# find the union of all texture files listed in our models and all texture files in our resource pack def namespace:
texture_list=( $(jq -s -r '((.[1] - (.[1] - .[0])) + ["./assets/minecraft/textures/0.png"]) | .[]' textures1.temp textures2.temp) ) if contains(":") then sub("\\:(.+)"; "") else "minecraft" end;
[.[]| [.textures[]] | unique]
| map(map("./assets/" + (. | namespace) + "/textures/" + (. | sub("(.*?)\\:"; "")) + ".png"))
' ${model_list[@]} | sponge union_atlas.temp
jq '
def intersects(a;b): any(a[]; . as $x | any(b[]; . == $x));
# generate our atlas from the final texture list def mapatlas(set):
status_message process "Generating sprite sheet" (set | unique) as $unique_set
spritesheet-js -f json --fullpath ${texture_list[@]} > /dev/null 2>&1 | (map(if intersects(.; $unique_set) then . else empty end) | add + $unique_set | unique) as $new_set
status_message completion "Sprite sheet successfully generated" | map(if intersects(.; $new_set) then empty else . end) + [$new_set];
mv spritesheet.png ./target/rp/textures/geyser/geyser_custom/gmdl_atlas.png
[["./assets/minecraft/textures/0.png"]] +
reduce .[] as $entry ([]; mapatlas($entry))
' union_atlas.temp | sponge union_atlas.temp
total_union_atlas=($(jq -r 'length - 1' union_atlas.temp))
mkdir spritesheet
status_message process "Generating $((1+${total_union_atlas})) sprite sheets..."
for i in $(seq 0 ${total_union_atlas})
do
# find the union of all texture files listed in this atlas and all texture files in our resource pack
texture_list=( $(jq -s --arg index "${i}" -r '(.[1][($index | tonumber)] - .[0] | length > 0) as $fallback_needed | ((.[1][($index | tonumber)] - (.[1][($index | tonumber)] - .[0])) + (if $fallback_needed then ["./assets/minecraft/textures/0.png"] else [] end)) | .[]' all_textures.temp union_atlas.temp) )
status_message process "Generating sprite sheet ${i} of ${total_union_atlas}"
spritesheet-js -f json --name spritesheet/${i} --fullpath ${texture_list[@]} > /dev/null 2>&1
jq --arg atlas_index "${i}" '.texture_data += {("gmdl_atlas_" + $atlas_index): {"textures": ("textures/geyser/geyser_custom/" + $atlas_index)}}' ./target/rp/textures/terrain_texture.json | sponge ./target/rp/textures/terrain_texture.json
done
status_message completion "All sprite sheets generated"
mv spritesheet/*.png ./target/rp/textures/geyser/geyser_custom
# begin conversion # begin conversion
jq -r '.[] | [.path, .geyserID, .generated] | @tsv | gsub("\\t";",")' config.json | sponge all.csv jq -r '.[] | [.path, .geyserID, .generated] | @tsv | gsub("\\t";",")' config.json | sponge all.csv
@@ -577,20 +546,22 @@ do
local gid=${2} local gid=${2}
local generated=${3} local generated=${3}
# find which texture atlas we will be using if not generated
if [[ ${generated} = "false" ]]
then
local atlas_index=$(jq -r -s 'def namespace: if contains(":") then sub("\\:(.+)"; "") else "minecraft" end; def intersects(a;b): any(a[]; . as $x | any(b[]; . == $x)); (.[0] | [.textures[]] | map("./assets/" + (. | namespace) + "/textures/" + (. | sub("(.*?)\\:"; "")) + ".png")) as $inp | [(.[1] | (map(if intersects(.;$inp) then . else empty end)[])) as $entry | .[1] | to_entries[] | select(.value == $entry).key][0] // 0' ${file} union_atlas.temp)
else
local atlas_index=0
fi
status_message process "Starting conversion of model with GeyserID ${gid}" status_message process "Starting conversion of model with GeyserID ${gid}"
jq --slurpfile atlas spritesheet.json --arg generated "${generated}" --arg binding "c.item_slot == 'head' ? 'head' : q.item_slot_to_bone_name(c.item_slot)" --arg model_name "${gid}" -c ' jq --slurpfile atlas spritesheet/${atlas_index}.json --arg generated "${generated}" --arg binding "c.item_slot == 'head' ? 'head' : q.item_slot_to_bone_name(c.item_slot)" --arg model_name "${gid}" -c '
.textures as $texture_list | .textures as $texture_list |
def namespace: if contains(":") then sub("\\:(.+)"; "") else "minecraft" end; def namespace: if contains(":") then sub("\\:(.+)"; "") else "minecraft" end;
def totexture($input): ($texture_list[($input[1:])]? // ([$texture_list[]][0])); def totexture($input): ($texture_list[($input[1:])]? // ([$texture_list[]][0]));
def topath($input): ("./assets/" + ($input | namespace) + "/textures/" + ($input | sub("(.*?)\\:"; "")) + ".png"); def topath($input): ("./assets/" + ($input | namespace) + "/textures/" + ($input | sub("(.*?)\\:"; "")) + ".png");
def texturedata($input): $atlas[] | .frames | (.[topath(totexture($input))] // ."./assets/minecraft/textures/0.png"); def texturedata($input): $atlas[] | .frames | (.[topath(totexture($input))] // ."./assets/minecraft/textures/0.png");
def roundit: (.*10000 | round) / 10000; def roundit: (.*10000 | round) / 10000;
def element_array: def element_array:
if .elements then (.elements | map({ if .elements then (.elements | map({
"origin": [((-.to[0] + 8) | roundit), ((.from[1]) | roundit), ((.from[2] - 8) | roundit)], "origin": [((-.to[0] + 8) | roundit), ((.from[1]) | roundit), ((.from[2] - 8) | roundit)],
@@ -624,7 +595,6 @@ do
}) })
}) | walk( if type == "object" then with_entries(select(.value != null)) else . end)) else {} end }) | walk( if type == "object" then with_entries(select(.value != null)) else . end)) else {} end
; ;
def pivot_groups: def pivot_groups:
if .elements then ((element_array) as $element_array | if .elements then ((element_array) as $element_array |
[[.elements[].rotation] | unique | .[] | select (.!=null)] [[.elements[].rotation] | unique | .[] | select (.!=null)]
@@ -638,7 +608,6 @@ do
"cubes": [($element_array | .[] | select(.rotation == $i_rot and .pivot == $i_piv))] "cubes": [($element_array | .[] | select(.rotation == $i_rot and .pivot == $i_piv))]
}))) else {} end }))) else {} end
; ;
{ {
"format_version": "1.16.0", "format_version": "1.16.0",
"minecraft:geometry": [{ "minecraft:geometry": [{
@@ -793,7 +762,7 @@ do
# generate our bp block definition if this is a 3D item # generate our bp block definition if this is a 3D item
if [[ ${generated} = false ]] if [[ ${generated} = false ]]
then then
jq -c -n --arg block_material "${block_material}" --arg geyser_id "${gid}" ' jq -c -n --arg atlas_index "${atlas_index}" --arg block_material "${block_material}" --arg geyser_id "${gid}" '
{ {
"format_version": "1.16.100", "format_version": "1.16.100",
"minecraft:block": { "minecraft:block": {
@@ -803,7 +772,7 @@ do
"components": { "components": {
"minecraft:material_instances": { "minecraft:material_instances": {
"*": { "*": {
"texture": "gmdl_atlas", "texture": ("gmdl_atlas_" + $atlas_index),
"render_method": $block_material, "render_method": $block_material,
"face_dimming": false, "face_dimming": false,
"ambient_occlusion": false "ambient_occlusion": false
@@ -845,7 +814,7 @@ do
fi fi
# generate our rp attachable definition # generate our rp attachable definition
jq -c -n --arg generated "${generated}" --arg attachable_material "${attachable_material}" --arg v_main "v.main_hand = c.item_slot == 'main_hand';" --arg v_off "v.off_hand = c.item_slot == 'off_hand';" --arg v_head "v.head = c.item_slot == 'head';" --arg model_name "${gid}" ' jq -c -n --arg generated "${generated}" --arg atlas_index "${atlas_index}" --arg attachable_material "${attachable_material}" --arg v_main "v.main_hand = c.item_slot == 'main_hand';" --arg v_off "v.off_hand = c.item_slot == 'off_hand';" --arg v_head "v.head = c.item_slot == 'head';" --arg model_name "${gid}" '
{ {
"format_version": "1.10.0", "format_version": "1.10.0",
@@ -857,7 +826,7 @@ do
"enchanted": $attachable_material "enchanted": $attachable_material
}, },
"textures": { "textures": {
"default": (if $generated == "true" then ("textures/geyser/geyser_custom/" + $model_name) else "textures/geyser/geyser_custom/gmdl_atlas" end), "default": (if $generated == "true" then ("textures/geyser/geyser_custom/" + $model_name) else ("textures/geyser/geyser_custom/" + $atlas_index) end),
"enchanted": "textures/misc/enchanted_item_glint" "enchanted": "textures/misc/enchanted_item_glint"
}, },
"geometry": { "geometry": {
@@ -974,7 +943,7 @@ fi
# cleanup # cleanup
status_message critical "Deleting scratch files" status_message critical "Deleting scratch files"
rm -rf assets && rm -f pack.mcmeta && rm -f pack.png && rm -f parents.json && rm -f all.csv && rm -f pa.csv && rm -f *.temp && rm -f spritesheet.json rm -rf spritesheet && rm -rf assets && rm -f pack.mcmeta && rm -f pack.png && rm -f parents.json && rm -f all.csv && rm -f pa.csv && rm -f *.temp && rm -f item_mappings.json && rm -f item_texture.json
#status_message critical "Deleting unused entries from config" #status_message critical "Deleting unused entries from config"
# jq 'map_values(del(.path, .element_parent, .parent, .geyserID))' config.json | sponge config.json # jq 'map_values(del(.path, .element_parent, .parent, .geyserID))' config.json | sponge config.json
@@ -987,8 +956,9 @@ jq '
{ {
"name": .key, "name": .key,
"allow_offhand": true, "allow_offhand": true,
"icon": (if .value.generated == "false" then .value.item else .key end) "icon": (if .value.generated == "false" then .value.item else .value.bedrock_icon.icon end)
} }
+ (if .value.nbt.generated then {"frame": (.value.bedrock_icon.frame)} else {} end)
+ (if .value.nbt.CustomModelData then {"custom_model_data": (.value.nbt.CustomModelData)} else {} end) + (if .value.nbt.CustomModelData then {"custom_model_data": (.value.nbt.CustomModelData)} else {} end)
+ (if .value.nbt.Damage then {"damage_predicate": (.value.nbt.Damage)} else {} end) + (if .value.nbt.Damage then {"damage_predicate": (.value.nbt.Damage)} else {} end)
+ (if .value.nbt.Unbreakable then {"unbreakable": (.value.nbt.Unbreakable)} else {} end) + (if .value.nbt.Unbreakable then {"unbreakable": (.value.nbt.Unbreakable)} else {} end)