#!/usr/bin/env bash

# Minecraft 1.12.2 Kozem server launcher.

set -uo pipefail

# === Paths ===
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
SERVER_DIR="${KOZEM_SERVER_DIR:-${SCRIPT_DIR}}"
JAR_FILE="${KOZEM_SERVER_JAR:-forge-1.12.2-14.23.5.2864.jar}"
LONGSNAP_FILE="${KOZEM_LONGSNAP_JAR:-longsnap.jar}"
RESTART_MARKER=".kozem-restart-requested"

# Prefer an explicit Java executable, then JAVA_HOME, then macOS's Java 8
# locator, and finally the java available on PATH.
if [[ -n "${KOZEM_JAVA:-}" ]]; then
  JAVA_CMD="${KOZEM_JAVA}"
elif [[ -n "${JAVA_HOME:-}" && -x "${JAVA_HOME}/bin/java" ]]; then
  JAVA_CMD="${JAVA_HOME}/bin/java"
elif [[ -x /usr/libexec/java_home ]]; then
  MAC_JAVA_HOME="$(/usr/libexec/java_home -v 1.8 2>/dev/null || true)"
  if [[ -n "${MAC_JAVA_HOME}" && -x "${MAC_JAVA_HOME}/bin/java" ]]; then
    JAVA_CMD="${MAC_JAVA_HOME}/bin/java"
  else
    JAVA_CMD="$(command -v java || true)"
  fi
else
  JAVA_CMD="$(command -v java || true)"
fi

# === Memory ===
MIN_RAM="4G"
MAX_RAM="10G"

# === Java 8 / G1GC settings ===
JAVA_FLAGS=(
  "-Xms${MIN_RAM}"
  "-Xmx${MAX_RAM}"

  "-XX:+UnlockExperimentalVMOptions"
  "-XX:+UseG1GC"
  "-XX:+ParallelRefProcEnabled"
  "-XX:MaxGCPauseMillis=100"
  "-XX:+DisableExplicitGC"
  "-XX:+AlwaysPreTouch"

  # This large 1.12.2 modpack compiles enough methods to fragment Java 8's
  # default 128 MiB code cache during long uptimes. Once full, HotSpot disables
  # JIT compilation and server tick costs rise across every dimension.
  "-XX:ReservedCodeCacheSize=256M"
  "-XX:+UseCodeCacheFlushing"

  "-XX:G1NewSizePercent=20"
  "-XX:G1MaxNewSizePercent=40"
  "-XX:G1ReservePercent=20"
  "-XX:G1HeapWastePercent=5"
  "-XX:G1MixedGCCountTarget=4"
  "-XX:InitiatingHeapOccupancyPercent=20"
  "-XX:G1MixedGCLiveThresholdPercent=90"

  "-XX:+ExitOnOutOfMemoryError"
  "-Dfile.encoding=UTF-8"
  # Forge 1.12 enables its DEBUG/TRACE file appender by default. Leak
  # diagnostics are promoted to WARN by TorgoCore and remain in latest.log.
  "-Dforge.logging.debugFile.level=off"

  "-Xloggc:logs/gc.log"
  "-XX:+PrintGCDetails"
  "-XX:+PrintGCDateStamps"
  "-XX:+PrintTenuringDistribution"
  "-XX:+UseGCLogFileRotation"
  "-XX:NumberOfGCLogFiles=5"
  "-XX:GCLogFileSize=20M"
)

cd "${SERVER_DIR}" || {
  echo "ERROR: Unable to enter ${SERVER_DIR}"
  exit 1
}

mkdir -p logs

if [[ ! -x "${JAVA_CMD}" ]]; then
  echo "ERROR: Java executable is unavailable: ${JAVA_CMD}"
  exit 1
fi
if [[ ! -f "${LONGSNAP_FILE}" ]]; then
  echo "ERROR: Longsnap is unavailable: ${SERVER_DIR}/${LONGSNAP_FILE}"
  exit 1
fi

# Remove an incomplete temporary marker or a marker left from a previous
# launcher invocation. This invocation is already performing the restart.
rm -f "${RESTART_MARKER}" "${RESTART_MARKER}.tmp"

echo "Using Java:"
JAVA_VERSION_OUTPUT="$("${JAVA_CMD}" -version 2>&1)"
echo "${JAVA_VERSION_OUTPUT}"
if [[ "${JAVA_VERSION_OUTPUT}" != *'version "1.8.'* ]]; then
  echo "ERROR: Kozem Minecraft 1.12.2 requires Java 8. Set KOZEM_JAVA to a Java 8 executable."
  exit 1
fi

while true; do
  echo "============================================================"
  echo "Updating server with Longsnap"
  echo "============================================================"

  if ! "${JAVA_CMD}" -jar "${LONGSNAP_FILE}"; then
    echo "ERROR: Longsnap failed. The Minecraft server will not start."
    exit 1
  fi

  if [[ ! -f "${JAR_FILE}" ]]; then
    echo "ERROR: Forge server is unavailable after Longsnap: ${SERVER_DIR}/${JAR_FILE}"
    exit 1
  fi

  echo "============================================================"
  echo "Starting Minecraft 1.12.2 server"
  echo "Initial heap: ${MIN_RAM}"
  echo "Maximum heap: ${MAX_RAM}"
  echo "============================================================"

  "${JAVA_CMD}" "${JAVA_FLAGS[@]}" -jar "${JAR_FILE}" nogui
  SERVER_STATUS=$?

  if [[ -f "${RESTART_MARKER}" ]]; then
    rm -f "${RESTART_MARKER}" "${RESTART_MARKER}.tmp"

    echo "============================================================"
    echo "Queued restart detected."
    echo "Longsnap will update the server before it relaunches."
    echo "============================================================"

    continue
  fi

  echo "============================================================"
  echo "Server stopped without requesting an automatic restart."
  echo "Exit status: ${SERVER_STATUS}"
  echo "============================================================"

  exit "${SERVER_STATUS}"
done
