#!/usr/sbin/env bash # Disables warning about echo not expanding escape sequences # shellcheck disable=SC2028 # Used for internal errors function internal_error() { echo "-> INTERNAL ERROR: ${*}" exit 99 } # Automatically accepts the End User License Agreement function accept_eula() { echo "eula=true" > /data/eula.txt } # Cleans /logs and /crash-reports function clean_logs() { if [ "${MCSD_CLEAN_LOGS}" == "true" ]; then rm -rf "/data/logs" "/data/crash-reports" fi } # Used by trap, shuts the server down function kill_server() { if [ -z "${CHILDPID}" ]; then internal_error "\$CHILDPID is unset" fi export "SHUTDOWN=true" kill -INT "${CHILDPID}" } # Print the MCSD banner function print_banner() { echo " ____ ____ ____ __" echo " /'\\_/\`\\/\\ _\`\\ /\\ _\`\\ /\\ _\`\\ /\\ \\" echo "/\\ \\ \\ \\/\\_\\\\ \\,\\L\\_\\ __ _ __ __ __ __ _ __\\ \\ \\/\\ \\ ___ ___\\ \\ \\/'\\ __ _ __" echo "\\ \\ \\__\\ \\ \\ \\/_/_\\/_\\__ \\ /'__\`\\/\\\`'__\\/\\ \\/\\ \\ /'__\`\\/\\\`'__\\ \\ \\ \\ \\ / __\`\\ /'___\\ \\ , < /'__\`\\/\\\`'__\\" echo " \\ \\ \\_/\\ \\ \\ \\L\\ \\ /\\ \\L\\ \\/\\ __/\\ \\ \\/ \\ \\ \\_/ |/\\ __/\\ \\ \\/ \\ \\ \\_\\ \\/\\ \\L\\ \\/\\ \\__/\\ \\ \\\\\`\\ /\\ __/\\ \\ \\/" echo " \\ \\_\\\\ \\_\\ \\____/ \\ \`\\____\\ \\____\\\\ \\_\\ \\ \\___/ \\ \\____\\\\ \\_\\ \\ \\____/\\ \\____/\\ \\____\\\\ \\_\\ \\_\\ \\____\\\\ \\_\\" echo " \\/_/ \\/_/\\/___/ \\/_____/\\/____/ \\/_/ \\/__/ \\/____/ \\/_/ \\/___/ \\/___/ \\/____/ \\/_/\\/_/\\/____/ \\/_/" } # Initialize MCSD function initialize() { echo ":: Initializing MCSD" # Server arguments if [ ! "${MCSD_ENFORCE_FRESH_CACHES}" == "true" ] && [ ! "${MCSD_ENFORCE_FRESH_CACHES}" == "false" ]; then echo ":: Warning: No/Invalid value supplied to \$MCSD_ENFORCE_FRESH_CACHES, defaulting to false" export "MCSD_ENFORCE_FRESH_CACHES=false" fi if [ ! "${MCSD_FORCE_UPGRADE}" == "true" ] && [ ! "${MCSD_FORCE_UPGRADE}" == "false" ]; then echo ":: Warning: No/Invalid value supplied to \$MCSD_FORCE_UPGRADE, defaulting to true" export "MCSD_FORCE_UPGRADE=true" fi if [ ! "${MCSD_SAFEMODE}" == "true" ] && [ ! "${MCSD_SAFEMODE}" == "false" ]; then echo ":: Warning: No/Invalid value supplied to \$MCSD_SAFEMODE, defaulting to false" export "MCSD_SAFEMODE=false" fi # MCSD functionality if [ ! "${MCSD_CLEAN_LOGS}" == "true" ] && [ ! "${MCSD_CLEAN_LOGS}" == "false" ]; then echo ":: Warning: No/Invalid value supplied to \$MCSD_CLEAN_LOGS, defaulting to false" export "MCSD_CLEAN_LOGS=false" fi # Memory limits if [ -z "${MCSD_MEMORY_MIN}" ]; then echo ":: Error: No memory limit supplied to \$MCSD_MEMORY_MIN" exit 1 fi if [ -z "${MCSD_MEMORY_MAX}" ]; then echo ":: Error: No memory limit supplied to \$MCSD_MEMORY_MAX" exit 1 fi # Java version if [ ! "${MCSD_JAVA_VERSION}" == "21" ] && [ ! "${MCSD_JAVA_VERSION}" == "17" ] && [ ! "${MCSD_JAVA_VERSION}" == "11" ] && [ ! "${MCSD_JAVA_VERSION}" == "8" ]; then echo ":: Warning: No/Invalid java version supplied to \$MCSD_JAVA_VERSION, defaulting to java version 17" export "MCSD_JAVA_VERSION=17" fi # Java custom JVM if [ ! "${MCSD_JAVA_CUSTOM}" == "true" ] && [ ! "${MCSD_JAVA_CUSTOM}" == "false" ]; then echo ":: Warning: No/Invalid value supplied to \$MCSD_JAVA_CUSTOM, defaulting to false" export "MCSD_JAVA_CUSTOM=false" fi # Java optimization if [ ! "${MCSD_OPTIMIZED_FLAGS}" == "true" ] && [ ! "${MCSD_OPTIMIZED_FLAGS}" == "false" ]; then echo ":: Warning: No/Invalid value supplied to \$MCSD_OPTIMIZED_FLAGS, defaulting to true" export "MCSD_OPTIMIZED_FLAGS=true" fi if [ ! "${MCSD_GARBAGECOLLECTOR}" == "G1GC" ] && [ ! "${MCSD_GARBAGECOLLECTOR}" == "ZGC" ]; then echo ":: Warning: No/Invalid value supplied to \$MCSD_GARBAGECOLLECTOR, defaulting to G1GC" export "MCSD_GARBAGECOLLECTOR=G1GC" fi } # Check for directories and files function check() { echo ":: Checking environment" if [ ! -d "/data" ]; then echo ":: Error: Could not locate /data directory" exit 1 fi if [ ! -f "/data/server.jar" ]; then echo ":: Error: Could not locate server.jar" exit 1 fi } # Compile server arguments function compile_args() { echo ":: Compiling server arguments" export "ARGS=--nogui" case "${MCSD_ENFORCE_FRESH_CACHES}" in "true") export "ARGS=${ARGS} --eraseCache" ;; "false") ;; *) internal_error "\$MCSD_ENFORCE_FRESH_CACHES has invalid value" ;; esac case "${MCSD_FORCE_UPGRADE}" in "true") export "ARGS=${ARGS} --forceUpgrade" ;; "false") ;; *) internal_error "\$MCSD_FORCE_UPGRADE has invalid value" ;; esac case "${MCSD_SAFEMODE}" in "true") export "ARGS=${ARGS} --safeMode" ;; "false") ;; *) internal_error "\$MCSD_SAFEMODE has invalid value" ;; esac } # Compile java flags function compile_flags() { echo ":: Compiling java flags" if [ "${MCSD_JAVA_CUSTOM}" == "true" ]; then if [ -f "/jvm/bin/java" ]; then export "JAVA_HOME=/jvm" else echo ":: Error: /jvm/bin/java not found, using built-in JVM" export "JAVA_HOME=/usr/lib/jvm/java-${MCSD_JAVA_VERSION}-openjdk" fi else export "JAVA_HOME=/usr/lib/jvm/java-${MCSD_JAVA_VERSION}-openjdk" fi export "FLAGS=-Xms${MCSD_MEMORY_MIN} -Xmx${MCSD_MEMORY_MAX}" case "${MCSD_OPTIMIZED_FLAGS}" in "true") export "FLAGS=${FLAGS} -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3" ;; "false") ;; *) internal_error "\$MCSD_OPTIMIZED_FLAGS has invalid value" ;; esac case "${MCSD_GARBAGECOLLECTOR}" in "G1GC") export "FLAGS=${FLAGS} -XX:+UseG1GC -XX:MaxGCPauseMillis=130 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=28 -XX:G1HeapRegionSize=16M -XX:G1ReservePercent=20 -XX:G1MixedGCCountTarget=3 -XX:InitiatingHeapOccupancyPercent=10 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=0 -XX:SurvivorRatio=32 -XX:MaxTenuringThreshold=1 -XX:G1SATBBufferEnqueueingThresholdPercent=30 -XX:G1ConcMarkStepDurationMillis=5 -XX:G1ConcRSHotCardLimit=16 -XX:G1ConcRefinementServiceIntervalMillis=150" ;; "ZGC") export "FLAGS=${FLAGS} -XX:+UseZGC -XX:AllocatePrefetchStyle=1 -XX:-ZProactive" ;; *) internal_error "\$MCSD_GARBAGECOLLECTOR has invalid value" ;; esac if [ "${MCSD_JAVA_VERSION}" == "17" ] || [ "${MCSD_JAVA_VERSION}" == "21" ]; then export "FLAGS=${FLAGS} --add-modules=jdk.incubator.vector" fi } print_banner initialize check accept_eula clean_logs compile_args compile_flags echo ":: Starting server" cd /data||exit 69 if [ -z "${MCSD_CUSTOM_ARGS}" ]; then exec "${JAVA_HOME}/bin/java" ${FLAGS} -jar "/data/server.jar" ${ARGS} else exec "${JAVA_HOME}/bin/java" ${MCSD_CUSTOM_ARGS} -jar "/data/server.jar" ${ARGS} fi