Knowledge Base

Preserving for the future: Shell scripts, AoC, and more

Lego Universe autologin

I got tired of my Lego Universe game crashing, and having to type my username/password in again. This is not a shared machine, so I wrote a small utility to handle logging in for me.

The first time you use it, it will prompt for username and password. You can trigger this prompting again with parameter --login.

To simulate the clicks and key presses, use parameter --apply.

files/2024/listings/autologin-lego-universe.sh (Source)

#!/bin/sh
# File: autologin-lego-universe.sh
# Location: /mnt/public/Games/lego-universe/
# Author: bgstack15
# SPDX-License-Identifier: GPL-3.0-only
# Startdate: 2024-10-07-2 15:26
# Title Autologin for Lego Universe client
# Purpose: Given a username and password, auto log in to the Lego Universe/Darkflame client
# History:
# Usage:
#    Env vars:
#       APPLY
#    Parameters:
#       --login Change username and password in conf file
#       --apply Actually run automation
# Reference:
#    https://stackoverflow.com/questions/2683279/how-to-detect-if-a-script-is-being-sourced/28776166#28776166
#    man xdotool, yad
# Improve:
#    This is slightly buggy. The longer the delays in typing and between tasks, the better it runs.
#    This is only tested against 1920x1080
# Dependencies:
#    dep-devuan: xdotool, yad
#    Lego Universe already running! This script does not know how long it takes to load the username prompt in the game.
# Documentation:
# variables
CONFFILE=~/.config/autologin-lego-universe.conf
autologin_lego_universe() {
   # pixel offset, only tested against 1920x1080
   _type_delay_ms=60
   _step_delay_s=0.3
   _y_offset_username_field=50
   _loop_max_safety=10
   _tmpfile1="$( mktemp )" ; rm "${_tmpfile1}"
   # needs env vars: USERNAME, PASSWORD
   # step 0: find window that matters
   _x=0
   while test ! -f "${_tmpfile1}" ;
   do
      printf '%s ' "Loop ${_x}" 1>&2
      WINDOWID="$( xdotool search "Lego Universe - " )"
      test -n "${WINDOWID}" && touch "${_tmpfile1}"
      sleep 0.5 ;
      _x=$(( _x + 1 ))
      test ${_x} -ge ${_loop_max_safety} && { echo "Fatal! Safety valve: could not find game window after 20 loops. Aborting." 1>&2 ; rm -f "${_tmpfile1:-NOTHINGTODEL}" 1>/dev/null 2>&1 ; return 1 ; }
   done
   echo "Found WINDOWID=${WINDOWID}"
   rm -f "${_tmpfile1:-NOTHINGTODEL}"
   # step 0: bring game window to top. This does not work for me, but maybe it works for somebody else.
   xdotool windowactivate --window "${WINDOWID}" windowfocus --window "${WINDOWID}"
   # step 1: move mouse to username field
   xdotool mousemove --window "${WINDOWID}" $(( 1920 / 2 )) $(( 1080 / 2 - ${_y_offset_username_field} ))
   # step 2: enter username
   xdotool click 1 sleep "${_step_delay_s}" click 1 key ctrl+a type --delay "${_type_delay_ms}" "${USERNAME}"
   # step 3: move to password field
   xdotool sleep "${_step_delay_s}" key Tab
   # step 4: enter password
   xdotool sleep "${_step_delay_s}" sleep "${_step_delay_s}" type --delay "${_type_delay_ms}" "${PASSWORD}"
   # step 5: press enter
   xdotool sleep "${_step_delay_s}" key Return
}
save_field() {
   # usage: save_field USERNAME
   _field="${1}"
   # no error handling. Do not mess up save_field!
   case "${_field}" in
      USERNAME)
         _yad_opts='--text Username'
         _default="${USERNAME}"
         ;;
      PASSWORD)
         _yad_opts='--hide-text --text Password'
         set -x
         _default="${PASSWORD}"
         ;;
      *)
         echo "Error! save_field ${@} is invalid. Needs USERNAME or PASSWORD. Continuing..." 1>&2
         return 1
         ;;
   esac
   # do not quote _yad_opts on next line.
   result="$( yad ${_yad_opts} --entry --entry-text "${_default}" --title "Autologin for Lego Universe" )"
   _response_code=$?
   # write to file
   if test 0 -eq ${_response_code} ;
   then
      sed -i -r -e "/^${_field}=/d" "${CONFFILE}"
      echo "${_field}=\"${result}\"" >> "${CONFFILE}"
   else
      yad --text "Action cancelled."
   fi
   set +x
   unset _default _response_code
}
# if dot-sourced, run main
# BEGIN IF-DOT-SOURCED, so 2683279
sourced=0
if [ -n "$ZSH_VERSION" ]; then
  case $ZSH_EVAL_CONTEXT in *:file) sourced=1;; esac
elif [ -n "$KSH_VERSION" ]; then
  [ "$(cd -- "$(dirname -- "$0")" && pwd -P)/$(basename -- "$0")" != "$(cd -- "$(dirname -- "${.sh.file}")" && pwd -P)/$(basename -- "${.sh.file}")" ] && sourced=1
elif [ -n "$BASH_VERSION" ]; then
  (return 0 2>/dev/null) && sourced=1
else # All other shells: examine $0 for known shell binary filenames.
  # Detects `sh` and `dash`; add additional shell filenames as needed.
  case ${0##*/} in sh|-sh|dash|-dash) sourced=1;; esac
fi
# END IF-DOT-SOURCED
if test "${sourced}" = "0" ;
then
   test -f "${CONFFILE}" && . "${CONFFILE}"
   unset _reload
   if test -z "${USERNAME}" || echo " ${@} " | grep -qE " --login " ; then save_field USERNAME ; _reload=1 ; fi
   if test -z "${PASSWORD}" || echo " ${@} " | grep -qE " --login " ; then save_field PASSWORD ; _reload=1 ; fi
   echo " ${@} " | grep -qE " --apply " && APPLY=1
   test -n "${_reload}" && test -f "${CONFFILE}" && . "${CONFFILE}"
   # If you want to be more basic:
   #test -z "${USERNAME}" && { echo "Fatal! Need env var USERNAME. Aborted." 1>&2 ; exit 1 ; }
   #test -z "${PASSWORD}" && { echo "Fatal! Need env var PASSWORD. Aborted." 1>&2 ; exit 1 ; }
   unset _reload
   test -n "${APPLY}" && autologin_lego_universe ;
fi

And you can set your desktop shortcut to run this script then:

files/2024/listings/run-lego-universe-and-autologin.sh (Source)

#!/bin/sh
# Startdate: 2024-10-08-3 14:30
# Purpose: run Lego Universe, and then wait a few seconds, and then auto login.
legouniverse_script="$( find ~/.wine* -iname lego-universe.sh -print -quit )"
"${legouniverse_script}" &
# Hopefully this is long enough
sleep 10
# This if-dot-sourcing does not work so just go ahead and call it dot-sourced and then call the relevant function.
. /mnt/public/Games/lego-universe/autologin-lego-universe.sh
autologin_lego_universe

Comments