Code:
#!/bin/bash
#############################################################################
# General Information
#
# Command Line Interface launcher for Dungeons & Dragons online.
#
# To use this script, follow the instructions in the sections:
# 1) Create the script
# 2) Play the game
# 3) Optional: Personalize the script
#
# Note that this script cannot update the game. If it fails to work, run the
# original DDO Launcher to allow it to perform any pending updates first.
#
# (C) 2007-2011 SNy <SNy@bmx-chemnitz.de>
#
# AtomicMew 6/3/12
# -modded to take command line args and windoze use
#
# Kaytis 5/31/13 v 1.1
# -modded to work on Mac OS X
#
# Kaytis 2/18/15 v 1.2
# -updated to match new login protocols
#
# Kaytis 11/30/15 v 1.2.1
# -disabled peer verification to bypass invalid certificates
#
# Kaytis 4/4/19 v 1.3
# -simplified instructions
#
# Kaytis 10/19/19 v 1.4
# -added support for wine client
# -added support for command line arguments:
# -u username
# -p password
# -n subscription
# -w world
# -c character
#
# Kaytis 10/2/20 v 1.5
# -added support for Lamannia world
# -added support for 64-bit client
# -x64
#############################################################################
# Create the script
#
# 1) Open TextEdit, create a new document, and paste all of this text into it.
# 2) Select menu item "Format" > "Make Plain Text" (if you don't see this option, ignore this step).
# 3) Save the file as /Applications/DNDLauncher.sh
# 4) Open /Applications/Utilities/Terminal and type:
# chmod 755 /Applications/DNDLauncher.sh
# 5) Hit the return key to execute the command.
#############################################################################
# Play the game
#
# 1) Open /Applications/Utilities/Terminal
# 2) To start from the character selection screen, type:
# /Applications/DNDLauncher.sh -u username -p password -w world
# To start in world with a specific character type:
# /Applications/DNDLauncher.sh -u username -p password -w world -c character
# 3) Hit the return key to execute the command. The game will start.
#
# Handy tip: the up arrow will restore the last command you typed in the Terminal.
# Handy tip: you do not need to leave this file open after creating it.
#
# Note in certain circumstances, a subscription number is required. You can
# specify it using the -n parameter. If one is required, and it is not provided,
# the script will help you figure out what the number is so that it can be
# provided next time.
#############################################################################
# Parse the command line arguments.
#
# NOTE: If you don't personalize the script, you MUST provide at least the
# username, password and world on the command line.
# Version 1.4 and higher of this script can be customized in EXACTLY
# the same way as earlier versions, including personalizing it per character and
# invoking the script with just the character name (the "-c" is optional).
# If you want to personalize the script please skip to the
# "Personalize the script" section below.
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-u|--username)
ARG_USERNAME="$2"
shift # past argument
shift # past value
;;
-p|--password)
ARG_PASSWORD="$2"
shift # past argument
shift # past value
;;
-n|--subscription)
ARG_SUBSCRIPTION="$2"
shift # past argument
shift # past value
;;
-w|--world)
ARG_WORLD="$2"
shift # past argument
shift # past value
;;
-c|--character)
ARG_CHARACTER="$2"
shift # past argument
shift # past value
;;
-x64|--x64)
X64=YES
shift # past argument
;;
-h|--help)
HELP=YES
shift # past argument
;;
*) # unknown option -assume character name
ARG_CHARACTER="$1"
shift # past argument
;;
esac
done
#############################################################################
# Personalize the script
#
# Providing these values will allow you to go to the character select screen on
# a specific world without providing any arguments to the script. If you add a
# character name as an argument to the script, you will be taken straight to
# that character on the specified world.
#
# Optionally provide your username, password and primary world here. Note that
# if you choose to enter this information, you should NOT share this file with
# anyone. Note: arguments provided on the command line will override these
# values.
#
# 1) Fill in the following, by replacing,
# account_username_here,
# account_password_here, and
# world_name_here
# 2) When you are done typing the values, save the file. Don't share the
# file with anyone. Your password is in it.
username=account_username_here # Main account username. No spaces anywhere.
password=account_password_here # Main account password. No spaces anywhere.
subscription=0 # Main account subscription. Usually 0.
world=world_name_here # Main world name e.g. Orien. Capitalize the first letter!
#############################################################################
# Advanced instructions
#
# Providing values for:
# alt_account_character_name_here
# alt_account_username_here
# alt_account_password_here
# alt_world_name_here
# will allow you to go to a specific character on any account on any world by
# providing a character name as an argument to the script. The character name is
# used as a key to select the right account and world. You will typically just
# provide the character name and nothing else when multiboxing. Note: arguments
# provided on the command line will override these values.
#
# To play a character on an alternate account:
# 1) Open /Applications/Utilities/Terminal
# 2) Type:
# /Applications/DNDLauncher.sh alt_account_character_name
# 3) Hit the return key -a new copy of the game will start.
#
# Handy tip: you can have as many copies of the game open as you have alternate
# accounts. You can add more character names by duplicating an "elif" block.
if [ "${ARG_CHARACTER}" == "alt_account_character_name_here" ] ; then
username=alt_account_username_here # Alt account username
password=alt_account_password_here # Alt account password
subscription=0 # Alt account subscription. Usually 0
world=alt_world_name_here # Alt server name e.g. Orien
elif [ "${ARG_CHARACTER}" == "alt_account_character_name_here" ] ; then
username=alt_account_username_here # Alt account username
password=alt_account_password_here # Alt account password
subscription=0 # Alt account subscription. Usually 0
world=alt_world_name_here # Alt server name e.g. Orien
elif [ "${ARG_CHARACTER}" == "alt_account_character_name_here" ] ; then
username=alt_account_username_here # Alt account username
password=alt_account_password_here # Alt account password
subscription=0 # Alt account subscription. Usually 0
world=alt_world_name_here # Alt server name e.g. Orien
fi
#############################################################################
# Launcher script
if [ -n "${HELP}" ] ; then
echo ""
echo "A macOS command line launcher for DDO. Use this command for fast game launching"
echo "and multiboxing."
echo ""
echo "usage: DNDLauncher [-u username] [-p password] [-n subscription] [-w world] [-c character]"
echo ""
echo "-u username : account username"
echo "-p password : account password"
echo "-n subscription : account subscription. Usually 0. Omit if unknown."
echo "-w world : world e.g. Orien. Capitalize only the first letter"
echo "-c character : character to log in. '-c' is optional"
echo "-x64 : use 64-bit client"
echo ""
echo "Example:"
echo ""
echo " /Applications/DNDLauncher.sh -u my_account_name -p my_account_password -w Orien -c Kaytis"
echo ""
echo "or with appropriate script customization (see script for details):"
echo ""
echo " /Applications/DNDLauncher.sh -c Kaytis"
echo ""
exit 0
fi
# Snag the character name, if any, and stash it in the "character" variable.
character="${ARG_CHARACTER}"
# Apply overides
if [ -n "${ARG_USERNAME}" ] ; then
username="${ARG_USERNAME}"
fi
if [ -n "${ARG_PASSWORD}" ] ; then
password="${ARG_PASSWORD}"
fi
if [ -n "${ARG_SUBSCRIPTION}" ] ; then
subscription="${ARG_SUBSCRIPTION}"
fi
if [ -n "${ARG_WORLD}" ] ; then
world="${ARG_WORLD}"
fi
echo "-----------------------------------------------------------------------"
echo -e "Welcome to the CLI launcher for DDO for Mac OS X version 1.5"
echo "-----------------------------------------------------------------------"
exe() { echo "> $@" ; "$@" ; }
# Some common directories
gameCommon_DIR="$HOME/Library/Application Support/com.standingstonegames.ddo/common"
gameWineBin_DIR="$gameCommon_DIR/usr/bin"
gameWinePrefix_DIR="$gameCommon_DIR/wineprefix"
gameClient_DIR="$gameWinePrefix_DIR/drive_c/Program Files (x86)/StandingStoneGames/Dungeons & Dragons Online"
gameClient_EXE="C:/Program Files (x86)/StandingStoneGames/Dungeons & Dragons Online/dndclient.exe"
if [ -n "${X64}" ] ; then
gameClient_EXE="C:/Program Files (x86)/StandingStoneGames/Dungeons & Dragons Online/x64/dndclient64.exe"
fi
if [ "${world}" == "Lamannia" ] ; then
gameClient_DIR="$gameWinePrefix_DIR/drive_c/Program Files (x86)/StandingStoneGames/Dungeons & Dragons Online (Preview)"
gameClient_EXE="C:/Program Files (x86)/StandingStoneGames/Dungeons & Dragons Online (Preview)/dndclient.exe"
if [ -n "${X64}" ] ; then
gameClient_EXE="C:/Program Files (x86)/StandingStoneGames/Dungeons & Dragons Online (Preview)/x64/dndclient64.exe"
fi
fi
# make this script be callable from elsewhere (desktop shortcuts etc)
oldDir=`pwd`
# change directory to where the launcher resources reside
cd "${gameClient_DIR}"
# cleanup temp directory for configuration files downloaded from the official servers
rm -rf .launcher
mkdir .launcher
echo "Reading game configuration..."
# Get Game and DataCenter settings from launcher config file.
configFile="ddo.launcherconfig"
if ! [ -r "${configFile}" ] ; then
echo -e "\nError: ${configFile} cannot be read.\n"
cd "${oldDir}"
exit
fi
game=`grep -h "DataCenter.GameName" "${configFile}" | grep -v '<!--.*-->' | sed -e "s/^.*value=\"\([^\"]*\)\".*$/\1/"`
glsDataCenter_URL=`grep -h "Launcher.DataCenterService.GLS" "${configFile}" | grep -v '<!--.*-->' | sed -e "s/^.*value=\"\([^\"]*\)\".*$/\1/"`
echo "Game Name: ${game}"
echo "Game Login Server: ${glsDataCenter_URL}"
echo "-----------------------------------------------------------------------"
# get configuration info (xml-file containing auth, patch and game servers with their corresponding settings)
# NOTE: while a normal HTTP GET to /GLS.DataCenterServer/Service.asmx/GetDatacenters?game=LOTROEU
# works fine for the european datacenter, it does not work for the US/AU/... LOTRO one
# instead, we need to send a SOAP request there, ending up with a SOAP answer (no whitespace whatsoever)
# now, to have at least some whitespace we can deal with, sed is used to insert a newline after each closing xml tag below
echo "Querying Game Login Server..."
# wget \
# --no-check-certificate -q \
# --header 'Content-Type: text/xml; charset=utf-8' \
# --header 'SOAPAction: "http://www.turbine.com/SE/GLS/GetDatacenters"' \
# --post-data "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><GetDatacenters xmlns=\"http://www.turbine.com/SE/GLS\"><game>${game}</game></GetDatacenters></soap:Body></soap:Envelope>" \
# "${glsDataCenter_URL}" -O .launcher/GLSDataCenter.config
curl --silent \
--insecure \
--header 'Content-Type: text/xml; charset=utf-8' \
--header 'SOAPAction: "http://www.turbine.com/SE/GLS/GetDatacenters"' \
--data "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><GetDatacenters xmlns=\"http://www.turbine.com/SE/GLS\"><game>${game}</game></GetDatacenters></soap:Body></soap:Envelope>" \
"${glsDataCenter_URL}" \
--output .launcher/GLSDataCenter.config
if ! [ -r .launcher/GLSDataCenter.config ] ; then
echo -e "\nError: Could not fetch GLS data center configuration.\n"
cd "${oldDir}"
exit
fi
# Format the response by adding new lines after the closing xml tags.
sed -e "s#\(</[^>]*>\)#\1_make_newline_#g" -i "" .launcher/GLSDataCenter.config
awk '{ gsub(/_make_newline_/,"\n",$0); print }' .launcher/GLSDataCenter.config >> .launcher/GLSDataCenter.config.tmp
rm -f .launcher/GLSDataCenter.config
mv .launcher/GLSDataCenter.config.tmp .launcher/GLSDataCenter.config
# Grab only the first DataCenter.
echo -e "<!--\n NOTE\n This file is NOT a valid XML file!\n-->" >> .launcher/GLSDataCenter.config."${game}"
cat .launcher/GLSDataCenter.config | sed -n -e "/^.*<Datacenter><Name>${game}<\/Name>/,/<\/Datacenter>.*$/ p" >> .launcher/GLSDataCenter.config."${game}"
# Extract global server URLs
patchServer_ADR=`grep -h "<PatchServer>" .launcher/GLSDataCenter.config.${game} | grep -v '<!--.*-->' | sed -e "s/^.*<PatchServer>//;s/<\/PatchServer>.*$//"`
launcherCfg_URL=`grep -h "<LauncherConfigurationServer>" .launcher/GLSDataCenter.config.${game} | grep -v '<!--.*-->' | sed -e "s/^.*<LauncherConfigurationServer>//;s/<\/LauncherConfigurationServer>.*$//"`
authServer_URL=`grep -h "<AuthServer>" .launcher/GLSDataCenter.config.${game} | grep -v '<!--.*-->' | sed -e "s/^.*<AuthServer>//;s/<\/AuthServer>.*$//"`
# Extract world specific server URLs
serverChat_URL=`grep -h -A 4 "<World>" .launcher/GLSDataCenter.config.${game} | grep -F -A 3 "${world}" | grep -h "<ChatServerUrl>" | grep -v '<!--.*-->' | sed -e "s/^.*<ChatServerUrl>//;s/<\/ChatServerUrl>.*$//"`
serverStatus_URL=`grep -h -A 4 "<World>" .launcher/GLSDataCenter.config.${game} | grep -F -A 3 "${world}" | grep -h "<StatusServerUrl>" | grep -v '<!--.*-->' | sed -e "s/^.*<StatusServerUrl>//;s/<\/StatusServerUrl>.*$//"`
# Look up the server info in the configuration file
# The chat server address is given directly, other stuff needs another file (cache_$REALMNAME.xml) from the server
if [ -z "${launcherCfg_URL}" ] || [ -z "${authServer_URL}" ] ; then
echo -e "\nError: Could not extract one or more server URLs from the Game Login Server response.\n"
cd "${oldDir}"
exit
fi
# Extract list of game servers into an array
worlds=`grep -h -A 4 "<World>" .launcher/GLSDataCenter.config.${game} | grep "<Name>" | grep -v '<!--.*-->' | sed -e "s/^.*<Name>//;s/<\/Name>.*$//"`
IFS=$'\n'
i=0
for name in ${worlds} ; do
serverNames[$i]=${name}
i=$(($i + 1))
done
serverNames[$i]="end-of-list"
unset IFS
echo "Launch Configuration Server: ${launcherCfg_URL}"
echo "Patch Server: ${patchServer_ADR}"
echo "Authorization Server: ${authServer_URL}"
if [[ "${serverNames[0]}" != "end-of-list" ]] ; then
echo "Available Worlds: ${serverNames[0]}"
i=1
while [[ "${serverNames[$i]}" != "end-of-list" ]] ; do
echo -e " ${serverNames[$i]}"
i=$(($i + 1))
done
else
echo "Available Worlds: None"
cd "${oldDir}"
exit
fi
echo "${world} Chat Server: ${serverChat_URL}"
echo "${world} Status Server: ${serverStatus_URL}"
echo "-----------------------------------------------------------------------"
echo "Querying Launch Configuration Server..."
# wget --no-check-certificate \
# -q "${launcherCfg_URL}" \
# -O .launcher/launcher.config
curl --silent \
--insecure \
"${launcherCfg_URL}" \
--output .launcher/launcher.config
if ! [ -r .launcher/launcher.config ] ; then
echo -e "\nError: Could not fetch dynamic launcher configuration.\n"
cd "${oldDir}"
exit
fi
# Extract game settings from launcher configuration.
worldQueue_URL=`grep -h "WorldQueue.LoginQueue.URL" .launcher/launcher.config | grep -v '<!--.*-->' | sed -e "s/^.*value=\"\([^\"]*\)\".*$/\1/"`
worldQueue_ARGTMPL=`grep -h "WorldQueue.TakeANumber.Parameters" .launcher/launcher.config | grep -v '<!--.*-->' | sed -e "s/^.*value=\"\([^\"]*\)\".*$/\1/"`
glsTicketLifetime=`grep -h "GameClient.Arg.glsticketlifetime" .launcher/launcher.config | grep -v '<!--.*-->' | sed -e "s/^.*value=\"\([^\"]*\)\".*$/\1/"`
support_URL=`grep -h "GameClient.Arg.supporturl" .launcher/launcher.config | grep -v '<!--.*-->' | sed -e "s/^.*value=\"\([^\"]*\)\".*$/\1/"`
bug_URL=`grep -h "GameClient.Arg.bugurl" .launcher/launcher.config | grep -v '<!--.*-->' | sed -e "s/^.*value=\"\([^\"]*\)\".*$/\1/"`
supportService_URL=`grep -h "GameClient.Arg.supportserviceurl" .launcher/launcher.config | grep -v '<!--.*-->' | sed -e "s/^.*value=\"\([^\"]*\)\".*$/\1/"`
gameClient_FILE=`grep -h "GameClient.OSX.Filename" .launcher/launcher.config | grep -v '<!--.*-->' | sed -e "s/^.*value=\"\([^\"]*\)\".*$/\1/"`
gameClient_ARGTMPL=`grep -h "GameClient.OSX.ArgTemplate" .launcher/launcher.config | grep -v '<!--.*-->' | sed -e "s/^.*value=\"\([^\"]*\)\".*$/\1/"`
echo "World Queue Server: ${worldQueue_URL}"
echo "World Queue Args: ${worldQueue_ARGTMPL}"
echo "GLS Ticket Lifetime: ${glsTicketLifetime}"
echo "Support URL: ${support_URL}"
echo "Bug URL: ${bug_URL}"
echo "Support Service URL: ${supportService_URL}"
echo "Game Client File: ${gameClient_FILE}"
echo "Game Client Args: ${gameClient_ARGTMPL}"
echo "-----------------------------------------------------------------------"
########### CHOOSE LANGUAGE
languages[0]=english
selectedLanguage=0
########### PATCHING
# Note: This script cannot patch the game. Use the Launcher to do that.
########### AUTHENTICATION
function GLSAuth() {
# "submit" the login form via POST, will download a file called "LoginAccount"
# NOTE: the same thing as with the DataCenterServer applies here
# the lotroeugls server even has a service description and test form online
# well, at least they provide the SOAP request body as well...
# wget \
# --no-check-certificate -q \
# --header 'Content-Type: text/xml; charset=utf-8' \
# --header 'SOAPAction: "http://www.turbine.com/SE/GLS/LoginAccount"' \
# --post-data "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><LoginAccount xmlns=\"http://www.turbine.com/SE/GLS\"><username>${username}</username><password>${password}</password><additionalInfo></additionalInfo></LoginAccount></soap:Body></soap:Envelope>" \
# "${authServer_URL}" -O .launcher/GLSAuthServer.config
curl --silent \
--insecure \
--header 'Content-Type: text/xml; charset=utf-8' \
--header 'SOAPAction: "http://www.turbine.com/SE/GLS/LoginAccount"' \
--data "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><LoginAccount xmlns=\"http://www.turbine.com/SE/GLS\"><username>${username}</username><password>${password}</password><additionalInfo></additionalInfo></LoginAccount></soap:Body></soap:Envelope>" \
"${authServer_URL}" \
--output .launcher/GLSAuthServer.config
if ! [ -s .launcher/GLSAuthServer.config ] || grep -qs faultcode .launcher/GLSAuthServer.config ; then
echo -e "\nError: GLS auth server request failed. Wrong username / password?\n"
cd "${oldDir}"
exit
fi
}
echo "Requesting account details and authentication token from the Authorization Server..."
GLSAuth
# Check for multiple game subscriptions for the authenticated account.
# Insert whitespace after </GameSubscription> tags here (to have linebreaks as separators for accounts)
sed -e "s#\(</GameSubscription>\)#\1_make_newline_#g" -i "" .launcher/GLSAuthServer.config
awk '{ gsub(/_make_newline_/,"\n",$0); print }' .launcher/GLSAuthServer.config >> .launcher/GLSAuthServer.config.tmp
rm -f .launcher/GLSAuthServer.config
mv .launcher/GLSAuthServer.config.tmp .launcher/GLSAuthServer.config
# Extract each of the ids as well as descriptions for subscriptions to the current game.
subNames=`grep -h "<Game>${game}<\/Game>" .launcher/GLSAuthServer.config | grep "<Name>" | grep -v '<!--.*-->' | sed -e "s/^.*<Name>//;s/<\/Name>.*$//"`
subDescs=`grep -h "<Game>${game}<\/Game>" .launcher/GLSAuthServer.config | grep "<Description>" | grep -v '<!--.*-->' | sed -e "s/^.*<Description>//;s/<\/Description>.*$//"`
IFS=$'\n'
i=0
for sub in ${subNames} ; do
subs[$i]="${sub}"
i=$(($i + 1))
done
subs[$i]="end-of-list"
i=0
for desc in ${subDescs} ; do
descs[$i]="${desc}"
i=$(($i + 1))
done
descs[$i]="end-of-list"
unset IFS
# Check for at least one active subscription.
if [[ $i == 0 ]] ; then
echo -e "\nError: There appears to be no subscription for ${game}.\n"
cd "${oldDir}"
exit
fi
# Extract the ticket from the GLS auth file, check for failure
# NOTE: only the id (not the ticket) is subscription-specific
glsTicket=`sed -n -e "s/^.*<Ticket>//;s/<\/Ticket>.*$// p" .launcher/GLSAuthServer.config`
if [[ -z "${glsTicket}" ]] ; then
echo -e "\nError: Could not extract authetication token from the Authorization Server response.\n"
cd "${oldDir}"
exit
fi
if [[ "${subs[0]}" != "end-of-list" ]] ; then
echo "Subscription Names: ${subs[0]}"
i=1
while [[ "${subs[$i]}" != "end-of-list" ]] ; do
echo -e " ${subs[$i]}"
i=$(($i + 1))
done
else
echo "Subscription Names: None"
cd "${oldDir}"
exit
fi
if [[ "${descs[0]}" != "end-of-list" ]] ; then
echo "Subscription Descriptions: ${descs[0]}"
i=1
while [[ "${descs[$i]}" != "end-of-list" ]] ; do
echo -e " ${descs[$i]}"
i=$(($i + 1))
done
else
echo "Subscription Descriptions: None"
cd "${oldDir}"
exit
fi
echo "Authentication Token: ${glsTicket}"
echo "-----------------------------------------------------------------------"
# If there are multiple subscriptions to the current game available for the account,
# and we haven't set the subscription choice, ask which one to use.
if [[ "${subscription}" == "" ]] ; then
if [[ $i > 1 && "${subscription}" == "" ]] ; then
i=0
echo "You have the following subscriptions for $game:"
while [[ "${subs[$i]}" != "end-of-list" ]] ; do
echo -e " $i: ${subs[$i]}\t'${descs[$i]}'"
i=$(($i + 1))
done
echo -n "Please select the one you wish to use (enter the number on the left): "
read subscription
else
subscription=0
fi
fi
echo "Requesting world information for ${world} from the Status Server..."
# Download the status file and get the server adress and login queue adress to
# establish the connection.
# TODO: this file also contains current availability information, use it
# wget --no-check-certificate \
# -q "$serverStatus_URL" \
# -O .launcher/server.config
curl --silent \
--insecure \
"$serverStatus_URL" \
--output .launcher/server.config
# Extract the list of loginServers and queue URLs (two at this time, it seems)
loginServers=`grep -h "<loginservers>" .launcher/server.config | grep -v '<!--.*-->' | sed -e "s/^.*<loginservers>//;s/<\/loginservers>.*$//"`
queueUrls=`grep -h "<queueurls>" .launcher/server.config | grep -v '<!--.*-->' | sed -e "s/^.*<queueurls>//;s/<\/queueurls>.*$//"`
if [ -z "${loginServers}" ] || [ -z "${queueUrls}" ] ; then
echo -e "\nError: Could not extract world information for ${world}.\n"
cd "${oldDir}"
exit
fi
# Create array of servers
IFS=";"
i=0
for adr in ${loginServers} ; do
serverAddresses[$i]="${adr}"
i=$(($i + 1))
done
serverAddresses[$i]="end-of-list"
i=0
for adr in ${queueUrls} ; do
serverQueues[$i]="${adr}"
i=$(($i + 1))
done
serverQueues[$i]="end-of-list"
unset IFS
# Create the world queue login request for the requested world.
# The ticket can contain special characters and needs to be URL encoded before
# POSTing it (same for queue_url). launcher.config included a parameter template
# for the world queue request, used the same way as the client args below
serverAddress="${serverAddresses[0]}"
serverQueue="${serverQueues[0]}"
rawurlencode() {
local string="${1}"
local strlen=${#string}
local encoded=""
for (( pos=0 ; pos<strlen ; pos++ )); do
c=${string:$pos:1}
case "$c" in
[-_.~a-zA-Z0-9] ) o="${c}" ;;
* ) printf -v o '%%%02x' "'$c"
esac
encoded+="${o}"
done
echo "${encoded}"
}
glsTicketURLencoded=$(rawurlencode "${glsTicket}")
loginQueueURLencoded=$(rawurlencode "${serverQueue}")
worldQueue_ARGS=`echo "${worldQueue_ARGTMPL}" | sed -e "s/[{]0[}]/${subs[$subscription]}/;s/[{]1[}]/${glsTicketURLencoded}/;s/[{]2[}]/${loginQueueURLencoded}/;s/\&\;/\&/g"`
if [[ "${serverAddresses[0]}" != "end-of-list" ]] ; then
echo "${world} Login Servers: ${serverAddresses[0]}"
i=1
while [[ "${serverAddresses[$i]}" != "end-of-list" ]] ; do
echo -e " ${serverAddresses[$i]}"
i=$(($i + 1))
done
else
echo "${world} Login Servers: None"
cd "${oldDir}"
exit
fi
if [[ "${serverQueues[0]}" != "end-of-list" ]] ; then
echo "${world} Login Servers: ${serverQueues[0]}"
i=1
while [[ "${serverQueues[$i]}" != "end-of-list" ]] ; do
echo -e " ${serverQueues[$i]}"
i=$(($i + 1))
done
else
echo "${world} Login Servers: None"
cd "${oldDir}"
exit
fi
echo "Selecting queue: ${serverQueue}"
echo "Queue Arguments: ${worldQueue_ARGS}"
echo "-----------------------------------------------------------------------"
########### LOGIN QUEUE / CLIENT START
function JoinQueue() {
# Now get a queue number from the world login queue so that the client can enqueue and authenticate
inQueue=1
while [ "${inQueue}" == "1" ]; do
# loop when necessary
# wget --no-check-certificate \
# -q --post-data="${worldQueue_ARGS}" \
# "${worldQueue_URL}" \
# -O .launcher/WorldQueue.config
curl --silent \
--insecure \
--data "${worldQueue_ARGS}" \
"${worldQueue_URL}" \
--output .launcher/WorldQueue.config
if ! [ -r .launcher/WorldQueue.config ] ; then
echo -e "\nError: World login queue request failed.\n"
cd "${oldDir}"
exit
fi
# check the result, should be HRESULT 0x00000000, indicating success (Windows API madness)
hresult=`grep -h "<HResult>" .launcher/WorldQueue.config | grep -v '<!--.*-->' | sed -e "s/^.*<HResult>//;s/<\/HResult>.*$//"`
if [ "${hresult}" != "0x00000000" ] ; then
echo -e "\nError: World login queue response indicates failure."
cd "${oldDir}"
exit
else
# lets see what position we are at
queuePos=`grep -h "<QueueNumber>" .launcher/WorldQueue.config | grep -v '<!--.*-->' | sed -e "s/^.*<QueueNumber>//;s/<\/QueueNumber>.*$//"`
queueSrvd=`grep -h "<NowServingNumber>" .launcher/WorldQueue.config | grep -v '<!--.*-->' | sed -e "s/^.*<NowServingNumber>//;s/<\/NowServingNumber>.*$//"`
queueAhead=$(( ${queuePos} - ${queueSrvd} ))
if [ ${queueAhead} -gt 0 ]; then
# d'oh, need to wait
echo -e "\n${queueAhead} ahead in queue, retrying in 5s..."
sleep 5
else
# hah, ready to go
inQueue=0
fi
fi
done
}
echo "Joining ${world} Login Server queue..."
# new: world queue is unused on (some?) EU servers, just like with DDO, skip if no queue URL
if [ -n "${serverQueue}" ] ; then
JoinQueue
else
echo -e "\nWorld login queue seems to be disabled, skipping..."
fi
echo "Login to ${world} successful."
# OK, so we have a template for the client arguments and we have the arguments
# Note that for replacing the glsTicket, I use s### instead of s/// due to the ticket containing slashes
# Hopefully, it doesn't contain any sharp characters :)
gameClient_ARGS=`echo "${gameClient_ARGTMPL}" | sed -e "
s/[{]SUBSCRIPTION[}]/${subs[$subscription]}/;
s/[{]LOGIN[}]/${serverAddress}/;
s#[{]GLS[}]#${glsTicket}#;
s/[{]CHAT[}]/${serverChat_URL}/;
s/[{]LANG[}]/${languages[$selectedLanguage]}/;
s#[{]AUTHSERVERURL[}]#${authServer_URL}#;
s/[{]GLSTICKETLIFETIME[}]/${glsTicketLifetime}/;
s#[{]SUPPORTURL[}]#${support_URL}#;
s#[{]BUGURL[}]#${bug_URL}#;
s#[{]SUPPORTSERVICEURL[}]#${supportService_URL}#;
"`
if [ -n "${character}" ] ; then
gameClient_ARGS="$gameClient_ARGS -u $character"
fi
BP='\033[0;34m'
NC='\033[0m'
echo "Launching client:"
if [ -n "${X64}" ] ; then
echo -e "${BP}WINEPREFIX=$gameWinePrefix_DIR $gameWineBin_DIR/wine64 $gameClient_EXE ${gameClient_ARGS} &>/dev/null &${NC}"
WINEPREFIX="$gameWinePrefix_DIR" "$gameWineBin_DIR"/wine64 "$gameClient_EXE" ${gameClient_ARGS} &>/dev/null &
else
echo -e "${BP}WINEPREFIX=$gameWinePrefix_DIR $gameWineBin_DIR/wine $gameClient_EXE ${gameClient_ARGS} &>/dev/null &${NC}"
WINEPREFIX="$gameWinePrefix_DIR" "$gameWineBin_DIR"/wine "$gameClient_EXE" ${gameClient_ARGS} &>/dev/null &
fi
disown
echo "-----------------------------------------------------------------------"
echo "Done. Please allow the DDO client a few seconds to launch."
echo "-----------------------------------------------------------------------"
# Get back to where the caller was
cd "${oldDir}"
exit