Last active
February 27, 2021 22:50
-
-
Save waggz81/0355b4bed02dd214b16afb032acb17df to your computer and use it in GitHub Desktop.
Valheim Server Discord Alerts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
########################## | |
# Change these variables # | |
########################## | |
FILE="/path/to/console.log" | |
WEBHOOK_URL="CHANGEME" | |
STEAMKEY="CHANGEME" | |
########################## | |
### script logic ### | |
# array to store steam ids and map to player names | |
declare -A SteamID | |
# initialize global variables | |
lastSteamID=0 | |
havePlayerName=0 | |
# begin watching the log file and check each new line | |
tail -Fn0 $FILE | \ | |
while read -r line ; do | |
# check for the matching lines we want to look into further | |
if grep -iq "Closing socket\|Got handshake from client\|Got character ZDOID from" <<< "$line" | |
then | |
# tokenize the line sp;it by colons so easier to process | |
IFS=':' tokens=( $line ) | |
# we're only interested in the text of the log entry | |
entry=$(echo "${tokens[3]}" | xargs) | |
# get rid of windows carriage return | |
entry="$(echo $entry | sed 's/\r//g')" | |
if grep -iq "Got handshake from client" <<< "$entry" | |
then | |
# grab everything in the entry past the matching text and mark that we have a recent steam id | |
lastSteamID=$(sed -n -e 's/^.*Got handshake from client //p' <<< "$entry") | |
haveSteamID=1 | |
elif grep -iq "Got character ZDOID from" <<< "$entry" | |
then | |
# grab everything in the entry past the matching text and mark that we have a recent player name | |
playerName=$(sed -n -e 's/^.*Got character ZDOID from //p' <<< "$entry") | |
havePlayerName=1 | |
# add the name and id to the array for recall later | |
SteamID[$lastSteamID]=$playerName | |
# if we have both a recent name and recent steam id go ahead and assume we have a new client that connected and send alert | |
if [[ havePlayerName -eq 1 && haveSteamID -eq 1 ]] | |
then | |
# grab the steam id profile url and name | |
response=$(curl -Gs -d "steamids=${lastSteamID}" -d "key=${STEAMKEY}" https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/) | |
profile=$(jq '.response.players[0].profileurl' <<< $response | tr -d "\"") | |
personaname=$(jq '.response.players[0].personaname' <<< $response | tr -d "\"") | |
# output to terminal | |
echo "Player ${playerName} (probably ${lastSteamID}) has joined the server - Steam profile ${personaname} (${profile})" | |
# send to Discord | |
curl -X POST --data "{\"content\": \"Player ${playerName} (probably ${lastSteamID}) has joined the server - Steam profile ${personaname} (${profile})\"}" --header "Content-Type:application/json" "$WEBHOOK_URL" | |
# reset variables so we're not sending alerts without it being a new connection | |
havePlayerName=0 | |
haveSteamID=0 | |
fi | |
elif grep -iq "Closing socket" <<< "$entry" | |
then | |
# grab everything in the entry past the matching text | |
socket=$(sed -n -e 's/^.*Closing socket //p' <<< "$entry") | |
# check that it's an actual socket closing | |
if [ "$socket" != "0" ] | |
then | |
# output to terminal | |
echo "SteamID ${socket} left the server (was probably ${SteamID[$socket]})" | |
# send to Discord | |
curl -X POST --data "{\"content\": \"SteamID ${socket} left the server (was probably ${SteamID[$socket]})\"}" --header "Content-Type:application/json" "$WEBHOOK_URL" | |
fi | |
else | |
# this should never happen but is included for failover | |
echo "unhandled entry:" "$entry" | |
fi | |
fi | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This script monitors a Valheim server log (in my case generated by linuxgsm, but could be saved via redirection when starting the server in normal scenarios) and triggers a Discord webhook when someone joins or leaves. It's not exactly accurate at all times because there are no log entries on join or part that match, so we have to guess using the most recent steamid handshake with the player name, then remember it for later when the steamid closes the socket and we can guess who it was.
I found there were player connection refreshes without new handshakes so I made it not report unless both were collected and then clearing those values after a discord alert is sent.