Compare commits

..

10 commits
2.0.5 ... 2.2.0

Author SHA1 Message Date
a8492ad00b bump: 2.2.0 2024-06-26 12:29:48 +02:00
1306a477e9 Default blacklist to use only jfreu.plugin.php 2024-06-26 12:26:35 +02:00
86287db9ab Add VALIDATION_KEY to environment 2024-06-26 12:26:35 +02:00
eb3d051cc7 Try to determine WAN IP via ipify.org 2024-06-26 12:26:35 +02:00
fanyx
519e1946ca Changes to custom playlist parsing
Disable custom playlists by default
Guide on how to enable persistent playlist.xml usage
2022-12-24 13:40:42 +01:00
fanyx
e53bee942c Bump image tag to 2.1.0 2022-12-21 12:40:45 +01:00
b9d274cc2d Add default .env-files 2022-07-21 16:21:25 +02:00
fanyx
d408522060 Add TCP port and missing xaseco default configs 2022-06-28 10:43:58 +02:00
fanyx
c43f155ae2 rasp.settings.php needs to be in root folder 2022-06-27 10:48:03 +02:00
f6bda80b82 force take ownership of runtime directories 2022-06-27 09:50:48 +02:00
13 changed files with 272 additions and 20 deletions

46
.env-example Normal file
View file

@ -0,0 +1,46 @@
# TMSERVER
SERVER_LOGIN=<Dedicated Server Login>
SERVER_LOGIN_PASSWORD=
VALIDATION_KEY=
SERVER_SA_PASSWORD=
SERVER_ADM_PASSWORD=
SERVER_PORT=2350
SERVER_P2P_PORT=3450
SERVER_NAME=Trackmania Server
SERVER_COMMENT=This is a Trackmania Server
SERVER_PASSWORD=
HIDE_SERVER=0
MAX_PLAYERS=32
PACKMASK=stadium
GAMEMODE=1
CHATTIME=10000
FINISHTIMEOUT=1
DISABLERESPAWN=0
ROUNDS_POINTSLIMIT=30
TIMEATTACK_LIMIT=180000
TEAM_POINTSLIMIT=50
TEAM_MAXPOINTS=6
LAPS_NBLAPS=5
LAPS_TIMELIMIT=0
CUP_POINTSLIMIT=100
CUP_ROUNDSPERCHALLENGE=5
CUP_NBWINNERS=3
CUP_WARMUPDURATION=2
CUSTOM_PLAYLIST=
# XASECO
MASTERADMIN_LOGIN=<Your Login>
MYSQL_HOST=db
MYSQL_LOGIN=trackmania
MYSQL_DATABASE=trackmania
MYSQL_PASSWORD=

4
.env-mysql-example Normal file
View file

@ -0,0 +1,4 @@
MYSQL_ROOT_PASSWORD=
MYSQL_DATABASE=trackmania
MYSQL_USER=trackmania
MYSQL_PASSWORD=

View file

