Skip to content

Instantly share code, notes, and snippets.

@Kas-tle
Last active January 22, 2023 02:45
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Kas-tle/89c6adc3e7901fbabd1b9f71d902d0a6 to your computer and use it in GitHub Desktop.
Save Kas-tle/89c6adc3e7901fbabd1b9f71d902d0a6 to your computer and use it in GitHub Desktop.
Merge GeyserOptionalPack With Existing Resource Pack
: ${1?'Please specify an input resource pack in the same directory as the script (e.g. ./merge.sh MyResourcePack.zip)'}
# ensure jq is installed
if command jq --version 2>/dev/null | grep -q "1.6"; then
printf "\e[32m[+]\e[m \e[37mDependency jq satisfied\e[m\n"
echo
else
echo "Dependency jq-1.6 is not satisfied"
echo "You must install jq-1.6 before proceeding"
echo "See https://stedolan.github.io/jq/download/"
echo "Exiting script..."
exit 1
fi
# ensure input pack exists
if ! test -f "${1}"; then
echo "Input resource pack ${1} is not in this directory"
echo "Please ensure you have entered the filename correctly"
exit 1
else
printf "\e[33m[•]\e[m \e[37mInput file ${1} detected\e[m\n"
echo
fi
# download optional pack
printf "\e[3m\e[37m"
wget -nv --show-progress -O GeyserOptionalPack.mcpack https://ci.opencollab.dev/job/GeyserMC/job/GeyserOptionalPack/job/master/lastSuccessfulBuild/artifact/GeyserOptionalPack.mcpack
printf "\e[m"
echo
printf "\e[32m[+]\e[m \e[37mOptional pack downloaded\e[m\n"
# decompress optional pack and place in correct directory
mkdir opt
printf "\e[33m[•]\e[m \e[37mDecompressing optional pack\e[m\n"
unzip -q -d opt GeyserOptionalPack.mcpack
printf "\e[32m[+]\e[m \e[37mOptional pack decompressed\e[m\n"
echo
rm opt/manifest.json
rm opt/pack_icon.png
# decompress input pack and place in correct directory
mkdir inp
printf "\e[33m[•]\e[m \e[37mDecompressing input pack\e[m\n"
echo
unzip -q -d inp ${1}
printf "\e[32m[+]\e[m \e[37mInput pack decompressed\e[m\n"
echo
# get data about entities in input and optional packs
printf "\e[33m[•]\e[m \e[37mListing entities of optional pack\e[m\n"
jq -n '[inputs | {(."minecraft:client_entity".description.identifier): (input_filename)}] | add' $(find opt/entity -type f -name "*.json") > opt_entities.json
printf "\e[33m[•]\e[m \e[37mListing entities of input pack\e[m\n"
jq -n '[inputs | {(."minecraft:client_entity".description.identifier): (input_filename)}] | add' $(find inp/entity -type f -name "*.json") > inp_entities.json
# get identifiers of duplicate entities
printf "\e[33m[•]\e[m \e[37mListing duplicate entities\e[m\n"
duplicates=( $(jq -rs '(.[1] | keys) - ((.[1] | keys) - (.[0] | keys)) | .[]' opt_entities.json inp_entities.json) )
echo
printf "\e[33m[•]\e[m \e[37mBeginning duplicate entity merging\e[m\n"
echo
# iterate over duplicate entities
for i in ${duplicates[@]}
do
printf "\e[33m[•]\e[m \e[37mMerging entity ${i}\e[m\n"
# get input and optional pack duplicate entities
inp_file=$(jq -r --arg input ${i} '.[$input]' inp_entities.json)
opt_file=$(jq -r --arg input ${i} '.[$input]' opt_entities.json)
# merge duplicate entities
jq -s '
def meld(a; b):
a as $a | b as $b
| if ($a|type) == "object" and ($b|type) == "object"
then reduce ([$a,$b]|add|keys_unsorted[]) as $k ({};
.[$k] = meld( $a[$k]; $b[$k]) )
elif ($a|type) == "array" and ($b|type) == "array"
then $a+$b | unique
elif $b == null then $a
else $b
end;
meld(.[0]; .[1])
' ${inp_file} ${opt_file} > temp && mv temp ${inp_file} && rm ${opt_file}
printf "\e[32m[+]\e[m \e[37mMerge complete for ${i}\e[m\n"
echo
done
printf "\e[32m[+]\e[m \e[37mMerged all duplicate entities\e[m\n"
echo
printf "\e[33m[•]\e[m \e[37mBeginning file merging\e[m\n"
echo
# merge packs without overwrite
cd opt && opt_files=( $(find * -type f) ) && cd ..
for file in ${opt_files[@]}
do
if [[ -f inp/${file} ]]
then
mkdir -p inp/${file%/*} 2>/dev/null && cp opt/${file} inp/${file%.*}_opt.${file##*.}
printf "\e[32m[+]\e[m \e[37mCopied /opt/${file} to /inp/${file%.*}_opt.${file##*.}\e[m\n"
echo ${file%.*}_opt.${file##*.} >> duplicate_files.log
else
mkdir -p inp/${file%/*} 2>/dev/null && cp opt/$file inp/${file}
printf "\e[32m[+]\e[m \e[37mCopied /opt/${file} to /inp/${file}\e[m\n"
fi
done
echo
printf "\e[32m[+]\e[m \e[37mCopied all files to input pack\e[m\n"
echo
# cleanup
printf "\e[31m[X]\e[m \e[37mDeleting scratch files\e[m\n"
rm -rf opt && rm GeyserOptionalPack.mcpack && rm inp_entities.json && rm opt_entities.json
# compress input pack
printf "\e[33m[•]\e[m \e[37mCompressing output packs\e[m\n"
mkdir target
cd inp > /dev/null && zip -rq8 ${1} . -x "*/.*" && cd - > /dev/null && mv inp/${1} target/${1%.*}_opt.${1##*.}
rm -rf inp
echo
printf "\e[32m[+]\e[m \e[1m\e[37mMerge Process Complete\e[m\n"
echo
printf "\e[37mExiting...\e[m\n"
echo
@Kas-tle
Copy link
Author

Kas-tle commented Apr 28, 2021

Information and Usage

This script combines an input resource pack and GeyserOptionalPack. This should only be used if your pack makes edits to the same entities as GeyserOptionalPack. Use as follows from a directory containing your input pack and the script:

chmod 755 merge.sh
./merge.sh input.mcpack

Entities should merge automatically using jq. Any remaining duplicate filenames will be logged to duplicate_files.log and placed in the merged pack with the suffix _opt. You should manually review these for potential conflicts. Special attention should be given to render controllers with the same identifier, which are not currently handled by this script.

Dependencies

  • jq (1.6+)
  • zip
  • unzip

Dependency Installation

Debian, Ubuntu, & Mint

sudo apt-get install jq unzip zip

MacOS

brew install jq unzip zip

RHEL, Fedora, & Centos

sudo yum install jq unzip zip

Arch Linux

sudo pacman -S jq unzip zip

Windows

Impossible; consider WSL.

Special Notes for WSL

In general, packages on WSL seem to be a little wonky, and sometimes jq-1.5 will be installed, which will not work. To manually install jq-1.6 on WSL, at least for Ubuntu:

wget https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 && sudo chmod +x jq-linux64 && sudo mv jq-linux64 /usr/bin/jq

@BurntRanch
Copy link

why is this an SH script when bedrock isnt for linux

@Kas-tle
Copy link
Author

Kas-tle commented Sep 21, 2021

why is this an SH script when bedrock isnt for linux

@newbies155 because I use Linux and MacOS. If you'd like to develop a solution for your own platform, feel free.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment