# eval TMWW_ALTSPATH="${TMWW_ALTSPATH:-${DIRCONFIG}/alts}"
TMWW_ALTSPATH="${TMWW_ALTSPATH:-${DIRCONFIG}/alts}"
TMWW_ALTSPATH=${TMWW_ALTSPATH}/${servername}
TMWW_UPDATELIMITED="${TMWW_UPDATELIMITED:-no}"
TMWW_LIMITED="${TMWW_LIMITED:-no}"
playerdb="${TMWW_ALTSPATH}/dbplayers.jsonl"
limiteddb="${TMWW_ALTSPATH}/limited.jsonl"
# separate temp files in case of lockfile timeout
# using PRIVTMP here to avoid endless chmod to ensure multiuser support
playerdbtmp=${TMWW_PRIVTMP}/playerdb.temp
playerdbtmp2=${TMWW_PRIVTMP}/playerdb.temp2
check_jq() {
if [ -z "${JQ}" ]; then
error "jq not found. Aborting."
return 1
fi
}
check_player() {
check_string_chars "$1" "*[!${playerchars}]*" "Disallowed characters at player name" || return 1
if ! grep -m 1 "\"player\":\"$1\"" "${playerdb}" >/dev/null 2>&1 ; then
error "No such player: $1"; return 1
fi
}
# format: single line, space separated
player_fields_string="name wiki trello server port tmwc active cc"
player_fields_array="aka roles alts accounts links xmpp mail skype repo forum"
player_fields_roles="content sound music gm code map pixel admin host wiki advisor translator packager web concept dude"
aux_player_show_parties_by_player() {
local party
aux_player_query_chardb "$1" | while read -r line; do
party=$( func_party_get "${line#????????}" )
if [ -z "${party}" ]; then
printf "%s\n" "${line}"
else
printf "%-32s -- %s\n" "${line}" "${party}"
fi
done
# player not recorded in dbchars most probably has no party known
aux_player_query_alts "$1"
}
aux_player_query_chardb() {
aux_player_ids "$1" | while read line; do
aux_char_show_ids_by_id "${line}"
done
}
# single backslash sequence will be added as is
# duplicate backslashes if you want to insert two or more backslashes in row
# duplicates in field elements will be skipped
# adding alt will attempt to resolve it
# adding account will not check for duplicates in other records
# PLAYER FIELD value VALUE
# PLAYER FIELD element VALUE
func_player_add() {
[ -z "$5" -a ! -z "$4" ] || { error_incorrect; return 1; }
# exit if field was player. use create/rename/remove to change player
[ "$2" = "player" ] && return 1
# enforce types for standart fields
if printf "%s\n" "${player_fields_string}" | grep -wq -- "$2" ; then
[ "$3" != "value" ] && { error_params "Field must be of string type"; return 1; }
elif printf "%s\n" "${player_fields_array}" | grep -wq -- "$2" ; then
[ "$3" != "element" ] && { error_params "Field must be array"; return 1; }
fi
# check lowercase field name
check_string_chars "$2" "*[!a-z]*" "Field name must be lowercase" || return 1
check_jq || return 2
set_db_lock
cp -f "${playerdb}" "${playerdbtmp}" >/dev/null 2>&1
# result is undefined with non-default field of incompatible type
if [ "$3" = "value" ]; then
${JQ} -S -c -M --arg name "$1" --arg element "$4" \
"if (.[\"player\"]==\$name) \
then .[\"$2\"] = \$element else . end" \
"${playerdbtmp}" > "${playerdbtmp2}" 2>&-
elif [ "$3" = "element" ]; then
# check for duplicates in array
if [ "$2" = "alts" ]; then
result=$(func_char_get "$4")
if [ -z "$result" ]; then
field="$2"; element="$4"
else
field="accounts"; element="$result"
fi
else
field="$2"; element="$4"
fi
# silly comparison bcause jq can't strict "contains"
${JQ} -S -c -M --arg name "$1" --arg element "$element" \
"if ((.[\"player\"]==\$name) and \
((has(\"${field}\") and (.[\"${field}\"]|map(.==\$element)|contains([true])))|not)) \
then .[\"${field}\"] += [\$element] else . end" \
"${playerdbtmp}" > "${playerdbtmp2}" 2>&-
else error_incorrect; unset_db_lock; return 1; fi
if [ "$?" -eq 0 ]; then
store_shared "${playerdbtmp2}" "${playerdb}"
else
error "Error occured. Contact db owner to check consistency."
fi
unset_db_lock
func_player_lregen
}
aux_player_del_field() {
check_jq || return 2
set_db_lock
cp -f "${playerdb}" "${playerdbtmp}" >/dev/null 2>&1
${JQ} -S -c -M --arg name "$1" --arg field "$2" \
"if (.[\"player\"]==\$name) then \
(with_entries(select(.key!=\$field))) else . end" \
"${playerdbtmp}" > "${playerdbtmp2}" 2>&-
if [ "$?" -eq 0 ]; then
store_shared "${playerdbtmp2}" "${playerdb}"
else
error "Error occured. Contact db owner to check consistency."
fi
unset_db_lock
}
aux_player_del_element() {
check_jq || return 2
set_db_lock
cp -f "${playerdb}" "${playerdbtmp}" >/dev/null 2>&1
# remove element and field if no elements inside
${JQ} -S -c -M --arg name "$1" --arg element "$4" \
"if ((.[\"player\"]==\$name) and \
(has(\"$2\") and (.[\"$2\"]|map(.==\$element)|contains([true])))) \
then .[\"$2\"] -= [\$element] else . end | \
with_entries(if (.value|length)>0 then . else empty end)" \
"${playerdbtmp}" > "${playerdbtmp2}" 2>&-
if [ "$?" -eq 0 ]; then
store_shared "${playerdbtmp2}" "${playerdb}"
else
error "Error occured. Contact db owner to check consistency."
fi
unset_db_lock
}
func_player_del() {
# check lowercase field name
check_string_chars "$2" "*[!a-z]*" "Field name must be lowercase." || return 1
if [ -z "$3" -a -n "$2" ]; then
aux_player_del_field "$@"
elif [ -z "$5" -a -n "$4" -a "$3" = "element" ]; then
aux_player_del_element "$@"
else error_incorrect; fi
func_player_lregen
}
# this pattern generator skips spaces for char/party fuzzy search functions
aux_fuzzy_pattern() {
# constructing horrible case-insensitive pattern
# with missed, suppressed and few l33t chars
# this provides 1 possible error
# for more possible errors just use agrep; seems ok with 1
printf "%s" "$*" | sed "s/\(.\)/\1 /g" | ${AWK} ${AWKPARAMS} -- '
BEGIN { chars = "" }
{
for ( i=1; i<=NF; i++ ) {
s=""
if ( $i ~ "l" ) s = "I"
if ( $i ~ "I" ) s = "l"
if ( $i ~ "O" ) s = "0"
if ( $i ~ "0" ) s = "O"
# if ( $i ~ "5" ) s = "sS"
# if ( $i ~ "s|S" ) s = "5"
chars = sprintf("%s%s", chars, "[" tolower($i) toupper($i) s "] ")
}
n = split(chars, fuzzy)
# printf("(")
# letter not found
for ( i=1; i<=n; i++ ) {
# printf("%s", fuzzy[1])
for ( j=1; j<=n; j++ ) {
if ( j == i )
printf("%s?", fuzzy[j])
else
printf("%s", fuzzy[j])
}
printf("|")
}
# letter is different
for ( i=1; i<=n; i++ ) {
# printf("%s", fuzzy[1])
for ( j=1; j<=n; j++ ) {
if ( j == i )
printf(".?")
else
printf("%s", fuzzy[j])
}
printf("|")
}
# missing letter between
for ( i=1; i<n; i++ ) {
for ( j=1; j<=n; j++ ) {
if ( j == i )
printf("%s.?", fuzzy[j])
else
printf("%s", fuzzy[j])
}
if ( i != n - 1) printf("|")
}
# printf(")")
}
'
}