@ -135,6 +135,7 @@ in the `tracks/` folder and mounting it to `/var/lib/tmserver/GameData/Tracks/Cu
You can add tracks to a playlist in a simple way. You can add tracks to a playlist in a simple way.
Create a plaintext file like in the example below and mount it to `/var/lib/tmserver/playlist.txt`. Create a plaintext file like in the example below and mount it to `/var/lib/tmserver/playlist.txt`.
To enable parsing of this file set `CUSTOM_PLAYLIST` in your env-file to anything but an empty string.
The tracks for the server are stored relative to `/var/lib/tmserver/GameData/Tracks`. The tracks for the server are stored relative to `/var/lib/tmserver/GameData/Tracks`.
Creating your own playlist is as easy as specifying each track on a separate line in the `playlist.txt` Creating your own playlist is as easy as specifying each track on a separate line in the `playlist.txt`
@ -158,6 +159,39 @@ Custom/mini01.Challenge.Gbx
Custom/SpeedxZxZ.Challenge.Gbx Custom/SpeedxZxZ.Challenge.Gbx
``` ```
---
**NOTE**
When mounting your own `playlist.xml` file to the container you overwrite a lot of
customization options that usually would be parsed from environment variables.
```xml
<gameinfos>
<game_mode>@GAMEMODE@</game_mode>
<chat_time>@CHATTIME@</chat_time>
<finishtimeout>@FINISHTIMEOUT@</finishtimeout>
<disablerespawn>@DISABLERESPAWN@</disablerespawn>
<rounds_pointslimit>@ROUNDS_POINTSLIMIT@</rounds_pointslimit>
<team_pointslimit>@TEAM_POINTSLIMIT@</team_pointslimit>
<team_maxpoints>@TEAM_MAXPOINTS@</team_maxpoints>
<timeattack_limit>@TIMEATTACK_LIMIT@</timeattack_limit>
<timeattack_synchstartperiod>0</timeattack_synchstartperiod>
<laps_nblaps>@LAPS_NBLAPS@</laps_nblaps>
<laps_timelimit>@LAPS_TIMELIMIT@</laps_timelimit>
<cup_pointslimit>@CUP_POINTSLIMIT@</cup_pointslimit>
<cup_roundsperchallenge>@CUP_ROUNDSPERCHALLENGE@</cup_roundsperchallenge>
<cup_nbwinners>@CUP_NBWINNERS@</cup_nbwinners>
<cup_warmupduration>@CUP_WARMUPDURATION@</cup_warmupduration>
</gameinfos>
```
If you're familiar with these options anyway, you can mount `playlist.xml` to
`/var/lib/tmserver/GameData/MatchSettings/playlist.xml` and use it as a complete
and persistent configuration file that can be written to by plugins or external tools
like RemoteCP.
---
### Custom configuration files ### Custom configuration files
Most plugins need you to provide valid configuration files to function in the first place. Most plugins need you to provide valid configuration files to function in the first place.

View file

@ -1,7 +1,6 @@
version: '3.8'
services: services:
tmserver: tmserver:
image: fanyx/tmserver:2.0.5 image: fanyx/tmserver:2.2.0
container_name: trackmania_tmserver container_name: trackmania_tmserver
depends_on: depends_on:
- db - db
@ -14,6 +13,7 @@ services:
- ./plugins:/var/lib/xaseco/plugins/custom # => Custom plugins - ./plugins:/var/lib/xaseco/plugins/custom # => Custom plugins
- ./config:/var/lib/xaseco/config # => Custom configuration files - ./config:/var/lib/xaseco/config # => Custom configuration files
ports: ports:
- "2350:2350"
- "2350:2350/udp" - "2350:2350/udp"
- "3450:3450/udp" - "3450:3450/udp"
db: db:

View file

@ -2,7 +2,9 @@
set -e set -e
[[ "$(id -u)" == 0 ]] && s6-setuidgid trackmania "$0" [[ "$(id -u)" == 0 ]] && \
chown -R trackmania:trackmania /var/lib/xaseco && \
s6-setuidgid trackmania "$0"
cd /var/lib/xaseco cd /var/lib/xaseco

View file

@ -15,13 +15,13 @@
<password>User</password> <password>User</password>
</level> </level>
</authorization_levels> </authorization_levels>
<masterserver_account> <masterserver_account>
<login>@SERVER_LOGIN@</login> <login>@SERVER_LOGIN@</login>
<password>@SERVER_LOGIN_PASSWORD@</password> <password>@SERVER_LOGIN_PASSWORD@</password>
<validation_key>@VALIDATION_KEY@</validation_key> <validation_key>@VALIDATION_KEY@</validation_key>
</masterserver_account> </masterserver_account>
<server_options> <server_options>
<name>@SERVER_NAME@</name> <name>@SERVER_NAME@</name>
<comment>@SERVER_COMMENT@</comment> <comment>@SERVER_COMMENT@</comment>
@ -29,17 +29,17 @@
<max_players>@MAX_PLAYERS@</max_players> <max_players>@MAX_PLAYERS@</max_players>
<password>@SERVER_PASSWORD@</password> <password>@SERVER_PASSWORD@</password>
<max_spectators>32</max_spectators> <max_spectators>32</max_spectators>
<password_spectator></password_spectator> <password_spectator></password_spectator>
<ladder_mode>forced</ladder_mode> <!-- value between 'inactive', 'forced' (or '0', '1') --> <ladder_mode>forced</ladder_mode> <!-- value between 'inactive', 'forced' (or '0', '1') -->
<ladder_serverlimit_min>0</ladder_serverlimit_min> <!-- Those values will be clamped to the limits authorized on http://official.trackmania.com/tmf-ladderserver/ --> <ladder_serverlimit_min>0</ladder_serverlimit_min> <!-- Those values will be clamped to the limits authorized on http://official.trackmania.com/tmf-ladderserver/ -->
<ladder_serverlimit_max>50000</ladder_serverlimit_max> <ladder_serverlimit_max>50000</ladder_serverlimit_max>
<enable_p2p_upload>True</enable_p2p_upload> <enable_p2p_upload>True</enable_p2p_upload>
<enable_p2p_download>True</enable_p2p_download> <enable_p2p_download>True</enable_p2p_download>
<callvote_timeout>60000</callvote_timeout> <callvote_timeout>60000</callvote_timeout>
<callvote_ratio>0.5</callvote_ratio> <!-- default ratio. value in [0..1], or -1 to forbid. --> <callvote_ratio>0.5</callvote_ratio> <!-- default ratio. value in [0..1], or -1 to forbid. -->
<callvote_ratios> <callvote_ratios>
@ -56,27 +56,27 @@
<use_changing_validation_seed>False</use_changing_validation_seed> <use_changing_validation_seed>False</use_changing_validation_seed>
</server_options> </server_options>
<system_config> <system_config>
<connection_uploadrate>512</connection_uploadrate> <!-- Kbps (kilo bits per second) --> <connection_uploadrate>512</connection_uploadrate> <!-- Kbps (kilo bits per second) -->
<connection_downloadrate>8192</connection_downloadrate> <!-- Kbps --> <connection_downloadrate>8192</connection_downloadrate> <!-- Kbps -->
<force_ip_address></force_ip_address> <force_ip_address>@FORCE_IP_ADDRESS@</force_ip_address>
<server_port>@SERVER_PORT@</server_port> <server_port>@SERVER_PORT@</server_port>
<server_p2p_port>@SERVER_P2P_PORT@</server_p2p_port> <server_p2p_port>@SERVER_P2P_PORT@</server_p2p_port>
<client_port>0</client_port> <client_port>0</client_port>
<bind_ip_address></bind_ip_address> <bind_ip_address></bind_ip_address>
<use_nat_upnp></use_nat_upnp> <use_nat_upnp></use_nat_upnp>
<p2p_cache_size>600</p2p_cache_size> <p2p_cache_size>600</p2p_cache_size>
<xmlrpc_port>5000</xmlrpc_port> <xmlrpc_port>5000</xmlrpc_port>
<xmlrpc_allowremote>True</xmlrpc_allowremote> <!-- If you specify an ip adress here, it'll be the only accepted adress. this will improve security. --> <xmlrpc_allowremote>True</xmlrpc_allowremote> <!-- If you specify an ip adress here, it'll be the only accepted adress. this will improve security. -->
<blacklist_url></blacklist_url> <blacklist_url></blacklist_url>
<guestlist_filename></guestlist_filename> <guestlist_filename></guestlist_filename>
<blacklist_filename></blacklist_filename> <blacklist_filename></blacklist_filename>
<packmask>@PACKMASK@</packmask> <packmask>@PACKMASK@</packmask>
<allow_spectator_relays>False</allow_spectator_relays> <allow_spectator_relays>False</allow_spectator_relays>

View file

@ -10,6 +10,7 @@ SERVER_LOGIN_PASSWORD=${SERVER_LOGIN_PASSWORD?:ERROR | ServerLoginPassword is mi
config+=( "SERVER_LOGIN_PASSWORD" ) config+=( "SERVER_LOGIN_PASSWORD" )
# Optional # Optional
VALIDATION_KEY=${VALIDATION_KEY:-} && config+=( "VALIDATION_KEY" )
SERVER_SA_PASSWORD=${SERVER_SA_PASSWORD:-$(pwgen -s 24 1)} && config+=( "SERVER_SA_PASSWORD" ) SERVER_SA_PASSWORD=${SERVER_SA_PASSWORD:-$(pwgen -s 24 1)} && config+=( "SERVER_SA_PASSWORD" )
echo "INFO | SERVER_SA_PASSWORD: ${SERVER_SA_PASSWORD}" echo "INFO | SERVER_SA_PASSWORD: ${SERVER_SA_PASSWORD}"
SERVER_ADM_PASSWORD=${SERVER_ADM_PASSWORD:-$(pwgen -s 24 1)} && config+=( "SERVER_ADM_PASSWORD" ) SERVER_ADM_PASSWORD=${SERVER_ADM_PASSWORD:-$(pwgen -s 24 1)} && config+=( "SERVER_ADM_PASSWORD" )
@ -18,6 +19,8 @@ SERVER_PORT=${SERVER_PORT:-2350} && config+=( "SERVER_PORT" )
echo "INFO | SERVER_PORT: ${SERVER_PORT}" echo "INFO | SERVER_PORT: ${SERVER_PORT}"
SERVER_P2P_PORT=${SERVER_P2P_PORT:-3450} && config+=( "SERVER_P2P_PORT" ) SERVER_P2P_PORT=${SERVER_P2P_PORT:-3450} && config+=( "SERVER_P2P_PORT" )
echo "INFO | SERVER_P2P_PORT: ${SERVER_P2P_PORT}" echo "INFO | SERVER_P2P_PORT: ${SERVER_P2P_PORT}"
FORCE_IP_ADDRESS=${FORCE_IP_ADDRESS:-${curl https://api.ipify.org}} && config += ( "FORCE_IP_ADDRESS" )
echo "INFO | FORCE_IP_ADDRESS: ${FORCE_IP_ADDRESS}"
SERVER_NAME=${SERVER_NAME:-Trackmania Server} && config+=( "SERVER_NAME" ) SERVER_NAME=${SERVER_NAME:-Trackmania Server} && config+=( "SERVER_NAME" )
echo "INFO | SERVER_NAME: ${SERVER_NAME}" echo "INFO | SERVER_NAME: ${SERVER_NAME}"
SERVER_COMMENT=${SERVER_COMMENT:-This is a Trackmania Server} && config+=( "SERVER_COMMENT" ) SERVER_COMMENT=${SERVER_COMMENT:-This is a Trackmania Server} && config+=( "SERVER_COMMENT" )
@ -71,4 +74,4 @@ done
for idx in "${!playlist[@]}"; do for idx in "${!playlist[@]}"; do
arg=${playlist[$idx]} arg=${playlist[$idx]}
sed -i -e "s/@$arg@/${!arg}/g" GameData/Tracks/MatchSettings/playlist.xml sed -i -e "s/@$arg@/${!arg}/g" GameData/Tracks/MatchSettings/playlist.xml
done done

View file

@ -2,19 +2,23 @@
echo "INFO | Parsing custom playlist..." echo "INFO | Parsing custom playlist..."
CUSTOM_PLAYLIST=${CUSTOM_PLAYLIST:-playlist.txt} [[ -z "${CUSTOM_PLAYLIST}" ]] && \
echo "INFO | Custom Playlist is not enabled, keeping default or user-edited playlist" && \
exit 0
PLAYLIST_PATH=${PLAYLIST_PATH:-playlist.txt}
PLAYLIST_FILE='GameData/Tracks/MatchSettings/playlist.xml' PLAYLIST_FILE='GameData/Tracks/MatchSettings/playlist.xml'
if [[ -f "${CUSTOM_PLAYLIST}" ]]; then if [[ -f "${PLAYLIST_PATH}" ]]; then
count=1 count=1
while read l; do while read l; do
xmlstarlet ed -L -s /playlist -t elem -n challenge $PLAYLIST_FILE xmlstarlet ed -L -s /playlist -t elem -n challenge $PLAYLIST_FILE
xmlstarlet ed -L -s "/playlist/challenge[${count}]" -t elem -n file -v "${l}" $PLAYLIST_FILE xmlstarlet ed -L -s "/playlist/challenge[${count}]" -t elem -n file -v "${l}" $PLAYLIST_FILE
count=$((count+1)) count=$((count+1))
done < $CUSTOM_PLAYLIST done < $PLAYLIST_PATH
else else
xmlstarlet ed -L -s /playlist -t elem -n challenge $PLAYLIST_FILE xmlstarlet ed -L -s /playlist -t elem -n challenge $PLAYLIST_FILE
xmlstarlet ed -L -s "playlist/challenge[1]" -t elem -n file -v "Challenges/Nadeo/A01-Race.Challenge.Gbx" $PLAYLIST_FILE xmlstarlet ed -L -s "playlist/challenge[1]" -t elem -n file -v "Challenges/Nadeo/A01-Race.Challenge.Gbx" $PLAYLIST_FILE
fi fi
echo "INFO | Finished parsing playlist files." echo "INFO | Finished parsing playlist files"

View file

@ -2,7 +2,9 @@
set -e set -e
[[ "$(id -u)" == 0 ]] && s6-setuidgid trackmania "$0" [[ "$(id -u)" == 0 ]] && \
chown -R trackmania:trackmania /var/lib/tmserver && \
s6-setuidgid trackmania "$0"
cd /var/lib/tmserver cd /var/lib/tmserver

2
xaseco/blacklist Normal file
View file

@ -0,0 +1,2 @@
jfreu.lite.php
jfreu.chat.php

100
xaseco/matchsave.xml Normal file
View file

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8" ?>
<matchsave_settings>
<!-- use the following section to force known logins to a specific team -->
<teamforce_teams>
<team>
<name>XXX</name>
<logins>
<login>xxx-max</login>
<login>siteguru</login>
<!-- ... add as many logins as you like -->
</logins>
</team>
<!-- ... add as many teams as you like -->
<default_team_name>Challengers</default_team_name> <!-- This is the team where all other players end up when teamforce is enabled -->
</teamforce_teams>
<!-- now the design stuff, colors and so on -->
<str_points_this_round>$i$0AFPoints This Round</str_points_this_round>
<str_points_this_match>$i$AF0Points This Match</str_points_this_match>
<col_chat_plugin>{#emotic}</col_chat_plugin>
<col_chat_default>{#message}</col_chat_default>
<col_chat_highlite>{#server}</col_chat_highlite>
<col_window_default>$000</col_window_default>
<col_window_highlite>$f00</col_window_highlite>
<col_window_highlite_team>$0af</col_window_highlite_team>
<col_window_special>$i$n</col_window_special>
<col_window_separator>$fff</col_window_separator>
<col_window_hint>$n$888</col_window_hint>
<col_round_points>{#highlite}</col_round_points>
<col_match_points>{#highlite}</col_match_points>
<col_teamname_round>$0af</col_teamname_round>
<col_teamname_round_highlite>{#server}</col_teamname_round_highlite>
<col_teamname_match>$af0</col_teamname_match>
<col_teamname_match_highlite>{#server}</col_teamname_match_highlite>
<!-- help messages - they show up when the points are displayed, but only if you activate them -->
<help_enabled>True</help_enabled>
<!-- you can add more random messages (these will only show up if the player does not belong to a team-->
<hlp_no_team>{#server}To join a team type "{#welcome}/team {#message}yourteamname{#server}"</hlp_no_team>
<hlp_random_msg_no_team>{#server}See all team options by typing "{#welcome}/team {#message}help{#server}"</hlp_random_msg_no_team>
<hlp_random_msg_no_team>{#server}Join a team and chat with your teammates via "{#welcome}/tc {#message}Hello Teammates{#server}"</hlp_random_msg_no_team>
<hlp_random_msg_no_team>{#server}See the current match standings by typing "{#welcome}/standings{#server}"</hlp_random_msg_no_team>
<!-- you can add more random messages (these will only show up if the player already belongs to a team-->
<hlp_change_team>{#server}Change your teamname with "{#welcome}/team {#message}yourteamname{#server}"</hlp_change_team>
<hlp_random_msg>{#server}See all team options by typing "{#welcome}/team {#message}help{#server}"</hlp_random_msg>
<hlp_random_msg>{#server}See the current match standings by typing "{#welcome}/standings{#server}"</hlp_random_msg>
<hlp_random_msg>{#server}Chat with your teammates by typing "{#welcome}/tc {#message}Hello Teammates{#server}"</hlp_random_msg>
<!-- last but not least, edit the startup configuration below -->
<show_teamname_changes_to_public>true</show_teamname_changes_to_public> <!-- Determines whether a teamname change will be shown to all players or not (affects only the /teamname or /team command)-->
<admin_can_read_teamchat>True</admin_can_read_teamchat> <!-- If true admins can read the teamchat of other teams -->
<teamchat_enabled>true</teamchat_enabled> <!-- Enable or disable teamchat -->
<teamchat_prefix>{#highlite}[Team]</teamchat_prefix> <!-- Prefix shown in front of each teamchat line -->
<team_force_enabled>False</team_force_enabled> <!-- Determines whether all players are forced to be in a team -->
<others_can_score>True</others_can_score> <!-- Determines whether teamless players' scores are tracked or not -->
<teamname_colors_allowed>False</teamname_colors_allowed> <!-- Determines if the teamnames are allowed to be color coded -->
<teamname_max_length>12</teamname_max_length> <!-- Determines how long a teamname is allowed to be -->
<match_results_timeout>5000</match_results_timeout> <!-- Match Result window timeout in milliseconds -->
<save_to_db>True</save_to_db> <!-- Shall the teamnames be saved to a database -->
<save_to_file>True</save_to_file> <!-- Shall the results be written to files -->
<!-- some filenames -->
<template_name>html.tpl</template_name>
<output_name>race_results.html</output_name>
<output_name_last>race_results_last.html</output_name_last>
<output_name_match>match_results.html</output_name_match>
<!-- path to your playlist directory, enable one of these two: -->
<!-- Windows -->
<!-- <playlist_dir>D:/TMDedicated/GameData/Tracks/MatchSettings</playlist_dir> -->
<!-- Linux -->
<playlist_dir>/home/tmf/TMF/GameData/Tracks/MatchSettings</playlist_dir>
<!-- basic settings -->
<max_player_count>16</max_player_count>
<format_date>Y-m-d</format_date>
<format_time>H:i</format_time>
<points>10, 8, 6, 4, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0</points>
<!-- enable the whole plugin -->
<enabled>True</enabled>
</matchsave_settings>

55
xaseco/musicserver.xml Normal file
View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8" ?>
<settings>
<!-- override a track's custom music? -->
<override_track>False</override_track>
<!-- automatically load next song upon next track? -->
<auto_nextsong>True</auto_nextsong>
<!-- automatically shuffle songs at start-up & reload? -->
<auto_shuffle>False</auto_shuffle>
<!-- allow jukeboxing songs by players? -->
<allow_jukebox>True</allow_jukebox>
<!-- strip subdirs when showing song files? -->
<strip_subdirs>False</strip_subdirs>
<!-- strip extensions when showing song files? -->
<strip_exts>False</strip_exts>
<!-- read tags from all .ogg songs? -->
<cache_tags>True</cache_tags>
<!-- use read-only cache file? -->
<cache_readonly>False</cache_readonly>
<!-- filename in main directory to store tags -->
<cache_file>musictagscache.xml</cache_file>
<!-- full http link to directory holding the song files -->
<!-- http server must allow direct download of those files -->
<!-- OR a path below the server's GameData directory (e.g. -->
<!-- "Music/") which allows serving songs without webserver -->
<music_server>YOUR_SERVER_URL</music_server>
<!-- list of song files at your music server in .ogg or .mux -->
<!-- avoid spaces and special characters in the filenames and -->
<!-- http link, and observe correct upper/lowercase characters -->
<song_files>
<song>YOUR_FIRST_SONG.ogg</song>
<song>YOUR_SECOND_SONG.mux</song>
<song>YOUR_THIRD_SONG.ogg</song>
<!-- and so on -->
</song_files>
<messages>
<current>{#server}> {#music}The current song is: {#highlite}{1}</current>
<next>{#server}>> {#music}{1}$z$s {#highlite}{2}$z$s{#music} loaded the next song: {#highlite}{3}</next>
<reloaded>{#server}>> {#music}{1}$z$s {#highlite}{2}$z$s{#music} reloaded music config and cleared jukebox!</reloaded>
<sorted>{#server}>> {#music}{1}$z$s {#highlite}{2}$z$s{#music} sorted song list and cleared jukebox!</sorted>
<shuffled>{#server}>> {#music}{1}$z$s {#highlite}{2}$z$s{#music} shuffled song list and cleared jukebox!</shuffled>
<jukebox>{#server}>> {#highlite}{1}{#music} jukeboxed song: {#highlite}{2}</jukebox>
<jukebox_already>{#server}> {#music}You already have a song in the jukebox! Wait till it's been played before adding another.</jukebox_already>
<jukebox_dupl>{#server}> {#music}This song has already been added to the jukebox, pick another one.</jukebox_dupl>
<jukebox_notfound>{#server}> {#music}Song_ID not found - Type {#highlite}/music list{#music} to see all songs.</jukebox_notfound>
<jukebox_drop>{#server}>> {#music}Player {#highlite}{1}{#music} dropped his/her song {#highlite}{2}{#music} from jukebox!</jukebox_drop>
<jukebox_nodrop>{#server}> {#music}You don't have a song in the jukebox, use {#highlite}/music Song_ID{#music} to add one...</jukebox_nodrop>
<jukebox_empty>{#server}> {#music}No songs in the jukebox, use {#highlite}/music Song_ID{#music} to add one...</jukebox_empty>
<no_jukebox>{#server}> {#highlite}/music #{#music} is not currently enabled on this server.</no_jukebox>
<shutdown>{#server}>> {#music}{1}$z$s {#highlite}{2}$z$s{#music} disabled server music!</shutdown>
</messages>
</settings>