diff options
-rw-r--r-- | README.md | 72 | ||||
-rwxr-xr-x | tmw-info | 142 |
2 files changed, 89 insertions, 125 deletions
@@ -10,13 +10,10 @@ * The Mana World: https://themanaworld.org] ## Dependencies -Requires: Linux, Bourne Again Shell (BASH), grep +Requires: Linux, Bourne Again Shell (BASH), grep, curl and wget Suggests: zenity ## Intro: -Although much of this information is available on wiki and server pages, browsers can pose some issues; Load time, navigation and -browser fingerprinting are a few. The convenience and speed of having basic information available in the terminal can't be matched. - tmw-info's update functions download database(DB) files to be searched locally and only require updating after a server update, except in the case of GM Logs, where you may wish to update before searching, if looking for the newest issued commands. @@ -25,17 +22,18 @@ All searches ignore case. Only GM log searches can use any(search) and exact(ese Because tmw-info searches the actual DB files, hidden attributes are seen in the results. ## Tips: -When searching for references of items and mobs, remember to check it's ID and search with it too. When items and mobs are spawned, ID's are often used rather than names. Item IDs for drops are in mob DB files, but names are not. It is important to remember that the -files being searched contain IDs and are in some cases, like drops, converted into human readable text for viewing results in the terminal. +When searching for references of items and mobs, remember to check it's ID and search with it too. When items and mobs are spawned, ID's are +often used rather than names. Item IDs for drops are in mob DB files, but names are not. It is important to remember that the files being +searched contain IDs and are in some cases, like drops, converted into human readable text for viewing results in the terminal. When searching for monster drops, always use the item ID, which can be found easily in an item search. Item searches do not require an ID as it's name is searchable in the DB. Also note that the name in game may differ in rare cases, like the Magic Ring being the MageRing. gm-show is the only GUI aspect of tmw-info at the moment, but defaults to terminal output if zenity isn't installed (I didn't -uninstall zenity to test, but echoing to terminal should work. Let me know if I'm wrong please). It works the exact same as tmw-gmlog and -is available separately on my projects page (see top). It is intented to be called from a preset keyboard shortcut (I run ManaPlus in -window mode and use OS KB shortcuts to toggle fullscreen. Even when in fullscreen, the GUI window will show on top this way when the key -combo is pressed). It is also important to mention, there is a delay between the GM CMDs issued and the server's log being updated. +uninstall zenity to test, but echoing to terminal should work). It works the exact same as tmw-gmlog and is available separately on my +projects page (see top). It is intented to be called from a preset keyboard shortcut (I run ManaPlus in window mode and use OS KB shortcuts +to toggle fullscreen. Even when in fullscreen, the GUI window will show on top this way when the key combo is pressed). It is also important +to mention, there is a delay between the GM CMDs issued and the server's log being updated. If trying to compile a complete DB file of all items, for instance, a common character must be found in all references because wildcards will not work. " , " can be used to search all files since it is the common string separator in all, but will have a lot of @@ -43,14 +41,8 @@ empty space and junk lines and even some misplaced information. Due to the IDs h sorting them in the proper order can also be a challenge. You can encounter orders like this: 5524, 56, 5576, 558. If you still wish to create a full list: " grep -E '^[0-9]+,\s*' | sort -n | tee -a items.txt < <(tmw-info item-search ,) " -Due to the subshell, you will have to manually quit when the output stops with ctrl-c before the file is populated. I'll work on making it -pipe properly in the future. +Due to the subshell, you will have to manually quit when the output stops with ctrl-c before the file is populated. -## Note: -Due to TMW becoming deprecated with the coming of the new rEvolt server, future versions of this script will be sparse or unlikely -unless requested, though I may make a wiki search for very general infomation. More work will be put into making a version of this script -to be used with rEvolt in the near future and will, hopefully, not need too much reworking. I would like to make "Other Attributes" a bit -more human readable though. ## Help: ``` @@ -73,35 +65,23 @@ tmw-info [command] [STRING] If you get and error while searching, it may contain special characters and needs to be quoted gm searches, item-search, mob-search and cmds require periodic updating with their respective update commands To avoid hammering servers, there will be no update-all option. Use gm-update before performing gm searches. -Use gm-show to quickly display the last 10 gm commands run (updates automatically) +Use gm-show to quickly display the last 10 gm commands run. Updates automatically. Uses zenity to display GUI, if installed) ``` ## Changelog -* 2020-08-15 - - fixed gm-show (wasn't showing GUI) and removed trailing comma in mob drops -* 2020-08-16 - - added ratio for dropped items to represent chances in a more human readable way -* 2020-09-16 - - added chat log search -* 2021-04-13 - - added cmds-update to download @ command DB pages and jak1's wiki on client commands - - "cmds" now gets info from those pages and is better organized - - added extra function to chat-search to view a log file easily after a search - - fixed a bug that downloaded 2020-09 GM log everytime gm-update was run - - added support for GM log files ending in "-old" (2020-09-old is a restored file) -2020-08-15 - - fixed gm-show (wasn't showing GUI) and removed trailing comma in mob drops -2020-08-16 - - added ratio for dropped items to represent chances in a more human readable way -2020-09-16 - - added chat log search -2021-04-13 - - added cmds-update to download @ command DB pages and jak1's wiki on client commands - - "cmds" now gets info from those pages and is better organized - - added extra function to chat-search to view a log file easily after a search - - fixed a bug that downloaded 2020-09 GM log everytime gm-update was run - - added support for GM log files ending in "-old" (2020-09-old is a restored file) -2022-06-30 - - corrected update-cmds to cmds-update and missing data from web sources now shows - - cmds now pulls text from the M+ binary and some commands have been added manually that were found by chance - - Added extra help text +* 2022-12-13 - Changed check for zenity from dpkg -l to find in /bin or /usr/bin. + - Added general check and warning for those without curl or wget + - Used find for removing .tmp files instead of specifying locations in the exit trap + - Edited structure, comments and readme +* 2022-06-30 - corrected update-cmds to cmds-update and missing data from web sources now shows + - cmds now pulls text from the M+ binary and some commands have been added manually that were found by chance + - Added extra help text +* 2021-04-13 - added cmds-update to download @ command DB pages and jak1's wiki on client commands + - "cmds" now gets info from those pages and is better organized + - added extra function to chat-search to view a log file easily after a search + - fixed a bug that downloaded 2020-09 GM log everytime gm-update was run + - added support for GM log files ending in "-old" (2020-09-old is a restored file) +* 2020-09-16 - added chat log search +* 2020-08-16 - added ratio for dropped items to represent chances in a more human readable way +* 2020-08-15 - fixed gm-show (wasn't showing GUI) and removed trailing comma in mob drops + @@ -1,39 +1,38 @@ #!/bin/bash -# TMW GM Log Downloader (original): https://gitlab.com/liviorecchia/tmw-gm-log-downloader -# tmw-info: https://git.themanaworld.org/legacy/tmw-info/ -# The Mana World: https://themanaworld.org -# Ledmitz (2020) - GPL 3.0 +#TMW GM Log Downloader (original): https://gitlab.com/liviorecchia/tmw-gm-log-downloader +#tmw-info: https://git.themanaworld.org/legacy/tmw-info/ +#The Mana World: https://themanaworld.org +#Ledmitz (2020) - GPL 3.0 -# Chat logs DIR +#Chat logs DIR CHAT_LOGS="$HOME/.local/share/mana/logs/server.themanaworld.org/" months=(01 02 03 04 05 06 07 08 09 10 11 12) thisYear=$(date -u +'%Y') thisMonth=$(date -u +'%m') -# Main DIR +#Main DIR TMW_INFO="$HOME/.tmw-info" -# Items DB DIR +#Items DB DIR ITEM_DIR="$TMW_INFO/item" -# Monster DB DIR +#Monster DB DIR MOB_DIR="$TMW_INFO/mob" -# Commands DIR +#Commands DIR TMW_CMDS="$TMW_INFO/cmds" -# GM Log DIR +#GM Log DIR TMW_GM_LOGS="$TMW_INFO/logs" GM_LOG_LIST="$TMW_INFO/gm_log_list" -# Current month's GM log +#Current month's GM log GM_LOG="$TMW_INFO/gm_log.tmp" -# File to be read as report +#File to be read as report GM_REPORT="$TMW_INFO/gm_report.txt" -# Runs on exit (deletes tmp files) +#Runs on exit (deletes tmp files) function FINISH { - rm -f "$TMW_INFO"/*.tmp + find "$TMW_INFO" -type f -name '*.tmp' -exec rm -f {} \; } trap FINISH EXIT - help(){ echo "tmw-info [command] [STRING]" echo " help / --help / -h (this help screen)" @@ -53,62 +52,57 @@ help(){ echo " mob-search TERM1 TERM2 TERM3 ... (monsters: results contain all of the terms)" echo 'If you get and error while searching, it may contain special characters and needs to be quoted' echo 'gm searches, item-search, mob-search and cmds require periodic updating with their respective update commands' - echo 'To avoid hammering servers, there will be no update-all option. Use gm-update before performing gm searches. \ -Use gm-show to quickly display the last 10 gm commands run (updates automatically)' + echo 'To avoid hammering servers, there will be no update-all option. Use gm-update before performing gm searches. +Use gm-show to quickly display the last 10 gm commands run. Updates automatically. Uses zenity to display GUI, if installed)' } - if [ -z "$1" ]; then echo "Missing command" help exit 0 fi -# If no search term is given -if [ "$1" == "gm-search" ] || [ "$1" == "gm-asearch" ] || [ "$1" == "gm-esearch" ] || [ "$1" == "item-search" ] || [ "$1" == "mob-search" ]; then +if [ "$1" == "gm-search" ] || [ "$1" == "gm-asearch" ] || [ "$1" == "gm-esearch" ] || [ "$1" == "item-search" ] || [ "$1" == "mob-search" ] || [ "$1" == "chat-search" ]; then if [ -z "$2" ]; then echo "Missing search terms" help exit 0 fi - # If either the "logs" DIR doesn't exist or there are no files in the DIR fi - -# Create a DIR to save files in +if [[ $(find '/usr/bin/' '/bin/' -type f -name 'curl') == '' ]]; then + echo "Warning: cURL missing. Curl needs to be installed for most functions to work" +fi +if [[ $(find '/usr/bin/' '/bin/' -type f -name 'wget') == '' ]]; then + echo "Warning: wget missing. wget needs to be installed for gm-update and cmds-update to work" +fi mkdir -p "$TMW_INFO" - if [ "$1" == "help" ] || [ "$1" == "--help" ] || [ "$1" == "-h" ]; then help elif [ "$1" == "news" ]; then curl -s 'https://themanaworld.github.io/tmwa-server-data/news.html' | sed 's/<\/*[^>]*>//g' | less elif [ "$1" == "online" ]; then - #curl -s 'https://server.themanaworld.org/' | sed 's/<\/*[^>]*>//g' | sed -r '/^\s*$/d' | sed -r '/^\s*Name\s*$/d' | sed 1d curl -s 'https://server.themanaworld.org/' | sed 's/<\/*[^>]*>//g' | sed -r '/^\s*$/d' | sed -r '/^\s*Name\s*$/d' | grep -v 'Online Players' | sed 1d | LC_ALL=C sort elif [ "$1" == "gm-update" ]; then mkdir -p "$TMW_GM_LOGS" - # Get list of files from server to read the byte counts from + #Get list of files from server to read the byte counts from wget -c -q -O "$GM_LOG_LIST.tmp" 'https://server.themanaworld.org/gm' sed 's/<\/*[^>]*>//g' "$GM_LOG_LIST.tmp" > "$GM_LOG_LIST" - # Download the very first one without updating it if already exists - #This is the only gmlog without a byte count check. If it becomes corrupted, it must be deleted + #Download the very first one without updating it if already exists + #This is the only gmlog without a byte count check (none listed online). If it becomes corrupted, it must be deleted manually wget -nc -q -P "$TMW_GM_LOGS" 'https://server.themanaworld.org/gm/gm.log.2008-12' - for (( year = 2009; year <= thisYear; year++ )) - do - for month in ${months[*]} - do - # If the log is from this year and the month hasn't come yet, do nothing + for (( year = 2009; year <= thisYear; year++ )); do + for month in ${months[*]}; do + #If the log is from this year and the month hasn't come yet, do nothing if [[ "$year" == "$thisYear" ]] && [[ "$month" > "$thisMonth" ]]; then : else - # Get the bytecounts reported by server to compare with local file + #Get the bytecounts reported by server to compare with local file BYTECOUNT_WEB=$(grep "gm.log.$year-$month " "$GM_LOG_LIST" | awk '{print $4}' | sed -E 's/\s//g') BYTECOUNT_LOCAL=$(ls -l "$TMW_GM_LOGS/gm.log.$year-$month" 2> '/dev/null' | awk '{print $5}' | sed -E 's/\s//g') - #echo $BYTECOUNT_WEB - #echo $BYTECOUNT_LOCAL if [[ "$BYTECOUNT_WEB" != "$BYTECOUNT_LOCAL" ]]; then echo "Downloading $month/$year" wget -q -c -P "$TMW_GM_LOGS" "https://server.themanaworld.org/gm/gm.log.$year-$month" fi - # Added for file rebuilt from corrupted (2020-09-old) + #Added for file rebuilt from corrupted (2020-09-old) BYTECOUNT_WEB_OLD=$(grep "gm.log.$year-$month-old " "$GM_LOG_LIST" | awk '{print $4}' | sed -E 's/\s//g') BYTECOUNT_LOCAL_OLD=$(ls -l "$TMW_GM_LOGS/gm.log.$year-$month-old" 2> '/dev/null' | awk '{print $5}' | sed -E 's/\s//g') if [[ "$BYTECOUNT_WEB_OLD" != "$BYTECOUNT_LOCAL_OLD" ]]; then @@ -116,20 +110,19 @@ elif [ "$1" == "gm-update" ]; then wget -q -c -P "$TMW_GM_LOGS" "https://server.themanaworld.org/gm/gm.log.$year-$month-old" fi fi - done + done done -# All searches cancel special grep characters, [ and ], which are read by grep, even in single quoted text -# When echoing back, the \ are again removed to show what was originally typed by the user correctly -# only [ and ] regex characters seemed to pose a problem +#All searches cancel special grep characters [ and ], which are read by grep, even in single quoted text +#When echoing back, the \ are again removed to show what was originally typed by the user correctly +#Only [ and ] regex characters seemed to pose a problem elif [ "$1" == "gm-search" ]; then if [ ! -d "$TMW_GM_LOGS" ] || [ -z "$(ls "$TMW_GM_LOGS")" ]; then echo 'You must run gm-update before searching' exit 0 fi - # Any terms: This must be an array because each term is searched separately in the for loop. + #Any terms: This must be an array because each term is searched separately in the for loop. SEARCH_TERMS=($(echo "$*" | sed -E 's/^gm-search\s//g' | sed 's/\[/\\\[/g' | sed 's/\]/\\\]/g')) - for WORD in "${SEARCH_TERMS[@]}" - do + for WORD in "${SEARCH_TERMS[@]}"; do echo "========== Results (any): $WORD ==========" | sed 's/\\//g' grep -hi "$WORD" "$TMW_GM_LOGS"/* done @@ -138,13 +131,12 @@ elif [ "$1" == "gm-asearch" ]; then echo 'You must run gm-update before searching' exit 0 fi - # All terms: This must not be an array + #All terms: This must not be an array SEARCH_TERMS=$(echo "$*" | sed -E 's/^gm-asearch\s//g' | sed 's/\[/\\\[/g' | sed 's/\]/\\\]/g') WORD_COUNT=$(echo "$SEARCH_TERMS" | wc -w) COUNT='1' echo "========== Results (all): $SEARCH_TERMS ==========" | sed 's/\\//g' - while [ "$COUNT" -le "$WORD_COUNT" ] - do + while [ "$COUNT" -le "$WORD_COUNT" ]; do WORD=$(echo "$SEARCH_TERMS" | awk "{print \$$COUNT}") if [ "$COUNT" = '1' ]; then grep -hi "$WORD" "$TMW_GM_LOGS"/* > "$TMW_INFO/gm-asearch$COUNT.tmp" @@ -160,57 +152,55 @@ elif [ "$1" == "gm-esearch" ]; then echo 'You must run gm-update before searching' exit 0 fi - # Exact search: Must not be an array. Used once. + #Exact search: Must not be an array. Used once. SEARCH_TERMS=$(echo "$*" | sed -E 's/^gm-esearch\s//g' | sed 's/\[/\\\[/g' | sed 's/\]/\\\]/g') echo "========== Results (exact): $SEARCH_TERMS ==========" | sed 's/\\//g' grep -hi "$SEARCH_TERMS" "$TMW_GM_LOGS"/* elif [ "$1" == 'gm-show' ]; then - ## This shows a GUI window with the last 10 GM commands. The amount of lines can be changed with "LINE_COUNT" - # Root URL of the GM logs (no date) + ##This shows a GUI window with the last 10 GM commands. The amount of lines can be changed with "LINE_COUNT" + #Root URL of the GM logs (no date) GM_LOG_URL='https://server.themanaworld.org/gm/gm.log.' - # Date scheme used in URL + #Date scheme used in URL LOG_DATE=$(date -u +%Y-%m) - # The current day + #The current day TODAY=$(date -u +%d) - # Yesterday + #Yesterday YESTERDAY=$(date -u --date yesterday +%d) - # Last month + #Last month LAST_MONTH=$(date -u --date 'last month' +%m) - # Last year + #Last year LAST_YEAR=$(date -u --date 'last year' +%Y) - # Maximum number of new lines to report + #Maximum number of new lines to report LINE_COUNT='10' - # Download the GM log + #Download the GM log curl -s "$GM_LOG_URL$LOG_DATE" > "$GM_LOG" - # Check if no posts made this month yet + #Check if no posts made this month yet if [[ $(grep '<head><title>404 Not Found</title></head>' "$GM_LOG") != '' ]]; then LINE_COUNT_TODAY='0' - # Check if no posts made today yet + #Check if no posts made today yet elif [[ $(grep "$LOG_DATE-$TODAY" "$GM_LOG") == '' ]]; then LINE_COUNT_TODAY='0' else - # Number of commands issued today + #Number of commands issued today LINE_COUNT_TODAY=$(grep "$LOG_DATE-$TODAY" "$GM_LOG" | wc -l) fi - # If lines for today are at maximum, just get max lines + #If lines for today are at maximum, just get max lines if [ "$LINE_COUNT_TODAY" -ge "$LINE_COUNT" ]; then tail -n "$LINE_COUNT" "$GM_LOG" > "$GM_REPORT" - # If line aren't maxed yet... else - # If today isn't the first of the month, just get the lines from the current month's log + #If today isn't the first of the month, just get the lines from the current month's log if [[ "$TODAY" != '01' ]]; then tail -n "$LINE_COUNT" "$GM_LOG" > "$GM_REPORT" - # If it is the 1st of the month... else - # Number of lines to report from yesterday's commands (total - today = yesterday) + #Number of lines to report from yesterday's commands (total - today = yesterday) LINE_COUNT_YESTERDAY=$(( "$LINE_COUNT" - "$LINE_COUNT_TODAY" )) - # Make sure it isn't January, download last month's log and append lines to file + #Make sure it isn't January, download last month's log and append lines to file if [[ $(date -u +%m) != '01' ]]; then curl -s "$GM_LOG_URL$(date -u +%Y)-$LAST_MONTH" > "$GM_LOG"'_last_month' grep "$(date -u +%Y)-$LAST_MONTH-$YESTERDAY" "$GM_LOG"'_last_month' | tail -n "$LINE_COUNT_YESTERDAY" > "$GM_REPORT" grep "$LOG_DATE-$TODAY" "$GM_LOG" >> "$GM_REPORT" - # If it is January, last month is also last year + #If it is January, last month is also last year else curl -s "$GM_LOG_URL$LAST_YEAR-12" > "$GM_LOG"'_last_month' grep "$LAST_YEAR-12-31" "$GM_LOG"'_last_month' | tail -n "$LINE_COUNT_YESTERDAY" > "$GM_REPORT" @@ -218,8 +208,8 @@ elif [ "$1" == 'gm-show' ]; then fi fi fi - if [[ $(dpkg -l 'zenity' | grep -Eo '^ii') == 'ii' ]]; then - zenity --text-info 'tmw-gmlog' --width '600' --height '300' --filename "$GM_REPORT" + if [[ $(find '/usr/bin/' -type f -name 'zenity') == '/usr/bin/zenity' ]] || [[ $(find '/bin/' -type f -name 'zenity') == '/bin/zenity' ]]; then + zenity --text-info 'tmw-gmlog' --width '600' --height '300' --filename "$GM_REPORT" 2> '/dev/null' else cat < "$GM_REPORT" fi @@ -228,7 +218,7 @@ elif [ "$1" == "chat-search" ]; then echo 'There are no chat logs to search' exit 0 fi - # All terms: This must not be an array + #All terms: This must not be an array SEARCH_TERMS=$(echo "$*" | sed -E 's/^chat-search\s//g' | sed 's/\[/\\\[/g' | sed 's/\]/\\\]/g') WORD_COUNT=$(echo "$SEARCH_TERMS" | wc -w) COUNT='1' @@ -266,7 +256,7 @@ elif [ "$1" == "item-search" ]; then echo 'You must run item-update before searching' exit 0 fi - # All terms: This must not be an array + #All terms: This must not be an array SEARCH_TERMS=$(echo "$*" | sed -E 's/^item-search\s//g' | sed 's/\[/\\\[/g' | sed 's/\]/\\\]/g') WORD_COUNT=$(echo "$SEARCH_TERMS" | wc -w) COUNT='1' @@ -306,7 +296,7 @@ elif [ "$1" == "mob-search" ]; then echo 'You must run mob-update before searching' exit 0 fi - # All terms: This must not be an array + #All terms: This must not be an array SEARCH_TERMS=$(echo "$*" | sed -E 's/^mob-search\s//g' | sed 's/\[/\\\[/g' | sed 's/\]/\\\]/g') WORD_COUNT=$(echo "$SEARCH_TERMS" | wc -w) COUNT='1' @@ -371,21 +361,15 @@ elif [ "$1" == 'cmds-update' ];then grep -Eo '>/[a-z]+' "$TMW_CMDS/client_commands" | sed 's/^>//g' > "$TMW_CMDS/client" grep -Eo '>/[a-z\,/]+' "$TMW_CMDS/client_commands" | sed 's/^>//g' >> "$TMW_CMDS/client" grep -Eao '/[a-z]+ ' '/usr/games/manaplus' >> "$TMW_CMDS/client" - echo -e '/ipctoggle\n/targetmonster\n/movetotarget\n/attack\n/targetattack\n/untarget\n/where\n/navigate X Y\n/sethome\n/movetohome\n/present\n/all\n/pickup\n/useitem ID\n/disablehighlight\n/enablehighlight\n/sit\n/direct\n/turn[up,down,left,right]' >> "$TMW_CMDS/client" - #grep -Eo '>/[a-z\,/]+' "$TMW_CMDS/client_commands" | sed 's/^>//g' >> "$TMW_CMDS/client" - #grep -Eao '/[a-z]+ ' '/usr/games/manaplus' >> "$TMW_CMDS/client" + echo -e '/ipctoggle\n/lastseen\n/targetmonster\n/movetotarget\n/attack\n/targetattack\n/untarget\n/where\n/navigate X Y\n/sethome\n/movetohome\n/present\n/all\n/pickup\n/useitem ID\n/disablehighlight\n/enablehighlight\n/sit\n/direct\n/turn[up,down,left,right]' >> "$TMW_CMDS/client" cat < "$TMW_CMDS/client" | sed -E 's/\s*$//g' | sort -u > "$TMW_CMDS/client.tmp" mv -f "$TMW_CMDS/client.tmp" "$TMW_CMDS/client" - #rm "$TMW_CMDS/client_commands" echo "Downloading and creating default at command list..." wget -q -c -P "$TMW_CMDS" "https://github.com/themanaworld/tmwa-server-data/blob/master/world/map/conf/atcommand_athena.conf" sed 's/<\/*[^>]*>//g' "$TMW_CMDS/atcommand_athena.conf" | grep -Eo '[A-Za-z0-9]+: [0-9]+' "$TMW_CMDS/atcommand_athena.conf" | sort -u > "$TMW_CMDS/default_at" - #rm "$TMW_CMDS/atcommand_athena.conf" echo "Downloading and creating custom at command list..." wget -q -c -P "$TMW_CMDS" "https://github.com/themanaworld/tmwa-server-data/tree/master/world/map/npc/commands" sed 's/<\/*[^>]*>//g' "$TMW_CMDS/commands" | grep -Eo '[A-Za-z0-9]+.txt' | sed 's/.txt$//g' | grep -v '^import$\|^procedures$' | sort -u > "$TMW_CMDS/custom_at" - #rm "$TMW_CMDS/commands" - elif [ "$1" == 'cmds' ];then if [ ! -f "$TMW_CMDS/client" ] || [ ! -f "$TMW_CMDS/default_at" ] || [ ! -f "$TMW_CMDS/custom_at" ]; then echo 'You must run "cmds-update" first' |