Compare commits
8 Commits
f50397562e
...
fcf04ef651
Author | SHA1 | Date |
---|---|---|
fanyx | fcf04ef651 | |
fanyx | 6ff45af1cb | |
fanyx | f1b87b46b3 | |
fanyx | 8cd2157816 | |
fanyx | e5ec30e564 | |
fanyx | ffaeb8a8dc | |
fanyx | 53f162c802 | |
fanyx | d6eb6e7ad9 |
|
@ -0,0 +1,4 @@
|
|||
.gitignore
|
||||
/.tmp
|
||||
.env
|
||||
.env-mysql
|
|
@ -0,0 +1,24 @@
|
|||
FROM php:5.6-alpine
|
||||
ARG S6_OVERLAY_VERSION=3.1.1.1
|
||||
|
||||
RUN apk add --no-cache pwgen gettext xmlstarlet bash xz
|
||||
RUN docker-php-ext-install mysql
|
||||
|
||||
COPY tmserver/ /var/lib/tmserver
|
||||
COPY xaseco/ /var/lib/xaseco
|
||||
|
||||
RUN addgroup -S trackmania && adduser -D -H -S trackmania -G trackmania
|
||||
RUN chown -R trackmania:trackmania /var/lib/tmserver /var/lib/xaseco
|
||||
|
||||
EXPOSE 5000
|
||||
|
||||
CMD ["/var/lib/tmserver/entrypoint.sh"]
|
||||
|
||||
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
|
||||
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
|
||||
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz /tmp
|
||||
RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz
|
||||
ENTRYPOINT ["/init"]
|
||||
|
||||
RUN touch /etc/s6-overlay/s6-rc.d/user/contents.d/xaseco
|
||||
COPY services.d/xaseco/ /etc/s6-overlay/s6-rc.d/xaseco/
|
|
@ -0,0 +1,37 @@
|
|||
version: '3.8'
|
||||
services:
|
||||
tmserver:
|
||||
image: fanyx/tmserver:2.0.0
|
||||
container_name: trackmania_tmserver
|
||||
depends_on:
|
||||
- db
|
||||
restart: always
|
||||
env_file: .env
|
||||
volumes:
|
||||
- ./tracks:/var/lib/tmserver/GameData/Tracks/Challenges/Custom # => Custom tracks
|
||||
- ./blacklist:/var/lib/xaseco/blacklist # => Plugin blacklist
|
||||
- ./plugins:/var/lib/xaseco/plugins/custom # => Custom plugins
|
||||
- ./config:/var/lib/xaseco/config # => Custom configuration files
|
||||
ports:
|
||||
- "2350:2350/udp"
|
||||
- "3450:3450/udp"
|
||||
db:
|
||||
image: mysql:5
|
||||
container_name: trackmania_db
|
||||
restart: always
|
||||
env_file: .env-mysql
|
||||
volumes:
|
||||
- trackmania-db:/var/lib/mysql
|
||||
pma:
|
||||
image: phpmyadmin/phpmyadmin
|
||||
container_name: trackmania_phpmyadmin
|
||||
depends_on:
|
||||
- db
|
||||
environment:
|
||||
- PMA_HOST=db
|
||||
restart: always
|
||||
ports:
|
||||
- "8080:80"
|
||||
|
||||
volumes:
|
||||
trackmania-db:
|
|
@ -0,0 +1,18 @@
|
|||
#!/command/with-contenv bash
|
||||
|
||||
set -e
|
||||
|
||||
[[ "$(id -u)" == 0 ]] && s6-setuidgid trackmania "$0"
|
||||
|
||||
cd /var/lib/xaseco
|
||||
|
||||
# Parse environment to configuration files
|
||||
./bin/eval_env.sh
|
||||
|
||||
# Link custom configuration files
|
||||
./bin/config.sh
|
||||
|
||||
# Parse plugin list
|
||||
./bin/plugins.sh
|
||||
|
||||
exec "php" "aseco.php"
|
|
@ -0,0 +1 @@
|
|||
longrun
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<dedicated>
|
||||
<authorization_levels>
|
||||
<level>
|
||||
<name>SuperAdmin</name>
|
||||
<password>@SERVER_SA_PASSWORD@</password>
|
||||
</level>
|
||||
<level>
|
||||
<name>Admin</name>
|
||||
<password>@SERVER_ADM_PASSWORD@</password>
|
||||
</level>
|
||||
<level>
|
||||
<name>User</name>
|
||||
<password>User</password>
|
||||
</level>
|
||||
</authorization_levels>
|
||||
|
||||
<masterserver_account>
|
||||
<login>@SERVER_LOGIN@</login>
|
||||
<password>@SERVER_LOGIN_PASSWORD@</password>
|
||||
<validation_key>@VALIDATION_KEY@</validation_key>
|
||||
</masterserver_account>
|
||||
|
||||
<server_options>
|
||||
<name>@SERVER_NAME@</name>
|
||||
<comment>@SERVER_COMMENT@</comment>
|
||||
<hide_server>@HIDE_SERVER@</hide_server> <!-- value is 0 (always shown), 1 (always hidden), 2 (hidden from nations) -->
|
||||
|
||||
<max_players>@MAX_PLAYERS@</max_players>
|
||||
<password>@SERVER_PASSWORD@</password>
|
||||
|
||||
<max_spectators>32</max_spectators>
|
||||
<password_spectator></password_spectator>
|
||||
|
||||
<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_max>50000</ladder_serverlimit_max>
|
||||
|
||||
<enable_p2p_upload>True</enable_p2p_upload>
|
||||
<enable_p2p_download>True</enable_p2p_download>
|
||||
|
||||
<callvote_timeout>60000</callvote_timeout>
|
||||
<callvote_ratio>0.5</callvote_ratio> <!-- default ratio. value in [0..1], or -1 to forbid. -->
|
||||
<callvote_ratios>
|
||||
<voteratio command="Ban" ratio="0.65"/>
|
||||
<!-- commands can be "Ban", "Kick", "ChallengeRestart", "NextChallenge", ... -->
|
||||
</callvote_ratios>
|
||||
|
||||
<allow_challenge_download>True</allow_challenge_download>
|
||||
<autosave_replays>False</autosave_replays>
|
||||
<autosave_validation_replays>False</autosave_validation_replays>
|
||||
|
||||
<referee_password></referee_password>
|
||||
<referee_validation_mode>0</referee_validation_mode> <!-- value is 0 (only validate top3 players), 1 (validate all players) -->
|
||||
|
||||
<use_changing_validation_seed>False</use_changing_validation_seed>
|
||||
</server_options>
|
||||
|
||||
<system_config>
|
||||
<connection_uploadrate>512</connection_uploadrate> <!-- Kbps (kilo bits per second) -->
|
||||
<connection_downloadrate>8192</connection_downloadrate> <!-- Kbps -->
|
||||
|
||||
<force_ip_address></force_ip_address>
|
||||
<server_port>$SERVER_PORT</server_port>
|
||||
<server_p2p_port>$SERVER_P2P_PORT</server_p2p_port>
|
||||
<client_port>0</client_port>
|
||||
<bind_ip_address></bind_ip_address>
|
||||
<use_nat_upnp></use_nat_upnp>
|
||||
|
||||
<p2p_cache_size>600</p2p_cache_size>
|
||||
|
||||
<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. -->
|
||||
|
||||
<blacklist_url></blacklist_url>
|
||||
<guestlist_filename></guestlist_filename>
|
||||
<blacklist_filename></blacklist_filename>
|
||||
|
||||
<packmask>stadium</packmask>
|
||||
|
||||
<allow_spectator_relays>False</allow_spectator_relays>
|
||||
|
||||
<!-- <minimum_client_build>2009-10-01</minimum_client_build> -->
|
||||
|
||||
<!-- <disable_coherence_checks>laps</disable_coherence_checks> -->
|
||||
|
||||
<use_proxy>False</use_proxy>
|
||||
<proxy_login></proxy_login>
|
||||
<proxy_password></proxy_password>
|
||||
</system_config>
|
||||
</dedicated>
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<playlist>
|
||||
<gameinfos>
|
||||
<game_mode>@GAMEMODE@</game_mode>
|
||||
<chat_time>@CHATTIME@</chat_time>
|
||||
<finishtimeout>@FINISHTIMEOUT@</finishtimeout>
|
||||
<allwarmupduration>0</allwarmupduration>
|
||||
<disablerespawn>@DISABLERESPAWN@</disablerespawn>
|
||||
<forceshowallopponents>0</forceshowallopponents>
|
||||
<rounds_pointslimit>@ROUNDS_POINTSLIMIT@</rounds_pointslimit>
|
||||
<rounds_usenewrules>0</rounds_usenewrules>
|
||||
<rounds_forcedlaps>0</rounds_forcedlaps>
|
||||
<rounds_pointslimitnewrules>5</rounds_pointslimitnewrules>
|
||||
<team_pointslimit>@TEAM_POINTSLIMIT@</team_pointslimit>
|
||||
<team_maxpoints>@TEAM_MAXPOINTS@</team_maxpoints>
|
||||
<team_usenewrules>0</team_usenewrules>
|
||||
<team_pointslimitnewrules>5</team_pointslimitnewrules>
|
||||
<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>
|
||||
|
||||
<filter>
|
||||
<is_lan>1</is_lan>
|
||||
<is_internet>1</is_internet>
|
||||
<is_solo>0</is_solo>
|
||||
<is_hotseat>0</is_hotseat>
|
||||
<sort_index>7</sort_index>
|
||||
<random_map_order>0</random_map_order>
|
||||
<force_default_gamemode>0</force_default_gamemode>
|
||||
</filter>
|
||||
|
||||
<startindex>0</startindex>
|
||||
</playlist>
|
|
@ -0,0 +1,72 @@
|
|||
#!/command/with-contenv bash
|
||||
|
||||
config=( )
|
||||
playlist=( )
|
||||
|
||||
# Mandatory
|
||||
SERVER_SA_PASSWORD=${SERVER_SA_PASSWORD:?ERROR | SuperAdminPassword needs to be set. Generate with pwgen if needed.} && \
|
||||
config+=( "SERVER_SA_PASSWORD" )
|
||||
SERVER_ADM_PASSWORD=${SERVER_ADM_PASSWORD:?ERROR | AdminPassword needs to be set. Generate with pwgen if needed.} && \
|
||||
config+=( "SERVER_ADM_PASSWORD" )
|
||||
SERVER_LOGIN=${SERVER_LOGIN?:ERROR | ServerLogin is missing. Server cannot start.} && \
|
||||
config+=( "SERVER_LOGIN" )
|
||||
SERVER_LOGIN_PASSWORD=${SERVER_LOGIN_PASSWORD?:ERROR | ServerLoginPassword is missing. Server cannot start.} && \
|
||||
config+=( "SERVER_LOGIN_PASSWORD" )
|
||||
|
||||
# Optional
|
||||
SERVER_PORT=${SERVER_PORT:-2350} && config+=( "SERVER_PORT" )
|
||||
echo "INFO | SERVER_PORT: ${SERVER_PORT}"
|
||||
SERVER_P2P_PORT=${SERVER_P2P_PORT:-3450} && config+=( "SERVER_P2P_PORT" )
|
||||
echo "INFO | SERVER_P2P_PORT: ${SERVER_P2P_PORT}"
|
||||
SERVER_NAME=${SERVER_NAME:-Trackmania Server} && config+=( "SERVER_NAME" )
|
||||
echo "INFO | SERVER_NAME: ${SERVER_NAME}"
|
||||
SERVER_COMMENT=${SERVER_COMMENT:-This is a Trackmania Server} && config+=( "SERVER_COMMENT" )
|
||||
echo "INFO | SERVER_COMMENT: ${SERVER_COMMENT}"
|
||||
SERVER_PASSWORD=${SERVER_PASSWORD} && config+=( "SERVER_PASSWORD" )
|
||||
echo "INFO | SERVER_PASSWORD: ${SERVER_PASSWORD}"
|
||||
HIDE_SERVER=${HIDE_SERVER:-0} && config+=( "HIDE_SERVER" )
|
||||
echo "INFO | HIDE_SERVER: ${HIDE_SERVER}"
|
||||
MAX_PLAYERS=${MAX_PLAYERS:-32} && config+=( "MAX_PLAYERS" )
|
||||
echo "INFO | MAX_PLAYERS: ${MAX_PLAYERS}"
|
||||
|
||||
# Game Config
|
||||
GAMEMODE=${GAMEMODE:-1} && playlist+=( "GAMEMODE" )
|
||||
echo "INFO | GAMEMODE: ${GAMEMODE} | 1 = TimeAttack"
|
||||
CHATTIME=${CHATTIME:-10000} && playlist+=( "CHATTIME" )
|
||||
echo "INFO | CHATTTIME: ${CHATTIME} ms"
|
||||
FINISHTIMEOUT=${FINISHTIMEOUT:-1} && playlist+=( "FINISHTIMEOUT" )
|
||||
echo "INFO | FINISHTIMEOUT: ${FINISHTIMEOUT}"
|
||||
DISABLERESPAWN=${DISABLERESPAWN:-0} && playlist+=( "DISABLERESPAWN" )
|
||||
echo "INFO | DISABLERESPAWN: ${DISABLERESPAWN}"
|
||||
ROUNDS_POINTSLIMIT=${ROUNDS_POINTSLIMIT:-30} && playlist+=( "ROUNDS_POINTSLIMIT" )
|
||||
echo "INFO | ROUNDS_POINTSLIMIT: ${ROUNDS_POINTSLIMIT}"
|
||||
TIMEATTACK_LIMIT=${TIMEATTACK_LIMIT:-180000} && playlist+=( "TIMEATTACK_LIMIT" )
|
||||
echo "INFO | TIMEATTACK_LIMIT: ${TIMEATTACK_LIMIT} ms"
|
||||
TEAM_POINTSLIMIT=${TEAM_POINTSLIMIT:-50} && playlist+=( "TEAM_POINTSLIMIT" )
|
||||
echo "INFO | TEAM_POINTSLIMIT: ${TEAM_POINTSLIMIT}"
|
||||
TEAM_MAXPOINTS=${TEAM_MAXPOINTS:-6} && playlist+=( "TEAM_MAXPOINTS" )
|
||||
echo "INFO | TEAM_MAXPOINTS: ${TEAM_MAXPOINTS}"
|
||||
LAPS_NBLAPS=${LAPS_NBLAPS:-5} && playlist+=( "LAPS_NBLAPS" )
|
||||
echo "INFO | LAPS_NBLAPS: ${LAPS_NBLAPS}"
|
||||
LAPS_TIMELIMIT=${LAPS_TIMELIMIT:-0} && playlist+=( "LAPS_TIMELIMIT" )
|
||||
echo "INFO | LAPS_TIMELIMIT: ${LAPS_TIMELIMIT}"
|
||||
CUP_POINTSLIMIT=${CUP_POINTSLIMIT:-100} && playlist+=( "CUP_POINTSLIMIT" )
|
||||
echo "INFO | CUP_POINTSLIMIT: ${CUP_POINTSLIMIT}"
|
||||
CUP_ROUNDSPERCHALLENGE=${CUP_ROUNDSPERCHALLENGE:-5} && playlist+=( "CUP_ROUNDSPERCHALLENGE" )
|
||||
echo "INFO | CUP_ROUNDSPERCHALLENGE: ${CUP_ROUNDSPERCHALLENGE}"
|
||||
CUP_NBWINNERS=${CUP_NBWINNERS:-3} && playlist+=( "CUP_NBWINNERS" )
|
||||
echo "INFO | CUP_NBWINNERS: ${CUP_NBWINNERS}"
|
||||
CUP_WARMUPDURATION=${CUP_WARMUPDURATION:-2} && playlist+=( "CUP_WARMUPDURATION" )
|
||||
echo "INFO | CUP_WARMUPDURATION: ${CUP_WARMUPDURATION}"
|
||||
|
||||
# Parse config.xml
|
||||
for idx in "${!config[@]}"; do
|
||||
arg=${config[$idx]}
|
||||
sed -i -e "s/@$arg@/${!arg}/g" GameData/Config/config.xml
|
||||
done
|
||||
|
||||
# Parse playlist.xml
|
||||
for idx in "${!playlist[@]}"; do
|
||||
arg=${playlist[$idx]}
|
||||
sed -i -e "s/@$arg@/${!arg}/g" GameData/Tracks/MatchSettings/playlist.xml
|
||||
done
|
|
@ -0,0 +1,20 @@
|
|||
#!/command/with-contenv bash
|
||||
|
||||
echo "INFO | Parsing custom playlist..."
|
||||
|
||||
CUSTOM_PLAYLIST=${CUSTOM_PLAYLIST:-playlist.txt}
|
||||
PLAYLIST_FILE='GameData/Tracks/MatchSettings/playlist.xml'
|
||||
|
||||
if [[ -f "${CUSTOM_PLAYLIST}" ]]; then
|
||||
count=1
|
||||
while read l; do
|
||||
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
|
||||
count=$((count+1))
|
||||
done < $CUSTOM_PLAYLIST
|
||||
else
|
||||
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
|
||||
fi
|
||||
|
||||
echo "INFO | Finished parsing playlist files."
|
|
@ -0,0 +1,15 @@
|
|||
#!/command/with-contenv bash
|
||||
|
||||
set -e
|
||||
|
||||
[[ "$(id -u)" == 0 ]] && s6-setuidgid trackmania "$0"
|
||||
|
||||
cd /var/lib/tmserver
|
||||
|
||||
# Parse config files
|
||||
./bin/eval_env.sh
|
||||
|
||||
# Parse playlist files
|
||||
./bin/eval_playlist.sh
|
||||
|
||||
exec "./TrackmaniaServer" "/nodaemon" "/internet" "/game_settings=MatchSettings/playlist.xml" "/dedicated_cfg=config.xml"
|
|
@ -0,0 +1,93 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<access>
|
||||
<!-- For a detailed explanation of this three-pass access control system,
|
||||
see: http://httpd.apache.org/docs/2.0/mod/mod_access.html
|
||||
|
||||
The first pass checks all Allow or Deny entries, as specified by the
|
||||
Order directive. The second pass checks all Deny or Allow entries.
|
||||
The third pass applies to nations/zones which didn't match before.
|
||||
The last value in Order thus controls the default behavior when no
|
||||
match is found among Allow and Deny, and when both sections match.
|
||||
|
||||
From values are case-sensitive, upper- and lowercase characters must
|
||||
match exactly with the players' nations/zones you want to control.
|
||||
|
||||
Special From value 'all' matches all nations/zones, and can be used
|
||||
only once in either the Allow or Deny section, with no other From
|
||||
fields in that section.
|
||||
|
||||
Examples of some common situations:
|
||||
|
||||
1. On TMN allow only players from the Benelux:
|
||||
|
||||
<order>Deny,Allow</order>
|
||||
<allow>
|
||||
<from>BEL</from>
|
||||
<from>NED</from>
|
||||
<from>LUX</from>
|
||||
</allow>
|
||||
<deny>
|
||||
<from>all</from>
|
||||
</deny>
|
||||
|
||||
2. The same policy can also be configured like this (note that
|
||||
because Deny is last, it cannot contain 'all' or the allowed
|
||||
nations would be denied as yet):
|
||||
|
||||
<order>Allow,Deny</order>
|
||||
<allow>
|
||||
<from>BEL</from>
|
||||
<from>NED</from>
|
||||
<from>LUX</from>
|
||||
</allow>
|
||||
<deny>
|
||||
<from></from>
|
||||
</deny>
|
||||
|
||||
3. On TMF allow all players except from France and Great Britain:
|
||||
|
||||
<order>Deny,Allow</order>
|
||||
<allow>
|
||||
<from></from>
|
||||
</allow>
|
||||
<deny>
|
||||
<from>France</from>
|
||||
<from>United Kingdom</from>
|
||||
</deny>
|
||||
|
||||
And a more complex one:
|
||||
|
||||
On TMF allow only players from Germany and Austria, except Berlin,
|
||||
Vienna, and the entire Bavaria region:
|
||||
|
||||
<order>Allow,Deny</order>
|
||||
<allow>
|
||||
<from>Germany</from>
|
||||
<from>Austria</from>
|
||||
</allow>
|
||||
<deny>
|
||||
<from>Germany|Berlin</from>
|
||||
<from>Germany|Bavaria</from>
|
||||
<from>Austria|Vienna</from>
|
||||
</deny>
|
||||
|
||||
Configure your server's access policies below:
|
||||
-->
|
||||
<order>Deny,Allow</order>
|
||||
|
||||
<allow>
|
||||
<from>all</from>
|
||||
</allow>
|
||||
|
||||
<deny>
|
||||
<from></from>
|
||||
</deny>
|
||||
|
||||
<messages>
|
||||
<denied>{#server}>> {#message}Player {#highlite}{1}$z$s{#message} denied access from {2} {#highlite}{3}{#message} [{#error}Kicked $z$s{#message}]</denied>
|
||||
<dialog>{#message}Access from zone {#highlite}{1} {#message}denied$z</dialog>
|
||||
<reload>{#server}> Player access control reloaded from {#highlite}access.xml</reload>
|
||||
<xmlerr>{#server}> {#highlite}access.xml {#error}config error, player access control disabled!</xmlerr>
|
||||
<missing>{#server}> {#error}Missing parameter, use {#highlite}$i /admin access help {#error}!</missing>
|
||||
</messages>
|
||||
</access>
|
|
@ -0,0 +1,318 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<lists>
|
||||
<titles>
|
||||
<masteradmin>MasterAdmin</masteradmin>
|
||||
<admin>Admin</admin>
|
||||
<operator>Operator</operator>
|
||||
</titles>
|
||||
<!-- format:
|
||||
<admins>
|
||||
<tmlogin>YOUR_ADMIN_LOGIN</tmlogin> <ipaddress></ipaddress>
|
||||
</admins>
|
||||
-->
|
||||
<operators>
|
||||
<!-- format:
|
||||
<tmlogin>YOUR_OPERATOR_LOGIN</tmlogin> <ipaddress></ipaddress>
|
||||
-->
|
||||
</operators>
|
||||
|
||||
<admin_abilities>
|
||||
<help>true</help>
|
||||
<helpall>true</helpall>
|
||||
<setservername>false</setservername>
|
||||
<setcomment>false</setcomment>
|
||||
<setpwd>true</setpwd>
|
||||
<setspecpwd>true</setspecpwd>
|
||||
<setrefpwd>true</setrefpwd>
|
||||
<setmaxplayers>false</setmaxplayers>
|
||||
<setmaxspecs>false</setmaxspecs>
|
||||
<setgamemode>true</setgamemode>
|
||||
<setrefmode>true</setrefmode>
|
||||
<nextmap>true</nextmap>
|
||||
<next>true</next>
|
||||
<skipmap>true</skipmap>
|
||||
<skip>true</skip>
|
||||
<previous>true</previous>
|
||||
<prev>true</prev>
|
||||
<nextenv>true</nextenv>
|
||||
<restartmap>true</restartmap>
|
||||
<res>true</res>
|
||||
<replaymap>true</replaymap>
|
||||
<replay>true</replay>
|
||||
<dropjukebox>true</dropjukebox>
|
||||
<djb>true</djb>
|
||||
<clearjukebox>true</clearjukebox>
|
||||
<cjb>true</cjb>
|
||||
<clearhist>true</clearhist>
|
||||
<add>true</add>
|
||||
<addthis>true</addthis>
|
||||
<addlocal>true</addlocal>
|
||||
<warn>true</warn>
|
||||
<kick>true</kick>
|
||||
<kickghost>true</kickghost>
|
||||
<ban>true</ban>
|
||||
<unban>true</unban>
|
||||
<banip>true</banip>
|
||||
<unbanip>true</unbanip>
|
||||
<black>true</black>
|
||||
<unblack>true</unblack>
|
||||
<addguest>true</addguest>
|
||||
<removeguest>true</removeguest>
|
||||
<pass>true</pass>
|
||||
<cancel>true</cancel>
|
||||
<can>true</can>
|
||||
<endround>true</endround>
|
||||
<er>true</er>
|
||||
<players>true</players>
|
||||
<showbanlist>true</showbanlist>
|
||||
<listbans>true</listbans>
|
||||
<showiplist>true</showiplist>
|
||||
<listips>true</listips>
|
||||
<showblacklist>true</showblacklist>
|
||||
<listblacks>true</listblacks>
|
||||
<showguestlist>true</showguestlist>
|
||||
<listguests>true</listguests>
|
||||
<writeiplist>true</writeiplist>
|
||||
<readiplist>true</readiplist>
|
||||
<writeblacklist>true</writeblacklist>
|
||||
<readblacklist>true</readblacklist>
|
||||
<writeguestlist>true</writeguestlist>
|
||||
<readguestlist>true</readguestlist>
|
||||
<cleanbanlist>false</cleanbanlist>
|
||||
<cleaniplist>false</cleaniplist>
|
||||
<cleanblacklist>false</cleanblacklist>
|
||||
<cleanguestlist>false</cleanguestlist>
|
||||
<mergegbl>false</mergegbl>
|
||||
<access>false</access>
|
||||
<writetracklist>true</writetracklist>
|
||||
<readtracklist>true</readtracklist>
|
||||
<shuffle>true</shuffle>
|
||||
<shufflemaps>true</shufflemaps>
|
||||
<listdupes>true</listdupes>
|
||||
<remove>true</remove>
|
||||
<erase>true</erase>
|
||||
<removethis>true</removethis>
|
||||
<erasethis>true</erasethis>
|
||||
<mute>true</mute>
|
||||
<ignore>true</ignore>
|
||||
<unmute>true</unmute>
|
||||
<unignore>true</unignore>
|
||||
<mutelist>true</mutelist>
|
||||
<ignorelist>true</ignorelist>
|
||||
<listmutes>true</listmutes>
|
||||
<listignores>true</listignores>
|
||||
<cleanmutes>false</cleanmutes>
|
||||
<cleanignores>false</cleanignores>
|
||||
<addadmin>false</addadmin>
|
||||
<removeadmin>false</removeadmin>
|
||||
<addop>true</addop>
|
||||
<removeop>true</removeop>
|
||||
<listmasters>true</listmasters>
|
||||
<listadmins>true</listadmins>
|
||||
<listops>true</listops>
|
||||
<adminability>false</adminability>
|
||||
<opability>false</opability>
|
||||
<listabilities>true</listabilities>
|
||||
<writeabilities>true</writeabilities>
|
||||
<readabilities>true</readabilities>
|
||||
<wall>true</wall>
|
||||
<mta>true</mta>
|
||||
<delrec>false</delrec>
|
||||
<prunerecs>false</prunerecs>
|
||||
<rpoints>true</rpoints>
|
||||
<match>true</match>
|
||||
<acdl>false</acdl>
|
||||
<autotime>true</autotime>
|
||||
<disablerespawn>true</disablerespawn>
|
||||
<forceshowopp>true</forceshowopp>
|
||||
<scorepanel>true</scorepanel>
|
||||
<roundsfinish>true</roundsfinish>
|
||||
<forceteam>true</forceteam>
|
||||
<forcespec>true</forcespec>
|
||||
<specfree>true</specfree>
|
||||
<panel>true</panel>
|
||||
<style>false</style>
|
||||
<admpanel>false</admpanel>
|
||||
<donpanel>false</donpanel>
|
||||
<recpanel>false</recpanel>
|
||||
<votepanel>false</votepanel>
|
||||
<coppers>true</coppers>
|
||||
<pay>false</pay>
|
||||
<relays>true</relays>
|
||||
<server>true</server>
|
||||
<pm>true</pm>
|
||||
<pmlog>true</pmlog>
|
||||
<call>false</call>
|
||||
<unlock>true</unlock>
|
||||
<debug>false</debug>
|
||||
<shutdown>false</shutdown>
|
||||
<shutdownall>false</shutdownall>
|
||||
<uptodate>true</uptodate>
|
||||
<chat_pma>true</chat_pma>
|
||||
<chat_bestworst>true</chat_bestworst>
|
||||
<chat_statsip>true</chat_statsip>
|
||||
<chat_settings>true</chat_settings>
|
||||
<chat_summary>true</chat_summary>
|
||||
<chat_jukebox>true</chat_jukebox>
|
||||
<chat_jb_multi>true</chat_jb_multi>
|
||||
<chat_jb_recent>true</chat_jb_recent>
|
||||
<chat_add_tref>false</chat_add_tref>
|
||||
<chat_match>false</chat_match>
|
||||
<chat_tc_listen>false</chat_tc_listen>
|
||||
<chat_jfreu>true</chat_jfreu>
|
||||
<chat_musicadmin>true</chat_musicadmin>
|
||||
<noidlekick_play>false</noidlekick_play>
|
||||
<noidlekick_spec>true</noidlekick_spec>
|
||||
<server_coppers>true</server_coppers>
|
||||
</admin_abilities>
|
||||
|
||||
<operator_abilities>
|
||||
<help>true</help>
|
||||
<helpall>true</helpall>
|
||||
<setservername>false</setservername>
|
||||
<setcomment>false</setcomment>
|
||||
<setpwd>false</setpwd>
|
||||
<setspecpwd>false</setspecpwd>
|
||||
<setrefpwd>false</setrefpwd>
|
||||
<setmaxplayers>false</setmaxplayers>
|
||||
<setmaxspecs>false</setmaxspecs>
|
||||
<setgamemode>false</setgamemode>
|
||||
<setrefmode>false</setrefmode>
|
||||
<nextmap>true</nextmap>
|
||||
<next>true</next>
|
||||
<skipmap>true</skipmap>
|
||||
<skip>true</skip>
|
||||
<previous>true</previous>
|
||||
<prev>true</prev>
|
||||
<nextenv>true</nextenv>
|
||||
<restartmap>true</restartmap>
|
||||
<res>true</res>
|
||||
<replaymap>true</replaymap>
|
||||
<replay>true</replay>
|
||||
<dropjukebox>true</dropjukebox>
|
||||
<djb>true</djb>
|
||||
<clearjukebox>true</clearjukebox>
|
||||
<cjb>true</cjb>
|
||||
<clearhist>false</clearhist>
|
||||
<add>false</add>
|
||||
<addthis>false</addthis>
|
||||
<addlocal>false</addlocal>
|
||||
<warn>true</warn>
|
||||
<kick>true</kick>
|
||||
<kickghost>true</kickghost>
|
||||
<ban>false</ban>
|
||||
<unban>false</unban>
|
||||
<banip>false</banip>
|
||||
<unbanip>false</unbanip>
|
||||
<black>false</black>
|
||||
<unblack>false</unblack>
|
||||
<addguest>true</addguest>
|
||||
<removeguest>true</removeguest>
|
||||
<pass>true</pass>
|
||||
<cancel>true</cancel>
|
||||
<can>true</can>
|
||||
<endround>true</endround>
|
||||
<er>true</er>
|
||||
<players>true</players>
|
||||
<showbanlist>true</showbanlist>
|
||||
<listbans>true</listbans>
|
||||
<showiplist>true</showiplist>
|
||||
<listips>true</listips>
|
||||
<showblacklist>true</showblacklist>
|
||||
<listblacks>true</listblacks>
|
||||
<showguestlist>true</showguestlist>
|
||||
<listguests>true</listguests>
|
||||
<writeiplist>false</writeiplist>
|
||||
<readiplist>false</readiplist>
|
||||
<writeblacklist>false</writeblacklist>
|
||||
<readblacklist>false</readblacklist>
|
||||
<writeguestlist>false</writeguestlist>
|
||||
<readguestlist>false</readguestlist>
|
||||
<cleanbanlist>false</cleanbanlist>
|
||||
<cleaniplist>false</cleaniplist>
|
||||
<cleanblacklist>false</cleanblacklist>
|
||||
<cleanguestlist>false</cleanguestlist>
|
||||
<mergegbl>false</mergegbl>
|
||||
<access>false</access>
|
||||
<writetracklist>false</writetracklist>
|
||||
<readtracklist>false</readtracklist>
|
||||
<shuffle>false</shuffle>
|
||||
<shufflemaps>false</shufflemaps>
|
||||
<listdupes>false</listdupes>
|
||||
<remove>false</remove>
|
||||
<erase>false</erase>
|
||||
<removethis>false</removethis>
|
||||
<erasethis>false</erasethis>
|
||||
<mute>true</mute>
|
||||
<ignore>true</ignore>
|
||||
<unmute>true</unmute>
|
||||
<unignore>true</unignore>
|
||||
<mutelist>true</mutelist>
|
||||
<ignorelist>true</ignorelist>
|
||||
<listmutes>true</listmutes>
|
||||
<listignores>true</listignores>
|
||||
<cleanmutes>false</cleanmutes>
|
||||
<cleanignores>false</cleanignores>
|
||||
<addadmin>false</addadmin>
|
||||
<removeadmin>false</removeadmin>
|
||||
<addop>false</addop>
|
||||
<removeop>false</removeop>
|
||||
<listmasters>true</listmasters>
|
||||
<listadmins>true</listadmins>
|
||||
<listops>true</listops>
|
||||
<adminability>false</adminability>
|
||||
<opability>false</opability>
|
||||
<listabilities>true</listabilities>
|
||||
<writeabilities>false</writeabilities>
|
||||
<readabilities>false</readabilities>
|
||||
<wall>false</wall>
|
||||
<mta>false</mta>
|
||||
<delrec>false</delrec>
|
||||
<prunerecs>false</prunerecs>
|
||||
<rpoints>false</rpoints>
|
||||
<match>false</match>
|
||||
<acdl>false</acdl>
|
||||
<autotime>false</autotime>
|
||||
<disablerespawn>false</disablerespawn>
|
||||
<forceshowopp>false</forceshowopp>
|
||||
<scorepanel>true</scorepanel>
|
||||
<roundsfinish>true</roundsfinish>
|
||||
<forceteam>true</forceteam>
|
||||
<forcespec>true</forcespec>
|
||||
<specfree>true</specfree>
|
||||
<panel>true</panel>
|
||||
<style>false</style>
|
||||
<admpanel>false</admpanel>
|
||||
<donpanel>false</donpanel>
|
||||
<recpanel>false</recpanel>
|
||||
<votepanel>false</votepanel>
|
||||
<coppers>false</coppers>
|
||||
<pay>false</pay>
|
||||
<relays>true</relays>
|
||||
<server>false</server>
|
||||
<pm>false</pm>
|
||||
<pmlog>false</pmlog>
|
||||
<call>false</call>
|
||||
<unlock>true</unlock>
|
||||
<debug>false</debug>
|
||||
<shutdown>false</shutdown>
|
||||
<shutdownall>false</shutdownall>
|
||||
<uptodate>false</uptodate>
|
||||
<chat_pma>false</chat_pma>
|
||||
<chat_bestworst>false</chat_bestworst>
|
||||
<chat_statsip>false</chat_statsip>
|
||||
<chat_settings>true</chat_settings>
|
||||
<chat_summary>false</chat_summary>
|
||||
<chat_jukebox>false</chat_jukebox>
|
||||
<chat_jb_multi>false</chat_jb_multi>
|
||||
<chat_jb_recent>false</chat_jb_recent>
|
||||
<chat_add_tref>false</chat_add_tref>
|
||||
<chat_match>false</chat_match>
|
||||
<chat_tc_listen>false</chat_tc_listen>
|
||||
<chat_jfreu>false</chat_jfreu>
|
||||
<chat_musicadmin>false</chat_musicadmin>
|
||||
<noidlekick_play>false</noidlekick_play>
|
||||
<noidlekick_spec>true</noidlekick_spec>
|
||||
<server_coppers>false</server_coppers>
|
||||
</operator_abilities>
|
||||
</lists>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<autotime>
|
||||
<!-- Set the multiplicator for author time (e.g. 6x author -->
|
||||
<!-- time = new timelimit); set to 0 to disable function -->
|
||||
<multiplicator>6</multiplicator>
|
||||
<!-- Set minimum timelimit in minutes -->
|
||||
<mintime>3.5</mintime>
|
||||
<!-- Set maximum timelimit in minutes -->
|
||||
<maxtime>7</maxtime>
|
||||
<!-- Set default timelimit in minutes if any error occurs -->
|
||||
<defaulttime>5</defaulttime>
|
||||
<!-- 2 = in TMF message window, 1 = in chat, 0 = none -->
|
||||
<display>1</display>
|
||||
<message>{#server}>> Set {1} timelimit for {#highlite}{2}{#server} : {#highlite}{3}{#server} (Author time: {#highlite}{4}{#server})</message>
|
||||
</autotime>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ban_list>
|
||||
<!-- format:
|
||||
<ipaddress>xx.xx.xx.xx</ipaddress>
|
||||
-->
|
||||
</ban_list>
|
|
@ -0,0 +1,10 @@
|
|||
#!/command/with-contenv bash
|
||||
|
||||
if ls config/* &>/dev/null; then
|
||||
echo "INFO | Linking custom configuration files..."
|
||||
for i in config/*
|
||||
do
|
||||
ln -sf $i .
|
||||
done
|
||||
echo "INFO | Custom configuration done."
|
||||
fi
|
|
@ -0,0 +1,44 @@
|
|||
#!/command/with-contenv bash
|
||||
|
||||
config=( )
|
||||
database=( )
|
||||
|
||||
# Config
|
||||
MASTERADMIN_LOGIN=${MASTERADMIN_LOGIN:?ERROR | One player needs to be assigned the MasterAdmin role.} && \
|
||||
config+=( "MASTERADMIN_LOGIN" )
|
||||
SERVER_SA_PASSWORD=${SERVER_SA_PASSWORD:?ERROR | SuperAdminPassword was not given. Please refer to your TMServer configuration.} && \
|
||||
config+=( "SERVER_SA_PASSWORD" )
|
||||
|
||||
# Optional
|
||||
TMSERVER_HOST=${TMSERVER_HOST:-localhost} && \
|
||||
config+=( "TMSERVER_HOST" )
|
||||
echo "INFO | TMSERVER_HOST: ${TMSERVER_HOST}"
|
||||
TMSERVER_PORT=${TMSERVER_PORT:-5000} && \
|
||||
config+=( "TMSERVER_PORT" )
|
||||
echo "INFO | TMSERVER_PORT: ${TMSERVER_PORT}"
|
||||
|
||||
# Local Database
|
||||
MYSQL_HOST=${MYSQL_HOST:-db} && \
|
||||
database+=( "MYSQL_HOST" )
|
||||
echo "INFO | MYSQL_HOST: ${MYSQL_HOST}"
|
||||
MYSQL_LOGIN=${MYSQL_LOGIN:?ERROR | MySQL username was not given...} && \
|
||||
database+=( "MYSQL_LOGIN" )
|
||||
echo "INFO | MYSQL_LOGIN: ${MYSQL_LOGIN}"
|
||||
MYSQL_PASSWORD=${MYSQL_PASSWORD:?ERROR | MySQL password was not given...} && \
|
||||
database+=( "MYSQL_PASSWORD" )
|
||||
echo "INFO | MYSQL_PASSWORD: ${MYSQL_PASSWORD}"
|
||||
MYSQL_DATABASE=${MYSQL_DATABASE:-trackmania} && \
|
||||
database+=( "MYSQL_DATABASE" )
|
||||
echo "INFO | MYSQL_DATABASE: ${MYSQL_DATABASE}"
|
||||
|
||||
# Parse config.xml
|
||||
for idx in "${!config[@]}"; do
|
||||
arg=${config[$idx]}
|
||||
sed -i -e "s/@$arg@/${!arg}/g" config.xml
|
||||
done
|
||||
|
||||
# Parse localdatabase.xml
|
||||
for idx in "${!database[@]}"; do
|
||||
arg=${database[$idx]}
|
||||
sed -i -e "s/@$arg@/${!arg}/g" localdatabase.xml
|
||||
done
|
|
@ -0,0 +1,44 @@
|
|||
#!/command/with-contenv bash
|
||||
|
||||
cd /var/lib/xaseco
|
||||
|
||||
XML_HEADER='<?xml version="1.0" encoding="utf-8" ?>\n<aseco_plugins>\n'
|
||||
XML_FOOTER='</aseco_plugins>'
|
||||
|
||||
if ls plugins/custom/* &>/dev/null; then
|
||||
for i in plugins/custom/*
|
||||
do
|
||||
ln -sf ${i#*/} plugins/
|
||||
done
|
||||
fi
|
||||
|
||||
PLUGINS_LIST=($(ls -d plugins/*.php | sed -e 's/plugins\///g'))
|
||||
|
||||
[[ -r ./blacklist ]] && \
|
||||
PLUGINS_LIST=($(echo ${PLUGINS_LIST[@]} | tr ' ' '\n' | grep -vFf blacklist))
|
||||
|
||||
{
|
||||
# open with header -- \n interpreted
|
||||
printf "%b" "$XML_HEADER"
|
||||
|
||||
# main block -- parse plugin list
|
||||
{
|
||||
[[ "${PLUGINS_LIST[@]}" =~ "plugin.localdatabase.php" ]] && printf " <plugin>plugin.localdatabase.php</plugin>\n"
|
||||
for plugin in "${PLUGINS_LIST[@]}"
|
||||
do
|
||||
case "${plugin}" in
|
||||
"plugin.localdatabase.php")
|
||||
;;
|
||||
"plugin.records_eyepiece.php")
|
||||
;;
|
||||
*)
|
||||
printf " <plugin>%s</plugin>\n" "${plugin}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
[[ "${PLUGINS_LIST[@]}" =~ "plugin.records_eyepiece.php" ]] && printf " <plugin>plugin.records_eyepiece.php</plugin>\n"
|
||||
}
|
||||
|
||||
# finish with footer -- \n interpreted
|
||||
printf "%b" "$XML_FOOTER"
|
||||
} > plugins.xml
|
|
@ -0,0 +1,219 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<settings>
|
||||
<aseco>
|
||||
<masteradmins>
|
||||
<!-- /ip:port in tmlogin only needed when joining server over LAN -->
|
||||
<!-- ipaddress can be specified to guard each login against -->
|
||||
<!-- unauthorized use of admin commands from other IP addresses -->
|
||||
|
||||
<tmlogin>@MASTERADMIN_LOGIN@</tmlogin> <ipaddress></ipaddress>
|
||||
|
||||
</masteradmins>
|
||||
|
||||
<colors>
|
||||
<error>$f00$i</error>
|
||||
<welcome>$f00</welcome>
|
||||
<server>$ff0</server>
|
||||
<highlite>$fff</highlite>
|
||||
<timelite>$bbb</timelite>
|
||||
<record>$0f3</record>
|
||||
<emotic>$fa0</emotic>
|
||||
<music>$d80</music>
|
||||
<message>$39f</message>
|
||||
<rank>$ff3</rank>
|
||||
<vote>$f8f</vote>
|
||||
<karma>$ff0</karma>
|
||||
<donate>$f0f</donate>
|
||||
<admin>$ff0</admin>
|
||||
<black>$000</black>
|
||||
<grey>$888</grey>
|
||||
<login>$00f</login>
|
||||
<logina>$0c0</logina>
|
||||
<nick>$f00</nick>
|
||||
<interact>$ff0$i</interact>
|
||||
<dedimsg>$28b</dedimsg>
|
||||
<dedirec>$0b3</dedirec>
|
||||
</colors>
|
||||
|
||||
<messages>
|
||||
<!-- init messages -->
|
||||
<startup>{#server}*** XASECO {#highlite}v{1}{#server} running on {#highlite}{2}{#server}:{#highlite}{3}{#server} ***</startup>
|
||||
<welcome>{#welcome}Welcome {#highlite}{1}{#welcome} to {#highlite}{2}$z$s{br}{#welcome}This server uses {#highlite}XASECO v{3}{#welcome} to manage your records.</welcome>
|
||||
<warning>$s{#welcome}This is an administrative warning.{br}{br}$gWhatever you wrote is against our server's{br}policy. Not respecting other players, or{br}using offensive language might result in a{br}{#welcome}kick, or ban {#message}the next time.{br}{br}$gThe server administrators.</warning>
|
||||
|
||||
<!-- record messages -->
|
||||
<record_current>{#server}>> {#message}Current record on {#highlite}{1}{#message} is {#highlite}{2}{#message} by {#highlite}{3}</record_current>
|
||||
<record_none>{#server}>> {#message}Currently no record on {#highlite}{1}{#message} ...</record_none>
|
||||
<record_error>{#server}>> {#error}Could not get records from database... No records this round!</record_error>
|
||||
|
||||
<!-- ranking messages -->
|
||||
<ranking>{#server}>> {#message}Local Record rankings on {#highlite}{1}{#message} {2} this round:</ranking>
|
||||
<ranking_range>{#server}>> {#message}Local Record rankings on {#highlite}{1}{#message} {2} this round (range {#highlite}{3}{#message}):</ranking_range>
|
||||
<ranking_new>{#server}>> {#message}Local Record rankings on {#highlite}{1}{#message} {2} this round ({#highlite}{3}{#message} new):</ranking_new>
|
||||
<ranking_nonew>{#server}>> {#message}Local Record rankings on {#highlite}{1}{#message} {2} this round: none new so far</ranking_nonew>
|
||||
<ranking_none>{#server}>> {#message}Local Record rankings on {#highlite}{1}{#message} {2} this round: no records!</ranking_none>
|
||||
|
||||
<!-- record misc. messages -->
|
||||
<ranking_record_new_on>{#rank}{1}{#message}.$i{#highlite}{2}{#message}[{#highlite}{3}{#message}]$i, </ranking_record_new_on>
|
||||
<ranking_record_new>{#rank}{1}{#message}.{#highlite}{2}{#message}[{#highlite}{3}{#message}], </ranking_record_new>
|
||||
<ranking_record_on>{#rank}{1}{#message}.$i{#timelite}{2}{#message}[{#timelite}{3}{#message}]$i, </ranking_record_on>
|
||||
<ranking_record>{#rank}{1}{#message}.{#timelite}{2}{#message}[{#timelite}{3}{#message}], </ranking_record>
|
||||
<ranking_record2>{#rank}{1}{#message}.{#timelite}{2}{#message}, </ranking_record2>
|
||||
|
||||
<!-- record relation messages -->
|
||||
<first_record>{#server}> {#record}The first Local record is: </first_record>
|
||||
<last_record>{#server}> {#record}The last Local record is: </last_record>
|
||||
<diff_record>{#server}> {#record}Difference between {1}{#record} and {2}{#record} is: {#highlite}{3}</diff_record>
|
||||
<summary>{#server}> {#highlite}{1} $z$s{#record}has {#highlite}{2}{#record} Local record{3}, the top {4} being: </summary>
|
||||
<sum_entry>{#highlite}{1} {#record}rec{2} #{#rank}{3}{#record}, </sum_entry>
|
||||
|
||||
<!-- win messages -->
|
||||
<wins>{#server}> {#record}You have already won {#highlite}{1}{#record} race{2}</wins>
|
||||
<win_new>{#server}> {#record}Congratulations, you won your {#highlite}{1}{#record}. race!</win_new>
|
||||
<win_multi>{#server}>> {#record}Congratulations, {#highlite}{1}{#record} won his/her {#highlite}{2}{#record}. race!</win_multi>
|
||||
|
||||
<!-- muting messages -->
|
||||
<mute>{#server}> Player {#highlite}{1}$z$s{#server} is muted!</mute>
|
||||
<unmute>{#server}> Player {#highlite}{1}$z$s{#server} is unmuted!</unmute>
|
||||
<muted>{#server}> {#highlite}{1}{#error} disabled because you are on the global mute list!</muted>
|
||||
|
||||
<!-- donate/pay messages -->
|
||||
<donation>{#donate} Donate {#highlite}{1}{#donate} coppers to {#highlite}{2}$z</donation>
|
||||
<thanks_all>{#server}>> {#highlite}{1}$z$s{#donate} received a donation of {#highlite}{2}{#donate} coppers from {#highlite}{3}$z$s{#donate}. Thank You!</thanks_all>
|
||||
<thanks_you>{#server}> {#donate}You made a donation of {#highlite}{1}{#donate} coppers. Thank You!</thanks_you>
|
||||
<donate_minimum>{#server}> {#error}Minimum donation amount is {#highlite}$i {1}{#error} coppers!</donate_minimum>
|
||||
<donate_help>{#server}> {#error}Use {#highlite}$i /donate <number>{#error} to donate coppers to the server</donate_help>
|
||||
<payment>{#donate} Send {#highlite}{1}{#donate} coppers to {#highlite}{2}$z</payment>
|
||||
<pay_insuff>{#server}> {#error}Insufficient server coppers: {#highlite}$i {1}{#error}!</pay_insuff>
|
||||
<pay_server>{#server}> {#error}Cannot pay this server itself!</pay_server>
|
||||
<pay_confirm>{#server}> {#donate}Payment of {#highlite}{1}{#donate} coppers to {#highlite}{2}{#donate} confirmed! Remaining coppers: {#highlite}{3}</pay_confirm>
|
||||
<pay_cancel>{#server}> {#donate}Payment to {#highlite}{1}{#donate} cancelled!</pay_cancel>
|
||||
<pay_help>{#server}> {#error}Use {#highlite}$i /admin pay <login> $m<number>{#error} to send server coppers to a login</pay_help>
|
||||
|
||||
<!-- playtime/track messages -->
|
||||
<playtime>{#server}> Current track {#highlite}{1}{#server} has been played for {#highlite}{2}</playtime>
|
||||
<playtime_finish>{#server}>> Current track {#highlite}{1}{#server} finished after {#highlite}{2}</playtime_finish>
|
||||
<playtime_replay> {#server}({#highlite}{1}{#server} replay{2}, total {#highlite}{3}{#server})</playtime_replay>
|
||||
<track>{#server}> Current track {#highlite}{1} {#server}by {#highlite}{2} {#server}Author: {#highlite}{3} {#server}Gold: {#highlite}{4} {#server}Silver: {#highlite}{5} {#server}Bronze: {#highlite}{6} {#server}Cost: {#highlite}{7}</track>
|
||||
<current_track>{#server}>> Current track {#highlite}{1} {#server}by {#highlite}{2} {#server}Author: {#highlite}{3}</current_track>
|
||||
|
||||
<!-- rounds points messages -->
|
||||
<rpoints_named>{#server}> {1}Custom points system set to {#highlite}{2}{3}: {#highlite}{4},...</rpoints_named>
|
||||
<rpoints_nameless>{#server}> {1}Custom points system set to: {#highlite}{2},...</rpoints_nameless>
|
||||
<no_rpoints>{#server}> {1}No custom Rounds points system defined!</no_rpoints>
|
||||
|
||||
<!-- relay messages -->
|
||||
<no_relays>{#server}> {#error}No relay servers connected</no_relays>
|
||||
<relaymaster>{#server}> This server relays master server: {#highlite}{1}{#server} ({#highlite}{2}{#server})</relaymaster>
|
||||
<notonrelay>{#server}> {#error}Command unavailable on relay server</notonrelay>
|
||||
|
||||
<!-- uptodate messages -->
|
||||
<uptodate_ok>{#server}>> {#message}This XASECO version {#highlite}{1}{#message} is up to date</uptodate_ok>
|
||||
<uptodate_new>{#server}>> {#message}New XASECO version {#highlite}{1}{#message} available from {#highlite}{2}</uptodate_new>
|
||||
|
||||
<!-- connection messages -->
|
||||
<banip_dialog>{#welcome}Your IP was banned from this server.$z</banip_dialog>
|
||||
<banip_error>{#welcome}Could not connect:{br}{br}Your IP was banned from this server!</banip_error>
|
||||
<client_dialog>{#welcome}Obsolete client version, please $l[http://www.tm-forum.com/viewtopic.php?p=139752#p139752]upgrade$l.$z</client_dialog>
|
||||
<client_error>{#welcome}Obsolete client version!{br}Please upgrade to the $l[http://www.tm-forum.com/viewtopic.php?p=139752#p139752]latest version$l.</client_error>
|
||||
<connect_dialog>{#welcome}Connection problem, please retry.$z</connect_dialog>
|
||||
<connect_error>{#welcome}$sThis is an administrative notice.$z{br}{br}XASECO encountered a very rare player connection{br}problem. Please re-join the server to correct it.{br}Apologies for the inconvenience.{br}{br}$sThe server administrators.</connect_error>
|
||||
|
||||
<!-- idlekick messages -->
|
||||
<idlekick_play>{#server}>> IdleKick player {#highlite}{1}$z$s{#server} after {#highlite}{2}{#server} challenge{3}!</idlekick_play>
|
||||
<idlespec_play>{#server}>> IdleSpec player {#highlite}{1}$z$s{#server} after {#highlite}{2}{#server} challenge{3}</idlespec_play>
|
||||
<idlekick_spec>{#server}>> IdleKick spectator {#highlite}{1}$z$s{#server} after {#highlite}{2}{#server} challenge{3}!</idlekick_spec>
|
||||
|
||||
<!-- miscellaneous messages -->
|
||||
<song>{#server}> Track {#highlite}{1} {#server}plays song: {#highlite}{2}</song>
|
||||
<mod>{#server}> Track {#highlite}{1} {#server}uses mod: {#highlite}{2} {#server}({#highlite}{3}{#server})</mod>
|
||||
<coppers>{#server}> Server {#highlite}{1}$z$s {#server}owns {#highlite}{2} {#server}coppers!</coppers>
|
||||
<time>{#server}> {#interact}Current Server Time: {#highlite}$i {1}{#interact} on {#highlite}$i {2}</time>
|
||||
<tmxrec>{#server}>> {#record}TMX World Record: {#highlite}{1}{#record} by {#highlite}{2}</tmxrec>
|
||||
<round>$n{#message}R{#highlite}{1}{#message}> </round>
|
||||
<no_cpsspec>{#server}> {#highlite}/cpsspec{#server} is not currently enabled on this server.</no_cpsspec>
|
||||
<no_admin>{#server}> {#error}You have to be in admin list to do that!</no_admin>
|
||||
<help_explanation>{#server}> Press the {#highlite}C{#server} key to see the whole list, and use {#highlite}/helpall{#server} for details</help_explanation>
|
||||
<united_only>{#server}> {#error}This requires a TM United Forever {1}!</united_only>
|
||||
<forever_only>{#server}> {#error}Command only available on TM Forever!</forever_only>
|
||||
</messages>
|
||||
|
||||
<welcome_msg_window>False</welcome_msg_window>
|
||||
<lock_password></lock_password>
|
||||
<log_all_chat>False</log_all_chat>
|
||||
<chatpmlog_times>True</chatpmlog_times>
|
||||
<cheater_action>0</cheater_action>
|
||||
<script_timeout>60</script_timeout>
|
||||
|
||||
<show_min_recs>8</show_min_recs>
|
||||
<!-- 2 = full report, 1 = only track record, 0 = none -->
|
||||
<!-- add 4 to show the report in the TMF message -->
|
||||
<!-- window instead of the main chat window -->
|
||||
<show_recs_before>2</show_recs_before>
|
||||
<!-- 2 = full report, 1 = only top-5, 0 = none -->
|
||||
<!-- add 4 to show the report in the TMF message -->
|
||||
<!-- window instead of the main chat window -->
|
||||
<show_recs_after>2</show_recs_after>
|
||||
<show_recs_range>True</show_recs_range>
|
||||
<!-- 2 = in TMF message window, 1 = in chat, 0 = none -->
|
||||
<show_tmxrec>1</show_tmxrec>
|
||||
<!-- 2 = in TMF message window, 1 = in chat, 0 = none -->
|
||||
<show_playtime>1</show_playtime>
|
||||
<!-- 2 = in TMF message window, 1 = in chat, 0 = none -->
|
||||
<show_curtrack>0</show_curtrack>
|
||||
|
||||
<default_tracklist>tracklist.txt</default_tracklist>
|
||||
<writetracklist_random>True</writetracklist_random>
|
||||
<help_explanation>False</help_explanation>
|
||||
<lists_colornicks>True</lists_colornicks>
|
||||
<lists_colortracks>True</lists_colortracks>
|
||||
<topclans_minplayers>2</topclans_minplayers>
|
||||
<global_win_multiple>50</global_win_multiple>
|
||||
<display_checkpoints>True</display_checkpoints>
|
||||
<enable_cpsspec>False</enable_cpsspec>
|
||||
<auto_enable_cps>True</auto_enable_cps>
|
||||
<auto_enable_dedicps>False</auto_enable_dedicps>
|
||||
<auto_admin_addip>True</auto_admin_addip>
|
||||
<adminops_file>adminops.xml</adminops_file>
|
||||
<bannedips_file>bannedips.xml</bannedips_file>
|
||||
<blacklist_file>blacklist.txt</blacklist_file>
|
||||
<guestlist_file>guestlist.txt</guestlist_file>
|
||||
<trackhist_file>trackhist.txt</trackhist_file>
|
||||
|
||||
<!-- the remaining settings are for TMF only -->
|
||||
<admin_client_version>2.11.19</admin_client_version>
|
||||
<player_client_version></player_client_version>
|
||||
<default_rpoints></default_rpoints>
|
||||
<afk_force_spec>True</afk_force_spec>
|
||||
<clickable_lists>True</clickable_lists>
|
||||
<show_rec_logins>True</show_rec_logins>
|
||||
<!-- True = in TMF message window, False = in chat -->
|
||||
<recs_in_window>False</recs_in_window>
|
||||
<!-- True = in TMF message window, False = in chat -->
|
||||
<rounds_in_window>False</rounds_in_window>
|
||||
<!-- timeout of the TMF message window in seconds -->
|
||||
<window_timeout>6</window_timeout>
|
||||
<!-- True = display individual stats panels for each -->
|
||||
<!-- player during the scoreboard & disable the rank -->
|
||||
<!-- chat messages, False = show only rank messages -->
|
||||
<sb_stats_panels>False</sb_stats_panels>
|
||||
|
||||
<!-- default windows style: none for old TMN-like, or -->
|
||||
<!-- filename that should be at styles/<filename>.xml -->
|
||||
<window_style>DarkBlur</window_style>
|
||||
<!-- default panels: empty for no panel, otherwise a -->
|
||||
<!-- filename that should be at panels/<filename>.xml -->
|
||||
<admin_panel>AdminBelowChat</admin_panel>
|
||||
<donate_panel>DonateBelowCPList</donate_panel>
|
||||
<records_panel>RecordsRightBottom</records_panel>
|
||||
<vote_panel>VoteBelowChat</vote_panel>
|
||||
</aseco>
|
||||
|
||||
<tmserver>
|
||||
<login>SuperAdmin</login>
|
||||
<password>@SERVER_SA_PASSWORD@</password>
|
||||
<ip>@TMSERVER_HOST@</ip>
|
||||
<port>@TMSERVER_PORT@</port>
|
||||
<timeout>180</timeout>
|
||||
</tmserver>
|
||||
</settings>
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<dedimania>
|
||||
<database>
|
||||
<welcome>{#welcome}Welcome to the Dedimania world record system at www.dedimania.com - see {#highlite}/helpdedi</welcome>
|
||||
<timeout>{#dedimsg}Dedimania system timed out - retrying in {#highlite}{1}{#dedimsg} minutes</timeout>
|
||||
<name>Dedimania</name>
|
||||
<!-- Dedimania communication link, do not modify this! -->
|
||||
<url>http://dedimania.net:8002/Dedimania</url>
|
||||
<!-- Log Dedimania news in logfile? -->
|
||||
<log_news>True</log_news>
|
||||
<!-- Show welcome message in chat? -->
|
||||
<show_welcome>True</show_welcome>
|
||||
<!-- Minimum number of records you'd always like to see at -->
|
||||
<!-- the start and end of tracks, and with /dedilive (-2) -->
|
||||
<show_min_recs>8</show_min_recs>
|
||||
<!-- Display existing records at start of a new track? -->
|
||||
<!-- 2 = in message window, 1 = in chat, 0 = none -->
|
||||
<show_recs_before>1</show_recs_before>
|
||||
<!-- Display (possibly) updated records at end of a track? -->
|
||||
<!-- 2 = in message window, 1 = in chat, 0 = none -->
|
||||
<show_recs_after>1</show_recs_after>
|
||||
<!-- Display records range if there are no new records? -->
|
||||
<show_recs_range>True</show_recs_range>
|
||||
<!-- Do you want XASECO to display newly driven records? -->
|
||||
<display_recs>True</display_recs>
|
||||
<!-- Show logins on TMF for players in /dedirecs ? -->
|
||||
<show_rec_logins>True</show_rec_logins>
|
||||
<!-- Display records in TMF message window or in chat? -->
|
||||
<recs_in_window>False</recs_in_window>
|
||||
<!-- Limit the highest record that will be displayed to -->
|
||||
<!-- all? Only the pertaining player sees higher records, -->
|
||||
<!-- so typically this is the same as your Server MaxRank -->
|
||||
<limit_recs>30</limit_recs>
|
||||
</database>
|
||||
|
||||
<!-- Dedimania server registration, copy these from dedicated.cfg -->
|
||||
<!-- Instead of password you can also use the community code for -->
|
||||
<!-- your server by using the login/password on the official site -->
|
||||
<!-- For the nation, please use the 3-character abbreviation from -->
|
||||
<!-- http://en.wikipedia.org/wiki/List_of_IOC_country_codes -->
|
||||
<masterserver_account>
|
||||
<login>YOUR_SERVER_LOGIN</login>
|
||||
<password>YOUR_SERVER_PASSWORD</password>
|
||||
<nation>YOUR_SERVER_NATION</nation>
|
||||
</masterserver_account>
|
||||
|
||||
<messages>
|
||||
<!-- ranking messages -->
|
||||
<ranking>{#server}>> {#dedimsg}Dedimania Record rankings on {#highlite}{1}{#dedimsg} {2} this round:</ranking>
|
||||
<ranking_range>{#server}>> {#dedimsg}Dedimania Record rankings on {#highlite}{1}{#dedimsg} {2} this round (range {#highlite}{3}{#dedimsg}):</ranking_range>
|
||||
<ranking_new>{#server}>> {#dedimsg}Dedimania Record rankings on {#highlite}{1}{#dedimsg} {2} this round ({#highlite}{3}{#dedimsg} new):</ranking_new>
|
||||
<ranking_nonew>{#server}>> {#dedimsg}Dedimania Record rankings on {#highlite}{1}{#dedimsg} {2} this round: none new so far</ranking_nonew>
|
||||
<ranking_none>{#server}>> {#dedimsg}Dedimania Record rankings on {#highlite}{1}{#dedimsg} {2} this round: no records!</ranking_none>
|
||||
|
||||
<!-- record messages -->
|
||||
<record_new>{#server}>> {#highlite}{1}{#dedirec} secured his/her {#rank}{2}{#dedirec}. Dedimania Record! {3}: {#highlite}{4}{#dedirec} $n({#rank}{5}{#highlite}{6}{#dedirec})</record_new>
|
||||
<record_equal>{#server}>> {#highlite}{1}{#dedirec} equaled his/her {#rank}{2}{#dedirec}. Dedimania Record! {3}: {#highlite}{4}</record_equal>
|
||||
<record_new_rank>{#server}>> {#highlite}{1}{#dedirec} gained the {#rank}{2}{#dedirec}. Dedimania Record! {3}: {#highlite}{4}{#dedirec} $n({#rank}{5}{#highlite}{6}{#dedirec})</record_new_rank>
|
||||
<record_first>{#server}>> {#highlite}{1}{#dedirec} claimed the {#rank}{2}{#dedirec}. Dedimania Record! {3}: {#highlite}{4}</record_first>
|
||||
|
||||
<!-- record relation messages -->
|
||||
<first_record>{#server}> {#dedirec}The first Dedimania record is: </first_record>
|
||||
<last_record>{#server}> {#dedirec}The last Dedimania record is: </last_record>
|
||||
<diff_record>{#server}> {#dedirec}Difference between {1}{#dedirec} and {2}{#dedirec} is: {#highlite}{3}</diff_record>
|
||||
|
||||
<!-- pb messages -->
|
||||
<pb>{#server}> {#dedirec}Dedimania Personal Best: {#highlite}{1}{#dedirec}({#rank}{2}{#dedirec})</pb>
|
||||
<pb_none>{#server}> {#error}You don't have a Dedimania record on this track yet...</pb_none>
|
||||
|
||||
<!-- ban messages -->
|
||||
<banned_login>{#server}>> {#highlite}{1} {#server}({#highlite}{2}{#server}) {#error}is banned from Dedimania!</banned_login>
|
||||
<banned_finish>{#server}> {#error}Finish ignored by Dedimania as you are banned!</banned_finish>
|
||||
</messages>
|
||||
</dedimania>
|
|
@ -0,0 +1,891 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/*
|
||||
IXR - The Incutio XML-RPC Library - (c) Incutio Ltd 2002
|
||||
Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
|
||||
Site: http://scripts.incutio.com/xmlrpc/
|
||||
Manual: http://scripts.incutio.com/xmlrpc/manual.php
|
||||
Errors: http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
|
||||
Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
|
||||
|
||||
Modified to support protocol 'GbxRemote 2' ('GbxRemote 1')
|
||||
This version is for BigEndian machines. For LittleEndian (e.g. Intel PC)
|
||||
machines use the original GbxRemote.inc.php instead.
|
||||
|
||||
Release 2007-09-22 - Slig:
|
||||
Modified to support >256KB received data (and now >2MB data produce a specific error message)
|
||||
Modified readCB() to wait the initial timeout only before first read packet
|
||||
Modified readCB() to return true if there is data to get with getCBResponses()
|
||||
Modified to support amd64 (for $recvhandle)
|
||||
Modified IXR_ClientMulticall_Gbx::addCall() to fit Aseco 0.6.1
|
||||
Added IXR_Client_Gbx::bytes_sent & bytes_received counters
|
||||
Fix for a changed feature since php5.1.1 about reference parameter assignment (was used in stream_select)
|
||||
Workaround for stream_select return value bug with amd64
|
||||
|
||||
Release 2008-01-20 - Slig / Xymph / Assembler Maniac:
|
||||
Workaround for fread delay bug in some cases
|
||||
Added IXR_Client_Gbx::resetError() method (by Xymph)
|
||||
Some comments and strings code cleanup (by Xymph)
|
||||
Fix stream_set_timeout($this->socket,...) (thx to CavalierDeVache)
|
||||
Added a default timeout value to IXR_Client_Gbx::readCB($timeout)
|
||||
Changed calls with timeout on a stream to use microseconds instead of seconds (by AM)
|
||||
Removed IXR_Client_Gbx::bytes_sent & bytes_received counters - not used (by AM)
|
||||
|
||||
Release 2008-02-05 - Slig:
|
||||
Changed some socket read/write timeouts back to seconds to avoid 'transport error'
|
||||
Changed max data received from 2MB to 4MB
|
||||
|
||||
Release 2008-05-20 - Xymph:
|
||||
Prevented unpack() warnings in IXR_Client_Gbx::query() when the connection dies
|
||||
Changed IXR_Client_Gbx::resetError() to assign 'false' for correct isError()
|
||||
Tweaked some 'transport error' messages
|
||||
|
||||
Release 2009-04-08 - Gou1:
|
||||
Added method IXR_Client_Gbx::queryIgnoreResult()
|
||||
Added methods IXR_Client_Gbx::sendRequest() & IXR_Client_Gbx::getResult()
|
||||
IXR_Client_Gbx::queryIgnoreResult checks if the request is larger than 512KB to avoid errors
|
||||
If larger than 512KB and method is system.multicall, try to divide the request into
|
||||
two separate requests with two separate IXR_Client_Gbx::queryIgnoreResult() calls
|
||||
|
||||
Release 2009-06-03 - Xymph:
|
||||
Suppress possible repetitive CRT warning at stream_select
|
||||
|
||||
Release 2011-04-09 - Xymph / La beuze:
|
||||
Added optional timeout mechanism to IXR_Client_Gbx::InitWithIp()
|
||||
|
||||
Release 2011-05-22 - Xymph:
|
||||
Added non-error (true) return status to IXR_Client_Gbx::queryIgnoreResult()
|
||||
Updated status codes and messages for transport/endian errors
|
||||
Prevented possible PHP warning in IXR_Client_Gbx::getErrorCode() and getErrorMessage()
|
||||
|
||||
Release 2011-12-04 - Xymph:
|
||||
Prevented possible PHP warning in IXR_Value::calculateType
|
||||
|
||||
Release 2013-02-18 - Xymph:
|
||||
Removed unnecessary breaks after returns in IXR_Value::getXml() switch
|
||||
*/
|
||||
|
||||
if (!defined('LF')) {
|
||||
define('LF', "\n");
|
||||
}
|
||||
|
||||
class IXR_Value {
|
||||
public $data;
|
||||
public $type;
|
||||
|
||||
function IXR_Value ($data, $type = false) {
|
||||
$this->data = $data;
|
||||
if (!$type) {
|
||||
$type = $this->calculateType();
|
||||
}
|
||||
$this->type = $type;
|
||||
if ($type == 'struct') {
|
||||
// Turn all the values in the array into new IXR_Value objects
|
||||
foreach ($this->data as $key => $value) {
|
||||
$this->data[$key] = new IXR_Value($value);
|
||||
}
|
||||
}
|
||||
if ($type == 'array') {
|
||||
for ($i = 0, $j = count($this->data); $i < $j; $i++) {
|
||||
$this->data[$i] = new IXR_Value($this->data[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function calculateType() {
|
||||
if ($this->data === true || $this->data === false) {
|
||||
return 'boolean';
|
||||
}
|
||||
if (is_integer($this->data)) {
|
||||
return 'int';
|
||||
}
|
||||
if (is_double($this->data)) {
|
||||
return 'double';
|
||||
}
|
||||
// Deal with IXR object types base64 and date
|
||||
if (is_object($this->data) && ($this->data instanceof IXR_Date)) {
|
||||
return 'date';
|
||||
}
|
||||
if (is_object($this->data) && ($this->data instanceof IXR_Base64)) {
|
||||
return 'base64';
|
||||
}
|
||||
// If it is a normal PHP object convert it into a struct
|
||||
if (is_object($this->data)) {
|
||||
$this->data = get_object_vars($this->data);
|
||||
return 'struct';
|
||||
}
|
||||
if (!is_array($this->data)) {
|
||||
return 'string';
|
||||
}
|
||||
// We have an array - is it an array or a struct?
|
||||
if ($this->isStruct($this->data)) {
|
||||
return 'struct';
|
||||
} else {
|
||||
return 'array';
|
||||
}
|
||||
}
|
||||
|
||||
function getXml() {
|
||||
// Return XML for this value
|
||||
switch ($this->type) {
|
||||
case 'boolean':
|
||||
return '<boolean>' . ($this->data ? '1' : '0') . '</boolean>';
|
||||
case 'int':
|
||||
return '<int>' . $this->data . '</int>';
|
||||
case 'double':
|
||||
return '<double>' . $this->data . '</double>';
|
||||
case 'string':
|
||||
return '<string>' . htmlspecialchars($this->data) . '</string>';
|
||||
case 'array':
|
||||
$return = '<array><data>' . LF;
|
||||
foreach ($this->data as $item) {
|
||||
$return .= ' <value>' . $item->getXml() . '</value>' . LF;
|
||||
}
|
||||
$return .= '</data></array>';
|
||||
return $return;
|
||||
case 'struct':
|
||||
$return = '<struct>' . LF;
|
||||
foreach ($this->data as $name => $value) {
|
||||
$return .= ' <member><name>' . $name . '</name><value>';
|
||||
$return .= $value->getXml() . '</value></member>' . LF;
|
||||
}
|
||||
$return .= '</struct>';
|
||||
return $return;
|
||||
case 'date':
|
||||
case 'base64':
|
||||
return $this->data->getXml();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isStruct($array) {
|
||||
// Nasty function to check if an array is a struct or not
|
||||
$expected = 0;
|
||||
foreach ($array as $key => $value) {
|
||||
if ((string)$key != (string)$expected) {
|
||||
return true;
|
||||
}
|
||||
$expected++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IXR_Message {
|
||||
public $message;
|
||||
public $messageType; // methodCall / methodResponse / fault
|
||||
public $faultCode;
|
||||
public $faultString;
|
||||
public $methodName;
|
||||
public $params;
|
||||
// Current variable stacks
|
||||
protected $_arraystructs = array(); // Stack to keep track of the current array/struct
|
||||
protected $_arraystructstypes = array(); // Stack to keep track of whether things are structs or array
|
||||
protected $_currentStructName = array(); // A stack as well
|
||||
protected $_param;
|
||||
protected $_value;
|
||||
protected $_currentTag;
|
||||
protected $_currentTagContents;
|
||||
// The XML parser
|
||||
protected $_parser;
|
||||
|
||||
function IXR_Message ($message) {
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
function parse() {
|
||||
// first remove the XML declaration
|
||||
$this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message);
|
||||
if (trim($this->message) == '') {
|
||||
return false;
|
||||
}
|
||||
$this->_parser = xml_parser_create();
|
||||
// Set XML parser to take the case of tags into account
|
||||
xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
|
||||
// Set XML parser callback functions
|
||||
xml_set_object($this->_parser, $this);
|
||||
xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
|
||||
xml_set_character_data_handler($this->_parser, 'cdata');
|
||||
if (!xml_parse($this->_parser, $this->message)) {
|
||||
/* die(sprintf('GbxRemote XML error: %s at line %d',
|
||||
xml_error_string(xml_get_error_code($this->_parser)),
|
||||
xml_get_current_line_number($this->_parser))); */
|
||||
return false;
|
||||
}
|
||||
xml_parser_free($this->_parser);
|
||||
// Grab the error messages, if any
|
||||
if ($this->messageType == 'fault') {
|
||||
$this->faultCode = $this->params[0]['faultCode'];
|
||||
$this->faultString = $this->params[0]['faultString'];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function tag_open($parser, $tag, $attr) {
|
||||
$this->currentTag = $tag;
|
||||
switch ($tag) {
|
||||
case 'methodCall':
|
||||
case 'methodResponse':
|
||||
case 'fault':
|
||||
$this->messageType = $tag;
|
||||
break;
|
||||
// Deal with stacks of arrays and structs
|
||||
case 'data': // data is to all intents and purposes more interesting than array
|
||||
$this->_arraystructstypes[] = 'array';
|
||||
$this->_arraystructs[] = array();
|
||||
break;
|
||||
case 'struct':
|
||||
$this->_arraystructstypes[] = 'struct';
|
||||
$this->_arraystructs[] = array();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function cdata($parser, $cdata) {
|
||||
$this->_currentTagContents .= $cdata;
|
||||
}
|
||||
|
||||
function tag_close($parser, $tag) {
|
||||
$valueFlag = false;
|
||||
switch ($tag) {
|
||||
case 'int':
|
||||
case 'i4':
|
||||
$value = (int)trim($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
break;
|
||||
case 'double':
|
||||
$value = (double)trim($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
break;
|
||||
case 'string':
|
||||
$value = (string)trim($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
break;
|
||||
case 'dateTime.iso8601':
|
||||
$value = new IXR_Date(trim($this->_currentTagContents));
|
||||
// $value = $iso->getTimestamp();
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
break;
|
||||
case 'value':
|
||||
// If no type is indicated, the type is string
|
||||
if (trim($this->_currentTagContents) != '') {
|
||||
$value = (string)$this->_currentTagContents;
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
}
|
||||
break;
|
||||
case 'boolean':
|
||||
$value = (boolean)trim($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
break;
|
||||
case 'base64':
|
||||
$value = base64_decode($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
break;
|
||||
// Deal with stacks of arrays and structs
|
||||
case 'data':
|
||||
case 'struct':
|
||||
$value = array_pop($this->_arraystructs);
|
||||
array_pop($this->_arraystructstypes);
|
||||
$valueFlag = true;
|
||||
break;
|
||||
case 'member':
|
||||
array_pop($this->_currentStructName);
|
||||
break;
|
||||
case 'name':
|
||||
$this->_currentStructName[] = trim($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
break;
|
||||
case 'methodName':
|
||||
$this->methodName = trim($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($valueFlag) {
|
||||
/*
|
||||
if (!is_array($value) && !is_object($value)) {
|
||||
$value = trim($value);
|
||||
}
|
||||
*/
|
||||
if (count($this->_arraystructs) > 0) {
|
||||
// Add value to struct or array
|
||||
if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
|
||||
// Add to struct
|
||||
$this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value;
|
||||
} else {
|
||||
// Add to array
|
||||
$this->_arraystructs[count($this->_arraystructs)-1][] = $value;
|
||||
}
|
||||
} else {
|
||||
// Just add as a paramater
|
||||
$this->params[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IXR_Request {
|
||||
public $method;
|
||||
public $args;
|
||||
public $xml;
|
||||
|
||||
function IXR_Request($method, $args) {
|
||||
$this->method = $method;
|
||||
$this->args = $args;
|
||||
$this->xml = '<?xml version="1.0" encoding="utf-8" ?><methodCall><methodName>' . $this->method . '</methodName><params>';
|
||||
foreach ($this->args as $arg) {
|
||||
$this->xml .= '<param><value>';
|
||||
$v = new IXR_Value($arg);
|
||||
$this->xml .= $v->getXml();
|
||||
$this->xml .= '</value></param>' . LF;
|
||||
}
|
||||
$this->xml .= '</params></methodCall>';
|
||||
}
|
||||
|
||||
function getLength() {
|
||||
return strlen($this->xml);
|
||||
}
|
||||
|
||||
function getXml() {
|
||||
return $this->xml;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IXR_Error {
|
||||
public $code;
|
||||
public $message;
|
||||
|
||||
function IXR_Error($code, $message) {
|
||||
$this->code = $code;
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
function getXml() {
|
||||
$xml = <<<EOD
|
||||
<methodResponse>
|
||||
<fault>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>faultCode</name>
|
||||
<value><int>{$this->code}</int></value>
|
||||
</member>
|
||||
<member>
|
||||
<name>faultString</name>
|
||||
<value><string>{$this->message}</string></value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</fault>
|
||||
</methodResponse>
|
||||
EOD;
|
||||
return $xml;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IXR_Date {
|
||||
public $year;
|
||||
public $month;
|
||||
public $day;
|
||||
public $hour;
|
||||
public $minute;
|
||||
public $second;
|
||||
|
||||
function IXR_Date($time) {
|
||||
// $time can be a PHP timestamp or an ISO one
|
||||
if (is_numeric($time)) {
|
||||
$this->parseTimestamp($time);
|
||||
} else {
|
||||
$this->parseIso($time);
|
||||
}
|
||||
}
|
||||
|
||||
function parseTimestamp($timestamp) {
|
||||
$this->year = date('Y', $timestamp);
|
||||
$this->month = date('Y', $timestamp);
|
||||
$this->day = date('Y', $timestamp);
|
||||
$this->hour = date('H', $timestamp);
|
||||
$this->minute = date('i', $timestamp);
|
||||
$this->second = date('s', $timestamp);
|
||||
}
|
||||
|
||||
function parseIso($iso) {
|
||||
$this->year = substr($iso, 0, 4);
|
||||
$this->month = substr($iso, 4, 2);
|
||||
$this->day = substr($iso, 6, 2);
|
||||
$this->hour = substr($iso, 9, 2);
|
||||
$this->minute = substr($iso, 12, 2);
|
||||
$this->second = substr($iso, 15, 2);
|
||||
}
|
||||
|
||||
function getIso() {
|
||||
return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second;
|
||||
}
|
||||
|
||||
function getXml() {
|
||||
return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
|
||||
}
|
||||
|
||||
function getTimestamp() {
|
||||
return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IXR_Base64 {
|
||||
public $data;
|
||||
|
||||
function IXR_Base64($data) {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
function getXml() {
|
||||
return '<base64>'.base64_encode($this->data).'</base64>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// Nadeo modifications //
|
||||
// (many thanks to slig for adding callback support) //
|
||||
//////////////////////////////////////////////////////////
|
||||
class IXR_Client_Gbx {
|
||||
public $socket;
|
||||
public $message = false;
|
||||
public $cb_message = array();
|
||||
public $reqhandle;
|
||||
public $protocol = 0;
|
||||
// Storage place for an error message
|
||||
public $error = false;
|
||||
|
||||
function bigEndianTest() {
|
||||
list($endiantest) = array_values(unpack('L1L', pack('V', 1)));
|
||||
if ($endiantest == 1) {
|
||||
echo "Machine reports itself as LittleEndian, float handling will work correctly with unpack\r\n";
|
||||
echo "Use original GbxRemote.inc.php instead of GbxRemote.bem.php\r\n";
|
||||
die('App Terminated');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // bigEndianTest
|
||||
|
||||
function IXR_Client_Gbx() {
|
||||
$this->socket = false;
|
||||
$this->reqhandle = 0x80000000;
|
||||
}
|
||||
|
||||
function InitWithIp($ip, $port, $timeout = null) {
|
||||
|
||||
if (!$this->bigEndianTest()) {
|
||||
$this->error = new IXR_Error(-31999, 'endian error - script doesn\'t match machine type');
|
||||
return false;
|
||||
}
|
||||
|
||||
// open connection, with timeout if specified
|
||||
if (!isset($timeout)) {
|
||||
$this->socket = @fsockopen($ip, $port, $errno, $errstr);
|
||||
} else {
|
||||
$init_time = microtime(true);
|
||||
$init_timeout = 5; // retry every 5s
|
||||
while (true) {
|
||||
$this->socket = @fsockopen($ip, $port, $errno, $errstr, $init_timeout);
|
||||
if ($this->socket || (microtime(true) - $init_time >= $timeout))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$this->socket) {
|
||||
$this->error = new IXR_Error(-32300, "transport error - could not open socket (error: $errno, $errstr)");
|
||||
return false;
|
||||
}
|
||||
// handshake
|
||||
$array_result = big_endian_unpack('Vsize', fread($this->socket, 4));
|
||||
$size = $array_result['size'];
|
||||
if ($size > 64) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - wrong lowlevel protocol header');
|
||||
return false;
|
||||
}
|
||||
$handshake = fread($this->socket, $size);
|
||||
if ($handshake == 'GBXRemote 1') {
|
||||
$this->protocol = 1;
|
||||
} else if ($handshake == 'GBXRemote 2') {
|
||||
$this->protocol = 2;
|
||||
} else {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - wrong lowlevel protocol version');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function Init($port) {
|
||||
return $this->InitWithIp('localhost', $port);
|
||||
}
|
||||
|
||||
function Terminate() {
|
||||
if ($this->socket) {
|
||||
fclose($this->socket);
|
||||
$this->socket = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function sendRequest(IXR_Request $request) {
|
||||
$xml = $request->getXml();
|
||||
|
||||
@stream_set_timeout($this->socket, 20); // timeout 20s (to write the request)
|
||||
// send request
|
||||
$this->reqhandle++;
|
||||
if ($this->protocol == 1) {
|
||||
$bytes = pack('Va*', strlen($xml), $xml);
|
||||
} else {
|
||||
$bytes = pack('VVa*', strlen($xml), $this->reqhandle, $xml);
|
||||
}
|
||||
|
||||
$bytes_to_write = strlen($bytes);
|
||||
while ($bytes_to_write > 0) {
|
||||
$r = @fwrite($this->socket, $bytes);
|
||||
if ($r === false || $r == 0) {
|
||||
// connection interrupted
|
||||
return false; // or die?
|
||||
}
|
||||
|
||||
$bytes_to_write -= $r;
|
||||
if ($bytes_to_write == 0)
|
||||
break;
|
||||
|
||||
$bytes = substr($bytes, $r);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getResult() {
|
||||
$contents = '';
|
||||
$contents_length = 0;
|
||||
do {
|
||||
$size = 0;
|
||||
$recvhandle = 0;
|
||||
@stream_set_timeout($this->socket, 20); // timeout 20s (to read the reply header)
|
||||
// Get result
|
||||
if ($this->protocol == 1) {
|
||||
$contents = fread($this->socket, 4);
|
||||
if (strlen($contents) == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - cannot read size');
|
||||
return false;
|
||||
}
|
||||
$array_result = big_endian_unpack('Vsize', $contents);
|
||||
$size = $array_result['size'];
|
||||
$recvhandle = $this->reqhandle;
|
||||
} else {
|
||||
$contents = fread($this->socket, 8);
|
||||
if (strlen($contents) == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - cannot read size/handle');
|
||||
return false;
|
||||
}
|
||||
$array_result = big_endian_unpack('Vsize/Vhandle', $contents);
|
||||
$size = $array_result['size'];
|
||||
$recvhandle = $array_result['handle'];
|
||||
// -- amd64 support --
|
||||
$bits = sprintf('%b', $recvhandle);
|
||||
if (strlen($bits) == 64) {
|
||||
$recvhandle = bindec(substr($bits, 32));
|
||||
}
|
||||
}
|
||||
|
||||
if ($recvhandle == 0 || $size == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - connection interrupted!');
|
||||
return false;
|
||||
}
|
||||
if ($size > 4096*1024) {
|
||||
$this->error = new IXR_Error(-32300, "transport error - response too large ($size)");
|
||||
return false;
|
||||
}
|
||||
|
||||
$contents = '';
|
||||
$contents_length = 0;
|
||||
@stream_set_timeout($this->socket, 0, 10000); // timeout 10 ms (for successive reads until end)
|
||||
while ($contents_length < $size) {
|
||||
$contents .= fread($this->socket, $size-$contents_length);
|
||||
$contents_length = strlen($contents);
|
||||
}
|
||||
|
||||
if (($recvhandle & 0x80000000) == 0) {
|
||||
// this is a callback, not our answer! handle= $recvhandle, xml-rpc= $contents
|
||||
// just add it to the message list for the user to read
|
||||
$new_cb_message = new IXR_Message($contents);
|
||||
if ($new_cb_message->parse() && $new_cb_message->messageType != 'fault') {
|
||||
array_push($this->cb_message, array($new_cb_message->methodName, $new_cb_message->params));
|
||||
}
|
||||
}
|
||||
} while ((int)$recvhandle != (int)$this->reqhandle);
|
||||
|
||||
$this->message = new IXR_Message($contents);
|
||||
if (!$this->message->parse()) {
|
||||
// XML error
|
||||
$this->error = new IXR_Error(-32700, 'parse error. not well formed');
|
||||
return false;
|
||||
}
|
||||
// Is the message a fault?
|
||||
if ($this->message->messageType == 'fault') {
|
||||
$this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
|
||||
return false;
|
||||
}
|
||||
// Message must be OK
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function query() {
|
||||
$args = func_get_args();
|
||||
$method = array_shift($args);
|
||||
|
||||
if (!$this->socket || $this->protocol == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - client not initialized');
|
||||
return false;
|
||||
}
|
||||
|
||||
$request = new IXR_Request($method, $args);
|
||||
|
||||
// Check if request is larger than 512 Kbytes
|
||||
if (($size = $request->getLength()) > 512*1024-8) {
|
||||
$this->error = new IXR_Error(-32300, "transport error - request too large ($size)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send request
|
||||
$ok = $this->sendRequest($request);
|
||||
if (!$ok) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - connection interrupted!');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get result
|
||||
return $this->getResult();
|
||||
}
|
||||
|
||||
// Non-blocking query method: doesn't read the response
|
||||
function queryIgnoreResult() {
|
||||
$args = func_get_args();
|
||||
$method = array_shift($args);
|
||||
|
||||
if (!$this->socket || $this->protocol == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - client not initialized');
|
||||
return false;
|
||||
}
|
||||
|
||||
$request = new IXR_Request($method, $args);
|
||||
|
||||
// Check if the request is greater than 512 Kbytes to avoid errors
|
||||
// If the method is system.multicall, make two calls (possibly recursively)
|
||||
if (($size = $request->getLength()) > 512*1024-8) {
|
||||
if ($method = 'system.multicall' && isset($args[0])) {
|
||||
$count = count($args[0]);
|
||||
// If count is 1, query cannot be reduced
|
||||
if ($count < 2) {
|
||||
$this->error = new IXR_Error(-32300, "transport error - request too large ($size)");
|
||||
return false;
|
||||
}
|
||||
$length = floor($count/2);
|
||||
$args1 = array_slice($args[0], 0, $length);
|
||||
$args2 = array_slice($args[0], $length, ($count-$length));
|
||||
|
||||
$res1 = $this->queryIgnoreResult('system.multicall', $args1);
|
||||
$res2 = $this->queryIgnoreResult('system.multicall', $args2);
|
||||
return ($res1 && $res2);
|
||||
}
|
||||
// If the method is not a multicall, just stop
|
||||
else {
|
||||
$this->error = new IXR_Error(-32300, "transport error - request too large ($size)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Send request
|
||||
$ok = $this->sendRequest($request);
|
||||
if (!$ok) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - connection interrupted!');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function readCB($timeout = 2000) { // timeout 2 ms
|
||||
if (!$this->socket || $this->protocol == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - client not initialized');
|
||||
return false;
|
||||
}
|
||||
if ($this->protocol == 1)
|
||||
return false;
|
||||
|
||||
$something_received = count($this->cb_message)>0;
|
||||
$contents = '';
|
||||
$contents_length = 0;
|
||||
|
||||
@stream_set_timeout($this->socket, 0, 10000); // timeout 10 ms (to read available data)
|
||||
// (assignment in arguments is forbidden since php 5.1.1)
|
||||
$read = array($this->socket);
|
||||
$write = NULL;
|
||||
$except = NULL;
|
||||
$nb = @stream_select($read, $write, $except, 0, $timeout);
|
||||
// workaround for stream_select bug with amd64
|
||||
if ($nb !== false)
|
||||
$nb = count($read);
|
||||
|
||||
while ($nb !== false && $nb > 0) {
|
||||
$timeout = 0; // we don't want to wait for the full time again, just flush the available data
|
||||
|
||||
$size = 0;
|
||||
$recvhandle = 0;
|
||||
// Get result
|
||||
$contents = fread($this->socket, 8);
|
||||
if (strlen($contents) == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - cannot read size/handle');
|
||||
return false;
|
||||
}
|
||||
$array_result = big_endian_unpack('Vsize/Vhandle', $contents);
|
||||
$size = $array_result['size'];
|
||||
$recvhandle = $array_result['handle'];
|
||||
|
||||
if ($recvhandle == 0 || $size == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - connection interrupted!');
|
||||
return false;
|
||||
}
|
||||
if ($size > 4096*1024) {
|
||||
$this->error = new IXR_Error(-32300, "transport error - response too large ($size)");
|
||||
return false;
|
||||
}
|
||||
|
||||
$contents = '';
|
||||
$contents_length = 0;
|
||||
while ($contents_length < $size) {
|
||||
$contents .= fread($this->socket, $size-$contents_length);
|
||||
$contents_length = strlen($contents);
|
||||
}
|
||||
|
||||
if (($recvhandle & 0x80000000) == 0) {
|
||||
// this is a callback. handle= $recvhandle, xml-rpc= $contents
|
||||
//echo 'CALLBACK('.$contents_length.')[ '.$contents.' ]' . LF;
|
||||
$new_cb_message = new IXR_Message($contents);
|
||||
if ($new_cb_message->parse() && $new_cb_message->messageType != 'fault') {
|
||||
array_push($this->cb_message, array($new_cb_message->methodName, $new_cb_message->params));
|
||||
}
|
||||
$something_received = true;
|
||||
}
|
||||
|
||||
// (assignment in arguments is forbidden since php 5.1.1)
|
||||
$read = array($this->socket);
|
||||
$write = NULL;
|
||||
$except = NULL;
|
||||
$nb = @stream_select($read, $write, $except, 0, $timeout);
|
||||
// workaround for stream_select bug with amd64
|
||||
if ($nb !== false)
|
||||
$nb = count($read);
|
||||
}
|
||||
return $something_received;
|
||||
}
|
||||
|
||||
function getResponse() {
|
||||
// methodResponses can only have one param - return that
|
||||
return $this->message->params[0];
|
||||
}
|
||||
|
||||
function getCBResponses() {
|
||||
// (look at the end of basic.php for an example)
|
||||
$messages = $this->cb_message;
|
||||
$this->cb_message = array();
|
||||
return $messages;
|
||||
}
|
||||
|
||||
function isError() {
|
||||
return is_object($this->error);
|
||||
}
|
||||
|
||||
function resetError() {
|
||||
$this->error = false;
|
||||
}
|
||||
|
||||
function getErrorCode() {
|
||||
if ($this->isError())
|
||||
return $this->error->code;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getErrorMessage() {
|
||||
if ($this->isError())
|
||||
return $this->error->message;
|
||||
else
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IXR_ClientMulticall_Gbx extends IXR_Client_Gbx {
|
||||
public $calls = array();
|
||||
|
||||
function addCall($methodName, $args) {
|
||||
$struct = array('methodName' => $methodName, 'params' => $args);
|
||||
$this->calls[] = $struct;
|
||||
|
||||
return (count($this->calls) - 1);
|
||||
}
|
||||
|
||||
function multiquery($ignoreResult = false) {
|
||||
// Prepare multicall, then call the parent::query() (or queryIgnoreResult) method
|
||||
if ($ignoreResult) {
|
||||
$result = parent::queryIgnoreResult('system.multicall', $this->calls);
|
||||
} else {
|
||||
$result = parent::query('system.multicall', $this->calls);
|
||||
}
|
||||
$this->calls = array(); // reset for next calls
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The following code is a workaround for php's unpack function which
|
||||
* does not have the capability of unpacking double precision floats
|
||||
* that were packed in the opposite byte order of the current machine.
|
||||
*/
|
||||
function big_endian_unpack($format, $data) {
|
||||
$ar = unpack($format, $data);
|
||||
$vals = array_values($ar);
|
||||
$f = explode('/', $format);
|
||||
$i = 0;
|
||||
foreach ($f as $f_k => $f_v) {
|
||||
$repeater = intval(substr($f_v, 1));
|
||||
if ($repeater == 0)
|
||||
$repeater = 1;
|
||||
if ($f_v{1} == '*') {
|
||||
$repeater = count($ar) - $i;
|
||||
}
|
||||
if ($f_v{0} != 'd') {
|
||||
$i += $repeater;
|
||||
continue;
|
||||
}
|
||||
$j = $i + $repeater;
|
||||
for ($a = $i; $a < $j; ++$a) {
|
||||
$p = pack('d', $vals[$i]);
|
||||
$p = strrev($p);
|
||||
list($vals[$i]) = array_values(unpack('d1d', $p));
|
||||
++$i;
|
||||
}
|
||||
}
|
||||
$a = 0;
|
||||
foreach ($ar as $ar_k => $ar_v) {
|
||||
$ar[$ar_k] = $vals[$a];
|
||||
++$a;
|
||||
}
|
||||
return $ar;
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,854 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/*
|
||||
IXR - The Incutio XML-RPC Library - (c) Incutio Ltd 2002
|
||||
Version 1.61 - Simon Willison, 11th July 2003 (htmlentities -> htmlspecialchars)
|
||||
Site: http://scripts.incutio.com/xmlrpc/
|
||||
Manual: http://scripts.incutio.com/xmlrpc/manual.php
|
||||
Errors: http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
|
||||
Made available under the Artistic License: http://www.opensource.org/licenses/artistic-license.php
|
||||
|
||||
Modified to support protocol 'GbxRemote 2' ('GbxRemote 1')
|
||||
This version is for LittleEndian (e.g. Intel PC) machines. For BegEndian
|
||||
machines use GbxRemote.bem.php as GbxRemote.inc.php instead.
|
||||
|
||||
Release 2007-09-22 - Slig:
|
||||
Modified to support >256KB received data (and now >2MB data produce a specific error message)
|
||||
Modified readCB() to wait the initial timeout only before first read packet
|
||||
Modified readCB() to return true if there is data to get with getCBResponses()
|
||||
Modified to support amd64 (for $recvhandle)
|
||||
Modified IXR_ClientMulticall_Gbx::addCall() to fit Aseco 0.6.1
|
||||
Added IXR_Client_Gbx::bytes_sent & bytes_received counters
|
||||
Fix for a changed feature since php5.1.1 about reference parameter assignment (was used in stream_select)
|
||||
Workaround for stream_select return value bug with amd64
|
||||
|
||||
Release 2008-01-20 - Slig / Xymph / Assembler Maniac:
|
||||
Workaround for fread delay bug in some cases
|
||||
Added IXR_Client_Gbx::resetError() method (by Xymph)
|
||||
Some comments and strings code cleanup (by Xymph)
|
||||
Fix stream_set_timeout($this->socket,...) (thx to CavalierDeVache)
|
||||
Added a default timeout value to IXR_Client_Gbx::readCB($timeout)
|
||||
Changed calls with timeout on a stream to use microseconds instead of seconds (by AM)
|
||||
Removed IXR_Client_Gbx::bytes_sent & bytes_received counters - not used (by AM)
|
||||
|
||||
Release 2008-02-05 - Slig:
|
||||
Changed some socket read/write timeouts back to seconds to avoid 'transport error'
|
||||
Changed max data received from 2MB to 4MB
|
||||
|
||||
Release 2008-05-20 - Xymph:
|
||||
Prevented unpack() warnings in IXR_Client_Gbx::query() when the connection dies
|
||||
Changed IXR_Client_Gbx::resetError() to assign 'false' for correct isError()
|
||||
Tweaked some 'transport error' messages
|
||||
|
||||
Release 2009-04-08 - Gou1:
|
||||
Added method IXR_Client_Gbx::queryIgnoreResult()
|
||||
Added methods IXR_Client_Gbx::sendRequest() & IXR_Client_Gbx::getResult()
|
||||
IXR_Client_Gbx::queryIgnoreResult checks if the request is larger than 512KB to avoid errors
|
||||
If larger than 512KB and method is system.multicall, try to divide the request into
|
||||
two separate requests with two separate IXR_Client_Gbx::queryIgnoreResult() calls
|
||||
|
||||
Release 2009-06-03 - Xymph:
|
||||
Suppress possible repetitive CRT warning at stream_select
|
||||
|
||||
Release 2011-04-09 - Xymph / La beuze:
|
||||
Added optional timeout mechanism to IXR_Client_Gbx::InitWithIp()
|
||||
|
||||
Release 2011-05-22 - Xymph:
|
||||
Added non-error (true) return status to IXR_Client_Gbx::queryIgnoreResult()
|
||||
Updated status codes and messages for transport/endian errors
|
||||
Prevented possible PHP warning in IXR_Client_Gbx::getErrorCode() and getErrorMessage()
|
||||
|
||||
Release 2011-12-04 - Xymph:
|
||||
Prevented possible PHP warning in IXR_Value::calculateType
|
||||
|
||||
Release 2013-02-18 - Xymph:
|
||||
Removed unnecessary breaks after returns in IXR_Value::getXml() switch
|
||||
*/
|
||||
|
||||
if (!defined('LF')) {
|
||||
define('LF', "\n");
|
||||
}
|
||||
|
||||
class IXR_Value {
|
||||
public $data;
|
||||
public $type;
|
||||
|
||||
function IXR_Value ($data, $type = false) {
|
||||
$this->data = $data;
|
||||
if (!$type) {
|
||||
$type = $this->calculateType();
|
||||
}
|
||||
$this->type = $type;
|
||||
if ($type == 'struct') {
|
||||
// Turn all the values in the array into new IXR_Value objects
|
||||
foreach ($this->data as $key => $value) {
|
||||
$this->data[$key] = new IXR_Value($value);
|
||||
}
|
||||
}
|
||||
if ($type == 'array') {
|
||||
for ($i = 0, $j = count($this->data); $i < $j; $i++) {
|
||||
$this->data[$i] = new IXR_Value($this->data[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function calculateType() {
|
||||
if ($this->data === true || $this->data === false) {
|
||||
return 'boolean';
|
||||
}
|
||||
if (is_integer($this->data)) {
|
||||
return 'int';
|
||||
}
|
||||
if (is_double($this->data)) {
|
||||
return 'double';
|
||||
}
|
||||
// Deal with IXR object types base64 and date
|
||||
if (is_object($this->data) && ($this->data instanceof IXR_Date)) {
|
||||
return 'date';
|
||||
}
|
||||
if (is_object($this->data) && ($this->data instanceof IXR_Base64)) {
|
||||
return 'base64';
|
||||
}
|
||||
// If it is a normal PHP object convert it into a struct
|
||||
if (is_object($this->data)) {
|
||||
$this->data = get_object_vars($this->data);
|
||||
return 'struct';
|
||||
}
|
||||
if (!is_array($this->data)) {
|
||||
return 'string';
|
||||
}
|
||||
// We have an array - is it an array or a struct?
|
||||
if ($this->isStruct($this->data)) {
|
||||
return 'struct';
|
||||
} else {
|
||||
return 'array';
|
||||
}
|
||||
}
|
||||
|
||||
function getXml() {
|
||||
// Return XML for this value
|
||||
switch ($this->type) {
|
||||
case 'boolean':
|
||||
return '<boolean>' . ($this->data ? '1' : '0') . '</boolean>';
|
||||
case 'int':
|
||||
return '<int>' . $this->data . '</int>';
|
||||
case 'double':
|
||||
return '<double>' . $this->data . '</double>';
|
||||
case 'string':
|
||||
return '<string>' . htmlspecialchars($this->data) . '</string>';
|
||||
case 'array':
|
||||
$return = '<array><data>' . LF;
|
||||
foreach ($this->data as $item) {
|
||||
$return .= ' <value>' . $item->getXml() . '</value>' . LF;
|
||||
}
|
||||
$return .= '</data></array>';
|
||||
return $return;
|
||||
case 'struct':
|
||||
$return = '<struct>' . LF;
|
||||
foreach ($this->data as $name => $value) {
|
||||
$return .= ' <member><name>' . $name . '</name><value>';
|
||||
$return .= $value->getXml() . '</value></member>' . LF;
|
||||
}
|
||||
$return .= '</struct>';
|
||||
return $return;
|
||||
case 'date':
|
||||
case 'base64':
|
||||
return $this->data->getXml();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isStruct($array) {
|
||||
// Nasty function to check if an array is a struct or not
|
||||
$expected = 0;
|
||||
foreach ($array as $key => $value) {
|
||||
if ((string)$key != (string)$expected) {
|
||||
return true;
|
||||
}
|
||||
$expected++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IXR_Message {
|
||||
public $message;
|
||||
public $messageType; // methodCall / methodResponse / fault
|
||||
public $faultCode;
|
||||
public $faultString;
|
||||
public $methodName;
|
||||
public $params;
|
||||
// Current variable stacks
|
||||
protected $_arraystructs = array(); // Stack to keep track of the current array/struct
|
||||
protected $_arraystructstypes = array(); // Stack to keep track of whether things are structs or array
|
||||
protected $_currentStructName = array(); // A stack as well
|
||||
protected $_param;
|
||||
protected $_value;
|
||||
protected $_currentTag;
|
||||
protected $_currentTagContents;
|
||||
// The XML parser
|
||||
protected $_parser;
|
||||
|
||||
function IXR_Message ($message) {
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
function parse() {
|
||||
// first remove the XML declaration
|
||||
$this->message = preg_replace('/<\?xml(.*)?\?'.'>/', '', $this->message);
|
||||
if (trim($this->message) == '') {
|
||||
return false;
|
||||
}
|
||||
$this->_parser = xml_parser_create();
|
||||
// Set XML parser to take the case of tags into account
|
||||
xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
|
||||
// Set XML parser callback functions
|
||||
xml_set_object($this->_parser, $this);
|
||||
xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
|
||||
xml_set_character_data_handler($this->_parser, 'cdata');
|
||||
if (!xml_parse($this->_parser, $this->message)) {
|
||||
/* die(sprintf('GbxRemote XML error: %s at line %d',
|
||||
xml_error_string(xml_get_error_code($this->_parser)),
|
||||
xml_get_current_line_number($this->_parser))); */
|
||||
return false;
|
||||
}
|
||||
xml_parser_free($this->_parser);
|
||||
// Grab the error messages, if any
|
||||
if ($this->messageType == 'fault') {
|
||||
$this->faultCode = $this->params[0]['faultCode'];
|
||||
$this->faultString = $this->params[0]['faultString'];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function tag_open($parser, $tag, $attr) {
|
||||
$this->currentTag = $tag;
|
||||
switch ($tag) {
|
||||
case 'methodCall':
|
||||
case 'methodResponse':
|
||||
case 'fault':
|
||||
$this->messageType = $tag;
|
||||
break;
|
||||
// Deal with stacks of arrays and structs
|
||||
case 'data': // data is to all intents and purposes more interesting than array
|
||||
$this->_arraystructstypes[] = 'array';
|
||||
$this->_arraystructs[] = array();
|
||||
break;
|
||||
case 'struct':
|
||||
$this->_arraystructstypes[] = 'struct';
|
||||
$this->_arraystructs[] = array();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function cdata($parser, $cdata) {
|
||||
$this->_currentTagContents .= $cdata;
|
||||
}
|
||||
|
||||
function tag_close($parser, $tag) {
|
||||
$valueFlag = false;
|
||||
switch ($tag) {
|
||||
case 'int':
|
||||
case 'i4':
|
||||
$value = (int)trim($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
break;
|
||||
case 'double':
|
||||
$value = (double)trim($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
break;
|
||||
case 'string':
|
||||
$value = (string)trim($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
break;
|
||||
case 'dateTime.iso8601':
|
||||
$value = new IXR_Date(trim($this->_currentTagContents));
|
||||
// $value = $iso->getTimestamp();
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
break;
|
||||
case 'value':
|
||||
// If no type is indicated, the type is string
|
||||
if (trim($this->_currentTagContents) != '') {
|
||||
$value = (string)$this->_currentTagContents;
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
}
|
||||
break;
|
||||
case 'boolean':
|
||||
$value = (boolean)trim($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
break;
|
||||
case 'base64':
|
||||
$value = base64_decode($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
$valueFlag = true;
|
||||
break;
|
||||
// Deal with stacks of arrays and structs
|
||||
case 'data':
|
||||
case 'struct':
|
||||
$value = array_pop($this->_arraystructs);
|
||||
array_pop($this->_arraystructstypes);
|
||||
$valueFlag = true;
|
||||
break;
|
||||
case 'member':
|
||||
array_pop($this->_currentStructName);
|
||||
break;
|
||||
case 'name':
|
||||
$this->_currentStructName[] = trim($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
break;
|
||||
case 'methodName':
|
||||
$this->methodName = trim($this->_currentTagContents);
|
||||
$this->_currentTagContents = '';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($valueFlag) {
|
||||
/*
|
||||
if (!is_array($value) && !is_object($value)) {
|
||||
$value = trim($value);
|
||||
}
|
||||
*/
|
||||
if (count($this->_arraystructs) > 0) {
|
||||
// Add value to struct or array
|
||||
if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
|
||||
// Add to struct
|
||||
$this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value;
|
||||
} else {
|
||||
// Add to array
|
||||
$this->_arraystructs[count($this->_arraystructs)-1][] = $value;
|
||||
}
|
||||
} else {
|
||||
// Just add as a paramater
|
||||
$this->params[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IXR_Request {
|
||||
public $method;
|
||||
public $args;
|
||||
public $xml;
|
||||
|
||||
function IXR_Request($method, $args) {
|
||||
$this->method = $method;
|
||||
$this->args = $args;
|
||||
$this->xml = '<?xml version="1.0" encoding="utf-8" ?><methodCall><methodName>' . $this->method . '</methodName><params>';
|
||||
foreach ($this->args as $arg) {
|
||||
$this->xml .= '<param><value>';
|
||||
$v = new IXR_Value($arg);
|
||||
$this->xml .= $v->getXml();
|
||||
$this->xml .= '</value></param>' . LF;
|
||||
}
|
||||
$this->xml .= '</params></methodCall>';
|
||||
}
|
||||
|
||||
function getLength() {
|
||||
return strlen($this->xml);
|
||||
}
|
||||
|
||||
function getXml() {
|
||||
return $this->xml;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IXR_Error {
|
||||
public $code;
|
||||
public $message;
|
||||
|
||||
function IXR_Error($code, $message) {
|
||||
$this->code = $code;
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
function getXml() {
|
||||
$xml = <<<EOD
|
||||
<methodResponse>
|
||||
<fault>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>faultCode</name>
|
||||
<value><int>{$this->code}</int></value>
|
||||
</member>
|
||||
<member>
|
||||
<name>faultString</name>
|
||||
<value><string>{$this->message}</string></value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</fault>
|
||||
</methodResponse>
|
||||
EOD;
|
||||
return $xml;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IXR_Date {
|
||||
public $year;
|
||||
public $month;
|
||||
public $day;
|
||||
public $hour;
|
||||
public $minute;
|
||||
public $second;
|
||||
|
||||
function IXR_Date($time) {
|
||||
// $time can be a PHP timestamp or an ISO one
|
||||
if (is_numeric($time)) {
|
||||
$this->parseTimestamp($time);
|
||||
} else {
|
||||
$this->parseIso($time);
|
||||
}
|
||||
}
|
||||
|
||||
function parseTimestamp($timestamp) {
|
||||
$this->year = date('Y', $timestamp);
|
||||
$this->month = date('Y', $timestamp);
|
||||
$this->day = date('Y', $timestamp);
|
||||
$this->hour = date('H', $timestamp);
|
||||
$this->minute = date('i', $timestamp);
|
||||
$this->second = date('s', $timestamp);
|
||||
}
|
||||
|
||||
function parseIso($iso) {
|
||||
$this->year = substr($iso, 0, 4);
|
||||
$this->month = substr($iso, 4, 2);
|
||||
$this->day = substr($iso, 6, 2);
|
||||
$this->hour = substr($iso, 9, 2);
|
||||
$this->minute = substr($iso, 12, 2);
|
||||
$this->second = substr($iso, 15, 2);
|
||||
}
|
||||
|
||||
function getIso() {
|
||||
return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second;
|
||||
}
|
||||
|
||||
function getXml() {
|
||||
return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
|
||||
}
|
||||
|
||||
function getTimestamp() {
|
||||
return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IXR_Base64 {
|
||||
public $data;
|
||||
|
||||
function IXR_Base64($data) {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
function getXml() {
|
||||
return '<base64>'.base64_encode($this->data).'</base64>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// Nadeo modifications //
|
||||
// (many thanks to slig for adding callback support) //
|
||||
//////////////////////////////////////////////////////////
|
||||
class IXR_Client_Gbx {
|
||||
public $socket;
|
||||
public $message = false;
|
||||
public $cb_message = array();
|
||||
public $reqhandle;
|
||||
public $protocol = 0;
|
||||
// Storage place for an error message
|
||||
public $error = false;
|
||||
|
||||
function bigEndianTest() {
|
||||
list($endiantest) = array_values(unpack('L1L', pack('V', 1)));
|
||||
if ($endiantest != 1) {
|
||||
echo "Machine reports itself as BigEndian, float handling must be altered\r\n";
|
||||
echo "Overwrite GbxRemote.inc.php with GbxRemote.bem.php\r\n";
|
||||
die('App Terminated');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // bigEndianTest
|
||||
|
||||
function IXR_Client_Gbx() {
|
||||
$this->socket = false;
|
||||
$this->reqhandle = 0x80000000;
|
||||
}
|
||||
|
||||
function InitWithIp($ip, $port, $timeout = null) {
|
||||
|
||||
if (!$this->bigEndianTest()) {
|
||||
$this->error = new IXR_Error(-31999, 'endian error - script doesn\'t match machine type');
|
||||
return false;
|
||||
}
|
||||
|
||||
// open connection, with timeout if specified
|
||||
if (!isset($timeout)) {
|
||||
$this->socket = @fsockopen($ip, $port, $errno, $errstr);
|
||||
} else {
|
||||
$init_time = microtime(true);
|
||||
$init_timeout = 5; // retry every 5s
|
||||
while (true) {
|
||||
$this->socket = @fsockopen($ip, $port, $errno, $errstr, $init_timeout);
|
||||
if ($this->socket || (microtime(true) - $init_time >= $timeout))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$this->socket) {
|
||||
$this->error = new IXR_Error(-32300, "transport error - could not open socket (error: $errno, $errstr)");
|
||||
return false;
|
||||
}
|
||||
// handshake
|
||||
$array_result = unpack('Vsize', fread($this->socket, 4));
|
||||
$size = $array_result['size'];
|
||||
if ($size > 64) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - wrong lowlevel protocol header');
|
||||
return false;
|
||||
}
|
||||
$handshake = fread($this->socket, $size);
|
||||
if ($handshake == 'GBXRemote 1') {
|
||||
$this->protocol = 1;
|
||||
} else if ($handshake == 'GBXRemote 2') {
|
||||
$this->protocol = 2;
|
||||
} else {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - wrong lowlevel protocol version');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function Init($port) {
|
||||
return $this->InitWithIp('localhost', $port);
|
||||
}
|
||||
|
||||
function Terminate() {
|
||||
if ($this->socket) {
|
||||
fclose($this->socket);
|
||||
$this->socket = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function sendRequest(IXR_Request $request) {
|
||||
$xml = $request->getXml();
|
||||
|
||||
@stream_set_timeout($this->socket, 20); // timeout 20s (to write the request)
|
||||
// send request
|
||||
$this->reqhandle++;
|
||||
if ($this->protocol == 1) {
|
||||
$bytes = pack('Va*', strlen($xml), $xml);
|
||||
} else {
|
||||
$bytes = pack('VVa*', strlen($xml), $this->reqhandle, $xml);
|
||||
}
|
||||
|
||||
$bytes_to_write = strlen($bytes);
|
||||
while ($bytes_to_write > 0) {
|
||||
$r = @fwrite($this->socket, $bytes);
|
||||
if ($r === false || $r == 0) {
|
||||
// connection interrupted
|
||||
return false; // or die?
|
||||
}
|
||||
|
||||
$bytes_to_write -= $r;
|
||||
if ($bytes_to_write == 0)
|
||||
break;
|
||||
|
||||
$bytes = substr($bytes, $r);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getResult() {
|
||||
$contents = '';
|
||||
$contents_length = 0;
|
||||
do {
|
||||
$size = 0;
|
||||
$recvhandle = 0;
|
||||
@stream_set_timeout($this->socket, 20); // timeout 20s (to read the reply header)
|
||||
// Get result
|
||||
if ($this->protocol == 1) {
|
||||
$contents = fread($this->socket, 4);
|
||||
if (strlen($contents) == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - cannot read size');
|
||||
return false;
|
||||
}
|
||||
$array_result = unpack('Vsize', $contents);
|
||||
$size = $array_result['size'];
|
||||
$recvhandle = $this->reqhandle;
|
||||
} else {
|
||||
$contents = fread($this->socket, 8);
|
||||
if (strlen($contents) == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - cannot read size/handle');
|
||||
return false;
|
||||
}
|
||||
$array_result = unpack('Vsize/Vhandle', $contents);
|
||||
$size = $array_result['size'];
|
||||
$recvhandle = $array_result['handle'];
|
||||
// -- amd64 support --
|
||||
$bits = sprintf('%b', $recvhandle);
|
||||
if (strlen($bits) == 64) {
|
||||
$recvhandle = bindec(substr($bits, 32));
|
||||
}
|
||||
}
|
||||
|
||||
if ($recvhandle == 0 || $size == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - connection interrupted!');
|
||||
return false;
|
||||
}
|
||||
if ($size > 4096*1024) {
|
||||
$this->error = new IXR_Error(-32300, "transport error - response too large ($size)");
|
||||
return false;
|
||||
}
|
||||
|
||||
$contents = '';
|
||||
$contents_length = 0;
|
||||
@stream_set_timeout($this->socket, 0, 10000); // timeout 10 ms (for successive reads until end)
|
||||
while ($contents_length < $size) {
|
||||
$contents .= fread($this->socket, $size-$contents_length);
|
||||
$contents_length = strlen($contents);
|
||||
}
|
||||
|
||||
if (($recvhandle & 0x80000000) == 0) {
|
||||
// this is a callback, not our answer! handle= $recvhandle, xml-rpc= $contents
|
||||
// just add it to the message list for the user to read
|
||||
$new_cb_message = new IXR_Message($contents);
|
||||
if ($new_cb_message->parse() && $new_cb_message->messageType != 'fault') {
|
||||
array_push($this->cb_message, array($new_cb_message->methodName, $new_cb_message->params));
|
||||
}
|
||||
}
|
||||
} while ((int)$recvhandle != (int)$this->reqhandle);
|
||||
|
||||
$this->message = new IXR_Message($contents);
|
||||
if (!$this->message->parse()) {
|
||||
// XML error
|
||||
$this->error = new IXR_Error(-32700, 'parse error. not well formed');
|
||||
return false;
|
||||
}
|
||||
// Is the message a fault?
|
||||
if ($this->message->messageType == 'fault') {
|
||||
$this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
|
||||
return false;
|
||||
}
|
||||
// Message must be OK
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function query() {
|
||||
$args = func_get_args();
|
||||
$method = array_shift($args);
|
||||
|
||||
if (!$this->socket || $this->protocol == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - client not initialized');
|
||||
return false;
|
||||
}
|
||||
|
||||
$request = new IXR_Request($method, $args);
|
||||
|
||||
// Check if request is larger than 512 Kbytes
|
||||
if (($size = $request->getLength()) > 512*1024-8) {
|
||||
$this->error = new IXR_Error(-32300, "transport error - request too large ($size)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send request
|
||||
$ok = $this->sendRequest($request);
|
||||
if (!$ok) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - connection interrupted!');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get result
|
||||
return $this->getResult();
|
||||
}
|
||||
|
||||
// Non-blocking query method: doesn't read the response
|
||||
function queryIgnoreResult() {
|
||||
$args = func_get_args();
|
||||
$method = array_shift($args);
|
||||
|
||||
if (!$this->socket || $this->protocol == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - client not initialized');
|
||||
return false;
|
||||
}
|
||||
|
||||
$request = new IXR_Request($method, $args);
|
||||
|
||||
// Check if the request is greater than 512 Kbytes to avoid errors
|
||||
// If the method is system.multicall, make two calls (possibly recursively)
|
||||
if (($size = $request->getLength()) > 512*1024-8) {
|
||||
if ($method = 'system.multicall' && isset($args[0])) {
|
||||
$count = count($args[0]);
|
||||
// If count is 1, query cannot be reduced
|
||||
if ($count < 2) {
|
||||
$this->error = new IXR_Error(-32300, "transport error - request too large ($size)");
|
||||
return false;
|
||||
}
|
||||
$length = floor($count/2);
|
||||
$args1 = array_slice($args[0], 0, $length);
|
||||
$args2 = array_slice($args[0], $length, ($count-$length));
|
||||
|
||||
$res1 = $this->queryIgnoreResult('system.multicall', $args1);
|
||||
$res2 = $this->queryIgnoreResult('system.multicall', $args2);
|
||||
return ($res1 && $res2);
|
||||
}
|
||||
// If the method is not a multicall, just stop
|
||||
else {
|
||||
$this->error = new IXR_Error(-32300, "transport error - request too large ($size)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Send request
|
||||
$ok = $this->sendRequest($request);
|
||||
if (!$ok) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - connection interrupted!');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function readCB($timeout = 2000) { // timeout 2 ms
|
||||
if (!$this->socket || $this->protocol == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - client not initialized');
|
||||
return false;
|
||||
}
|
||||
if ($this->protocol == 1)
|
||||
return false;
|
||||
|
||||
$something_received = count($this->cb_message)>0;
|
||||
$contents = '';
|
||||
$contents_length = 0;
|
||||
|
||||
@stream_set_timeout($this->socket, 0, 10000); // timeout 10 ms (to read available data)
|
||||
// (assignment in arguments is forbidden since php 5.1.1)
|
||||
$read = array($this->socket);
|
||||
$write = NULL;
|
||||
$except = NULL;
|
||||
$nb = @stream_select($read, $write, $except, 0, $timeout);
|
||||
// workaround for stream_select bug with amd64
|
||||
if ($nb !== false)
|
||||
$nb = count($read);
|
||||
|
||||
while ($nb !== false && $nb > 0) {
|
||||
$timeout = 0; // we don't want to wait for the full time again, just flush the available data
|
||||
|
||||
$size = 0;
|
||||
$recvhandle = 0;
|
||||
// Get result
|
||||
$contents = fread($this->socket, 8);
|
||||
if (strlen($contents) == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - cannot read size/handle');
|
||||
return false;
|
||||
}
|
||||
$array_result = unpack('Vsize/Vhandle', $contents);
|
||||
$size = $array_result['size'];
|
||||
$recvhandle = $array_result['handle'];
|
||||
|
||||
if ($recvhandle == 0 || $size == 0) {
|
||||
$this->error = new IXR_Error(-32300, 'transport error - connection interrupted!');
|
||||
return false;
|
||||
}
|
||||
if ($size > 4096*1024) {
|
||||
$this->error = new IXR_Error(-32300, "transport error - response too large ($size)");
|
||||
return false;
|
||||
}
|
||||
|
||||
$contents = '';
|
||||
$contents_length = 0;
|
||||
while ($contents_length < $size) {
|
||||
$contents .= fread($this->socket, $size-$contents_length);
|
||||
$contents_length = strlen($contents);
|
||||
}
|
||||
|
||||
if (($recvhandle & 0x80000000) == 0) {
|
||||
// this is a callback. handle= $recvhandle, xml-rpc= $contents
|
||||
//echo 'CALLBACK('.$contents_length.')[ '.$contents.' ]' . LF;
|
||||
$new_cb_message = new IXR_Message($contents);
|
||||
if ($new_cb_message->parse() && $new_cb_message->messageType != 'fault') {
|
||||
array_push($this->cb_message, array($new_cb_message->methodName, $new_cb_message->params));
|
||||
}
|
||||
$something_received = true;
|
||||
}
|
||||
|
||||
// (assignment in arguments is forbidden since php 5.1.1)
|
||||
$read = array($this->socket);
|
||||
$write = NULL;
|
||||
$except = NULL;
|
||||
$nb = @stream_select($read, $write, $except, 0, $timeout);
|
||||
// workaround for stream_select bug with amd64
|
||||
if ($nb !== false)
|
||||
$nb = count($read);
|
||||
}
|
||||
return $something_received;
|
||||
}
|
||||
|
||||
function getResponse() {
|
||||
// methodResponses can only have one param - return that
|
||||
return $this->message->params[0];
|
||||
}
|
||||
|
||||
function getCBResponses() {
|
||||
// (look at the end of basic.php for an example)
|
||||
$messages = $this->cb_message;
|
||||
$this->cb_message = array();
|
||||
return $messages;
|
||||
}
|
||||
|
||||
function isError() {
|
||||
return is_object($this->error);
|
||||
}
|
||||
|
||||
function resetError() {
|
||||
$this->error = false;
|
||||
}
|
||||
|
||||
function getErrorCode() {
|
||||
if ($this->isError())
|
||||
return $this->error->code;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getErrorMessage() {
|
||||
if ($this->isError())
|
||||
return $this->error->message;
|
||||
else
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IXR_ClientMulticall_Gbx extends IXR_Client_Gbx {
|
||||
public $calls = array();
|
||||
|
||||
function addCall($methodName, $args) {
|
||||
$struct = array('methodName' => $methodName, 'params' => $args);
|
||||
$this->calls[] = $struct;
|
||||
|
||||
return (count($this->calls) - 1);
|
||||
}
|
||||
|
||||
function multiquery($ignoreResult = false) {
|
||||
// Prepare multicall, then call the parent::query() (or queryIgnoreResult) method
|
||||
if ($ignoreResult) {
|
||||
$result = parent::queryIgnoreResult('system.multicall', $this->calls);
|
||||
} else {
|
||||
$result = parent::query('system.multicall', $this->calls);
|
||||
}
|
||||
$this->calls = array(); // reset for next calls
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,218 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// File: Adds to GbxRemote.inc.php
|
||||
// Date: 10.07.2007
|
||||
// Author: Gilles Masson
|
||||
// Updated: Xymph
|
||||
//
|
||||
// xmlrpc_request() or RequestStd class to build a methodCall request (xml-rpc string)
|
||||
// xmlrpc_response() or ResponseStd class to build a method response (xml-rpc string)
|
||||
// xmlrpc_error() to build an error response (xml-rpc string)
|
||||
// rpc_method() to build a method array (for method call in a multicall)
|
||||
// rpc_response() to build a response array (for method response in a multicall)
|
||||
// rpc_error() to build an error array (for method error in a multicall)
|
||||
// xml_decode_rpc() to build a data array from a xml-rpc string
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Build a methodCall request in xml-rpc format from methodname and array params
|
||||
// (methodname + array_params ==> xml-rpc string)
|
||||
// -----------------------------------------------------------------------
|
||||
// $method is the method name.
|
||||
// $params should be an array containing the method parameters.
|
||||
// For system.multicall, there should be one parameter, which is an array
|
||||
// containing the methods structs {'methodName':string, 'params':array}
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
function xmlrpc_request($method, $params = null) {
|
||||
|
||||
// in case the first level array was forgotten in a multicall then add it...
|
||||
if ($method == 'system.multicall' && isset($params[0]['methodName']))
|
||||
$params = array($params);
|
||||
|
||||
$xml = '<?xml version="1.0" encoding="UTF-8" ?>'
|
||||
. "\n<methodCall>\n<methodName>$method</methodName>\n<params>\n";
|
||||
|
||||
if (is_array($params)) {
|
||||
foreach ($params as $param) {
|
||||
$xml .= "<param>\n<value>";
|
||||
$v = new IXR_Value($param);
|
||||
$xml .= $v->getXml();
|
||||
$xml .= "</value>\n</param>\n";
|
||||
}
|
||||
}
|
||||
$xml .= "</params>\n</methodCall>";
|
||||
return $xml;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Build a methodCall response in xml-rpc format from arrays args
|
||||
// (array_args ==> xml-rpc string)
|
||||
// -----------------------------------------------------------------------
|
||||
// $args should be an array containing the response
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
function xmlrpc_response($args = null) {
|
||||
|
||||
$xml = '<?xml version="1.0" encoding="UTF-8" ?>'
|
||||
. "\n<methodResponse>\n<params>\n<param>\n";
|
||||
|
||||
if ($args !== null) {
|
||||
$xml .= '<value>';
|
||||
$v = new IXR_Value($args);
|
||||
$xml .= $v->getXml();
|
||||
$xml .= "</value>\n";
|
||||
}
|
||||
$xml .= "</param>\n</params>\n</methodResponse>";
|
||||
return $xml;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Build an error response in xml-rpc format
|
||||
// (error code + message ==> xml-rpc string)
|
||||
// -----------------------------------------------------------------------
|
||||
// $code is the error code
|
||||
// $message is the error string
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
function xmlrpc_error($code, $message) {
|
||||
|
||||
$xml = '<?xml version="1.0" encoding="UTF-8" ?>'
|
||||
. "\n<methodResponse>\n<fault>\n"
|
||||
. "<value><struct>\n"
|
||||
. "<member><name>faultCode</name><value><int>$code</int></value>\n</member>\n"
|
||||
. "<member><name>faultString</name><value><string>$message</string></value></member>\n"
|
||||
. "</struct></value>\n"
|
||||
. "</fault>\n</methodResponse>";
|
||||
return $xml;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Build a method struct (array) usable for a method call in a multicall
|
||||
// (method name + params array ==> method struct array
|
||||
// -----------------------------------------------------------------------
|
||||
// $name is the method name
|
||||
// $params is the params array
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
function rpc_method($name, $params = null) {
|
||||
|
||||
if (!is_array($params))
|
||||
$params = array();
|
||||
return array('methodName' => $name, 'params' => $params);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Build a response struct (array) usable as a reply for a method in a multicall
|
||||
// (method name + params array ==> method struct array
|
||||
// -----------------------------------------------------------------------
|
||||
// $params is the methode response array
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
function rpc_response($response = null) {
|
||||
|
||||
if (!is_array($response))
|
||||
$response = array();
|
||||
return array($response);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Build an error struct (array) usable as an error for a method in a multicall
|
||||
// (error code + message ==> error struct array)
|
||||
// -----------------------------------------------------------------------
|
||||
// $code is the error code
|
||||
// $message is the error string
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
function rpc_error($code, $message) {
|
||||
|
||||
return array('faultCode' => $code, 'faultString' => $message);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Build a data array from a text xml-rpc
|
||||
// (xml-rpc string ==> array)
|
||||
// -----------------------------------------------------------------------
|
||||
// $xml is the xml-rpc text to decode
|
||||
// If there is an error then null is returned, you can then look infos
|
||||
// in global $_xmlrpc_decode_obj
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
function xml_decode_rpc($xml) {
|
||||
global $_xmlrpc_decode_obj;
|
||||
|
||||
$_xmlrpc_decode_obj = new IXR_Message($xml);
|
||||
if (!$_xmlrpc_decode_obj->parse() || !isset($_xmlrpc_decode_obj->params[0]))
|
||||
return null;
|
||||
return $_xmlrpc_decode_obj->params[0];
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// use this class constructor to build a methodCall request
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
class IXR_RequestStd {
|
||||
var $method;
|
||||
var $params;
|
||||
var $xml;
|
||||
|
||||
// see xmlrpc_request
|
||||
function IXR_RequestStd($method, $params = null) {
|
||||
|
||||
$this->method = $method;
|
||||
// in case the first level array was forgotten in a multicall then add it...
|
||||
if ($method == 'system.multicall' && isset($params[0]['methodName']))
|
||||
$this->params = array($params);
|
||||
else
|
||||
$this->params = $params;
|
||||
|
||||
$this->xml = xmlrpc_request($this->method, $this->params);
|
||||
}
|
||||
|
||||
function getLength() {
|
||||
|
||||
return strlen($this->xml);
|
||||
}
|
||||
|
||||
function getXml() {
|
||||
|
||||
return $this->xml;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// use this class constructor to build a methodCall response
|
||||
// -----------------------------------------------------------------------
|
||||
class IXR_ResponseStd {
|
||||
var $args;
|
||||
var $xml;
|
||||
|
||||
// see xmlrpc_response
|
||||
function IXR_ResponseStd($args) {
|
||||
|
||||
$this->args = $args;
|
||||
$this->xml = xmlrpc_response($this->args);
|
||||
}
|
||||
|
||||
function getLength() {
|
||||
|
||||
return strlen($this->xml);
|
||||
}
|
||||
|
||||
function getXml() {
|
||||
|
||||
return $this->xml;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,830 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
// Updated by Xymph
|
||||
|
||||
/**
|
||||
* Writes a logfile of all output messages, either in a single big file
|
||||
* or in monthly chunks inside the logs/ directory.
|
||||
*/
|
||||
function doLog($text) {
|
||||
global $logfile;
|
||||
|
||||
if (MONTHLY_LOGSDIR) {
|
||||
// create logs/ directory if needed
|
||||
$dir = './logs';
|
||||
if (!file_exists($dir)) mkdir($dir);
|
||||
|
||||
// define monthly file inside dir
|
||||
$file = $dir . '/logfile-' . date('Ym') . '.txt';
|
||||
|
||||
// if new monthly file, close old logfile
|
||||
if (!file_exists($file) && $logfile) {
|
||||
fclose($logfile);
|
||||
$logfile = false;
|
||||
}
|
||||
} else {
|
||||
// original single big file
|
||||
$file = 'logfile.txt';
|
||||
}
|
||||
|
||||
if (!$logfile) {
|
||||
$logfile = fopen($file, 'a+');
|
||||
}
|
||||
fwrite($logfile, $text);
|
||||
} // doLog
|
||||
|
||||
/**
|
||||
* Case-insensitive file_exists replacement function.
|
||||
* Returns matching path, otherwise false.
|
||||
* Created by Xymph
|
||||
*/
|
||||
function file_exists_nocase($filepath) {
|
||||
|
||||
// try case-sensitive path first
|
||||
if (file_exists($filepath)) return $filepath;
|
||||
|
||||
// extract directory path
|
||||
if (DIRECTORY_SEPARATOR == '/')
|
||||
preg_match('|^(.+/)([^/]+)$|', $filepath, $paths);
|
||||
else // '\'
|
||||
preg_match('|^(.+\\\\)([^\\\\]+)$|', $filepath, $paths);
|
||||
$dirpath = $paths[1];
|
||||
// $filename = $paths[2];
|
||||
|
||||
// collect all files inside directory
|
||||
$checkpaths = glob($dirpath . '*');
|
||||
if ($checkpaths === false || empty($checkpaths)) return false;
|
||||
|
||||
// check case-insensitive paths
|
||||
foreach ($checkpaths as $path)
|
||||
if (strtolower($filepath) == strtolower($path))
|
||||
return $path;
|
||||
|
||||
return false;
|
||||
} // file_exists_nocase
|
||||
|
||||
/**
|
||||
* Puts an element at a specific position into an array.
|
||||
* Increases original size by one element.
|
||||
*/
|
||||
function insertArrayElement(&$array, $value, $pos) {
|
||||
|
||||
// get current size
|
||||
$size = count($array);
|
||||
|
||||
// if position is in array range
|
||||
if ($pos < 0 && $pos >= $size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// shift values down
|
||||
for ($i = $size-1; $i >= $pos; $i--) {
|
||||
$array[$i+1] = $array[$i];
|
||||
}
|
||||
|
||||
// now put in the new element
|
||||
$array[$pos] = $value;
|
||||
return true;
|
||||
} // insertArrayElement
|
||||
|
||||
/**
|
||||
* Removes an element from a specific position in an array.
|
||||
* Decreases original size by one element.
|
||||
*/
|
||||
function removeArrayElement(&$array, $pos) {
|
||||
|
||||
// get current size
|
||||
$size = count($array);
|
||||
|
||||
// if position is in array range
|
||||
if ($pos < 0 && $pos >= $size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove specified element
|
||||
unset($array[$pos]);
|
||||
// shift values up
|
||||
$array = array_values($array);
|
||||
return true;
|
||||
} // removeArrayElement
|
||||
|
||||
/**
|
||||
* Moves an element from one position to the other.
|
||||
* All items between are shifted down or up as needed.
|
||||
*/
|
||||
function moveArrayElement(&$array, $from, $to) {
|
||||
|
||||
// get current size
|
||||
$size = count($array);
|
||||
|
||||
// destination and source have to be among the array borders!
|
||||
if ($from < 0 || $from >= $size || $to < 0 || $to >= $size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// backup the element we have to move
|
||||
$moving_element = $array[$from];
|
||||
|
||||
if ($from > $to) {
|
||||
// shift values between downwards
|
||||
for ($i = $from-1; $i >= $to; $i--) {
|
||||
$array[$i+1] = $array[$i];
|
||||
}
|
||||
} else { // $from < $to
|
||||
// shift values between upwards
|
||||
for ($i = $from; $i <= $to; $i++) {
|
||||
$array[$i] = $array[$i+1];
|
||||
}
|
||||
}
|
||||
|
||||
// now put in the element which was to move
|
||||
$array[$to] = $moving_element;
|
||||
return true;
|
||||
} // moveArrayElement
|
||||
|
||||
/**
|
||||
* Formats a string from the format sssshh0
|
||||
* into the format mmm:ss.hh (or mmm:ss if $hsec is false)
|
||||
*/
|
||||
function formatTime($MwTime, $hsec = true) {
|
||||
|
||||
if ($MwTime == -1) {
|
||||
return '???';
|
||||
} else {
|
||||
$minutes = floor($MwTime/(1000*60));
|
||||
$seconds = floor(($MwTime - $minutes*60*1000)/1000);
|
||||
$hseconds = substr($MwTime, strlen($MwTime)-3, 2);
|
||||
if ($hsec) {
|
||||
$tm = sprintf('%02d:%02d.%02d', $minutes, $seconds, $hseconds);
|
||||
} else {
|
||||
$tm = sprintf('%02d:%02d', $minutes, $seconds);
|
||||
}
|
||||
}
|
||||
if ($tm[0] == '0') {
|
||||
$tm = substr($tm, 1);
|
||||
}
|
||||
return $tm;
|
||||
} // formatTime
|
||||
|
||||
/**
|
||||
* Formats a string from the format sssshh0
|
||||
* into the format hh:mm:ss.hh (or hh:mm:ss if $hsec is false)
|
||||
*/
|
||||
function formatTimeH($MwTime, $hsec = true) {
|
||||
|
||||
if ($MwTime == -1) {
|
||||
return '???';
|
||||
} else {
|
||||
$hseconds = substr($MwTime, strlen($MwTime)-3, 2);
|
||||
$MwTime = substr($MwTime, 0, strlen($MwTime)-3);
|
||||
$hours = floor($MwTime / 3600);
|
||||
$MwTime = $MwTime - ($hours * 3600);
|
||||
$minutes = floor($MwTime / 60);
|
||||
$MwTime = $MwTime - ($minutes * 60);
|
||||
$seconds = floor($MwTime);
|
||||
if ($hsec) {
|
||||
return sprintf('%02d:%02d:%02d.%02d', $hours, $minutes, $seconds, $hseconds);
|
||||
} else {
|
||||
return sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
|
||||
}
|
||||
}
|
||||
} // formatTimeH
|
||||
|
||||
/**
|
||||
* Formats a text.
|
||||
* Replaces parameters in the text which are marked with {n}
|
||||
*/
|
||||
function formatText($text) {
|
||||
|
||||
// get all function's parameters
|
||||
$args = func_get_args();
|
||||
|
||||
// first parameter is the text to format
|
||||
$text = array_shift($args);
|
||||
|
||||
// further parameters will be replaced in the text
|
||||
$i = 1;
|
||||
foreach ($args as $param)
|
||||
$text = str_replace('{' . $i++ . '}', $param, $text);
|
||||
|
||||
// and return the modified text
|
||||
return $text;
|
||||
} // formatText
|
||||
|
||||
/**
|
||||
* Make String for SQL use that single quoted & got special chars replaced.
|
||||
*/
|
||||
function quotedString($input) {
|
||||
|
||||
return "'" . mysql_real_escape_string($input) . "'";
|
||||
} // quotedString
|
||||
|
||||
/**
|
||||
* Check login string for LAN postfix (pre/post v2.11.21).
|
||||
*/
|
||||
function isLANLogin($login) {
|
||||
|
||||
$n="(25[0-5]|2[0-4]\d|[01]?\d\d|\d)";
|
||||
return (preg_match("/(\/{$n}\\.{$n}\\.{$n}\\.{$n}:\d+)$/", $login) ||
|
||||
preg_match("/(_{$n}\\.{$n}\\.{$n}\\.{$n}_\d+)$/", $login));
|
||||
} // isLANLogin
|
||||
|
||||
/**
|
||||
* Summary: Strips all display formatting from an input string, suitable for display
|
||||
* within the game ('$$' escape pairs are preserved) and for logging
|
||||
* Params : $input - The input string to strip formatting from
|
||||
* $for_tm - Optional flag to double up '$' into '$$' (default, for TM) or not (for logs, etc)
|
||||
* Returns: The content portions of $input without formatting
|
||||
* Authors: Bilge/Assembler Maniac/Xymph/Slig
|
||||
*
|
||||
* "$af0Brat$s$fffwurst" will become "Bratwurst".
|
||||
* 2007-08-27 Xymph - replaced with Bilge/AM's code (w/o the H&L tags bit)
|
||||
* http://www.tm-forum.com/viewtopic.php?p=55867#p55867
|
||||
* 2008-04-24 Xymph - extended to handle the H/L/P tags for TMF
|
||||
* http://www.tm-forum.com/viewtopic.php?p=112856#p112856
|
||||
* 2009-05-16 Slig - extended to emit non-TM variant & handle incomplete colors
|
||||
* http://www.tm-forum.com/viewtopic.php?p=153368#p153368
|
||||
* 2010-10-05 Slig - updated to handle incomplete colors & tags better
|
||||
* http://www.tm-forum.com/viewtopic.php?p=183410#p183410
|
||||
* 2010-10-09 Xymph - updated to handle $[ and $] properly
|
||||
* http://www.tm-forum.com/viewtopic.php?p=183410#p183410
|
||||
*/
|
||||
function stripColors($input, $for_tm = true) {
|
||||
|
||||
return
|
||||
//Replace all occurrences of a null character back with a pair of dollar
|
||||
//signs for displaying in TM, or a single dollar for log messages etc.
|
||||
str_replace("\0", ($for_tm ? '$$' : '$'),
|
||||
//Replace links (introduced in TMU)
|
||||
preg_replace(
|
||||
'/
|
||||
#Strip TMF H, L & P links by stripping everything between each square
|
||||
#bracket pair until another $H, $L or $P sequence (or EoS) is found;
|
||||
#this allows a $H to close a $L and vice versa, as does the game
|
||||
\\$[hlp](.*?)(?:\\[.*?\\](.*?))*(?:\\$[hlp]|$)
|
||||
/ixu',
|
||||
//Keep the first and third capturing groups if present
|
||||
'$1$2',
|
||||
//Replace various patterns beginning with an unescaped dollar
|
||||
preg_replace(
|
||||
'/
|
||||
#Match a single dollar sign and any of the following:
|
||||
\\$
|
||||
(?:
|
||||
#Strip color codes by matching any hexadecimal character and
|
||||
#any other two characters following it (except $)
|
||||
[0-9a-f][^$][^$]
|
||||
#Strip any incomplete color codes by matching any hexadecimal
|
||||
#character followed by another character (except $)
|
||||
|[0-9a-f][^$]
|
||||
#Strip any single style code (including an invisible UTF8 char)
|
||||
#that is not an H, L or P link or a bracket ($[ and $])
|
||||
|[^][hlp]
|
||||
#Strip the dollar sign if it is followed by [ or ], but do not
|
||||
#strip the brackets themselves
|
||||
|(?=[][])
|
||||
#Strip the dollar sign if it is at the end of the string
|
||||
|$
|
||||
)
|
||||
#Ignore alphabet case, ignore whitespace in pattern & use UTF-8 mode
|
||||
/ixu',
|
||||
//Replace any matches with nothing (i.e. strip matches)
|
||||
'',
|
||||
//Replace all occurrences of dollar sign pairs with a null character
|
||||
str_replace('$$', "\0", $input)
|
||||
)
|
||||
)
|
||||
)
|
||||
;
|
||||
} // stripColors
|
||||
|
||||
/**
|
||||
* Strips only size tags from TM strings.
|
||||
* "$w$af0Brat$n$fffwurst" will become "$af0Brat$fffwurst".
|
||||
* 2009-03-27 Xymph - derived from stripColors above
|
||||
* http://www.tm-forum.com/viewtopic.php?f=127&t=20602
|
||||
* 2009-05-16 Slig - extended to emit non-TM variant
|
||||
* http://www.tm-forum.com/viewtopic.php?p=153368#p153368
|
||||
*/
|
||||
function stripSizes($input, $for_tm = true) {
|
||||
|
||||
return
|
||||
//Replace all occurrences of a null character back with a pair of dollar
|
||||
//signs for displaying in TM, or a single dollar for log messages etc.
|
||||
str_replace("\0", ($for_tm ? '$$' : '$'),
|
||||
//Replace various patterns beginning with an unescaped dollar
|
||||
preg_replace(
|
||||
'/
|
||||
#Match a single dollar sign and any of the following:
|
||||
\\$
|
||||
(?:
|
||||
#Strip any size code
|
||||
[nwo]
|
||||
#Strip the dollar sign if it is at the end of the string
|
||||
|$
|
||||
)
|
||||
#Ignore alphabet case, ignore whitespace in pattern & use UTF-8 mode
|
||||
/ixu',
|
||||
//Replace any matches with nothing (i.e. strip matches)
|
||||
'',
|
||||
//Replace all occurrences of dollar sign pairs with a null character
|
||||
str_replace('$$', "\0", $input)
|
||||
)
|
||||
)
|
||||
;
|
||||
} // stripSizes
|
||||
|
||||
/**
|
||||
* Strips only newlines from TM strings.
|
||||
*/
|
||||
function stripNewlines($input) {
|
||||
|
||||
return str_replace(array("\n\n", "\r", "\n"),
|
||||
array(' ', '', ''), $input);
|
||||
} // stripNewlines
|
||||
|
||||
|
||||
/**
|
||||
* Univeral show help for user, admin & Jfreu commands.
|
||||
* Created by Xymph
|
||||
*
|
||||
* $width is the width of the first column in the ManiaLink window on TMF
|
||||
*/
|
||||
function showHelp($player, $chat_commands, $head,
|
||||
$showadmin = false, $dispall = false, $width = 0.3) {
|
||||
global $aseco;
|
||||
|
||||
// display full help for TMN
|
||||
if ($aseco->server->getGame() == 'TMN' && $dispall) {
|
||||
$head = "Currently supported $head commands:" . LF;
|
||||
|
||||
if (!empty($chat_commands)) {
|
||||
// define admin or non-admin padding string
|
||||
$pad = ($showadmin ? '$f00... ' : '$f00/');
|
||||
$help = '';
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = 1;
|
||||
// create list of chat commands
|
||||
foreach ($chat_commands as $cc) {
|
||||
// collect either admin or non-admin commands
|
||||
if ($cc->isadmin == $showadmin) {
|
||||
$help .= $pad . $cc->name . ' $000' . $cc->help . LF;
|
||||
if (++$lines > 14) {
|
||||
$player->msgs[] = $head . $help;
|
||||
$lines = 0;
|
||||
$help = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if ($help != '')
|
||||
$player->msgs[] = $head . $help;
|
||||
|
||||
// display popup message
|
||||
if (count($player->msgs) == 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'OK', '', 0);
|
||||
} else { // > 2
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'Close', 'Next', 0);
|
||||
}
|
||||
}
|
||||
|
||||
// display full help for TMF
|
||||
} elseif ($aseco->server->getGame() == 'TMF' && $dispall) {
|
||||
$head = "Currently supported $head commands:";
|
||||
|
||||
if (!empty($chat_commands)) {
|
||||
// define admin or non-admin padding string
|
||||
$pad = ($showadmin ? '$f00... ' : '$f00/');
|
||||
$help = array();
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = array(1, $head, array(1.3, $width, 1.3 - $width), array('Icons64x64_1', 'TrackInfo', -0.01));
|
||||
// create list of chat commands
|
||||
foreach ($chat_commands as $cc) {
|
||||
// collect either admin or non-admin commands
|
||||
if ($cc->isadmin == $showadmin) {
|
||||
$help[] = array($pad . $cc->name, $cc->help);
|
||||
if (++$lines > 14) {
|
||||
$player->msgs[] = $help;
|
||||
$lines = 0;
|
||||
$help = array();
|
||||
}
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if (!empty($help))
|
||||
$player->msgs[] = $help;
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink_multi($player);
|
||||
}
|
||||
|
||||
// show help for TMS or TMO, and plain help for TMF/TMN
|
||||
} else {
|
||||
$head = "Currently supported $head commands:" . LF;
|
||||
$help = $aseco->formatColors('{#interact}' . $head);
|
||||
foreach ($chat_commands as $cc) {
|
||||
// collect either admin or non-admin commands
|
||||
if ($cc->isadmin == $showadmin) {
|
||||
$help .= $cc->name . ', ';
|
||||
}
|
||||
}
|
||||
// show chat message
|
||||
$help = substr($help, 0, strlen($help) - 2); // strip trailing ", "
|
||||
$aseco->client->query('ChatSendToLogin', $help, $player->login);
|
||||
}
|
||||
} // showHelp
|
||||
|
||||
/**
|
||||
* Map country names to 3-letter Nation abbreviations
|
||||
* Created by Xymph
|
||||
* Based on http://en.wikipedia.org/wiki/List_of_IOC_country_codes
|
||||
* See also http://en.wikipedia.org/wiki/Comparison_of_IOC,_FIFA,_and_ISO_3166_country_codes
|
||||
*/
|
||||
function mapCountry($country) {
|
||||
|
||||
$nations = array(
|
||||
'Afghanistan' => 'AFG',
|
||||
'Albania' => 'ALB',
|
||||
'Algeria' => 'ALG',
|
||||
'Andorra' => 'AND',
|
||||
'Angola' => 'ANG',
|
||||
'Argentina' => 'ARG',
|
||||
'Armenia' => 'ARM',
|
||||
'Aruba' => 'ARU',
|
||||
'Australia' => 'AUS',
|
||||
'Austria' => 'AUT',
|
||||
'Azerbaijan' => 'AZE',
|
||||
'Bahamas' => 'BAH',
|
||||
'Bahrain' => 'BRN',
|
||||
'Bangladesh' => 'BAN',
|
||||
'Barbados' => 'BAR',
|
||||
'Belarus' => 'BLR',
|
||||
'Belgium' => 'BEL',
|
||||
'Belize' => 'BIZ',
|
||||
'Benin' => 'BEN',
|
||||
'Bermuda' => 'BER',
|
||||
'Bhutan' => 'BHU',
|
||||
'Bolivia' => 'BOL',
|
||||
'Bosnia&Herzegovina' => 'BIH',
|
||||
'Botswana' => 'BOT',
|
||||
'Brazil' => 'BRA',
|
||||
'Brunei' => 'BRU',
|
||||
'Bulgaria' => 'BUL',
|
||||
'Burkina Faso' => 'BUR',
|
||||
'Burundi' => 'BDI',
|
||||
'Cambodia' => 'CAM',
|
||||
'Cameroon' => 'CAR', // actually CMR
|
||||
'Canada' => 'CAN',
|
||||
'Cape Verde' => 'CPV',
|
||||
'Central African Republic' => 'CAF',
|
||||
'Chad' => 'CHA',
|
||||
'Chile' => 'CHI',
|
||||
'China' => 'CHN',
|
||||
'Chinese Taipei' => 'TPE',
|
||||
'Colombia' => 'COL',
|
||||
'Congo' => 'CGO',
|
||||
'Costa Rica' => 'CRC',
|
||||
'Croatia' => 'CRO',
|
||||
'Cuba' => 'CUB',
|
||||
'Cyprus' => 'CYP',
|
||||
'Czech Republic' => 'CZE',
|
||||
'Czech republic' => 'CZE',
|
||||
'DR Congo' => 'COD',
|
||||
'Denmark' => 'DEN',
|
||||
'Djibouti' => 'DJI',
|
||||
'Dominica' => 'DMA',
|
||||
'Dominican Republic' => 'DOM',
|
||||
'Ecuador' => 'ECU',
|
||||
'Egypt' => 'EGY',
|
||||
'El Salvador' => 'ESA',
|
||||
'Eritrea' => 'ERI',
|
||||
'Estonia' => 'EST',
|
||||
'Ethiopia' => 'ETH',
|
||||
'Fiji' => 'FIJ',
|
||||
'Finland' => 'FIN',
|
||||
'France' => 'FRA',
|
||||
'Gabon' => 'GAB',
|
||||
'Gambia' => 'GAM',
|
||||
'Georgia' => 'GEO',
|
||||
'Germany' => 'GER',
|
||||
'Ghana' => 'GHA',
|
||||
'Greece' => 'GRE',
|
||||
'Grenada' => 'GRN',
|
||||
'Guam' => 'GUM',
|
||||
'Guatemala' => 'GUA',
|
||||
'Guinea' => 'GUI',
|
||||
'Guinea-Bissau' => 'GBS',
|
||||
'Guyana' => 'GUY',
|
||||
'Haiti' => 'HAI',
|
||||
'Honduras' => 'HON',
|
||||
'Hong Kong' => 'HKG',
|
||||
'Hungary' => 'HUN',
|
||||
'Iceland' => 'ISL',
|
||||
'India' => 'IND',
|
||||
'Indonesia' => 'INA',
|
||||
'Iran' => 'IRI',
|
||||
'Iraq' => 'IRQ',
|
||||
'Ireland' => 'IRL',
|
||||
'Israel' => 'ISR',
|
||||
'Italy' => 'ITA',
|
||||
'Ivory Coast' => 'CIV',
|
||||
'Jamaica' => 'JAM',
|
||||
'Japan' => 'JPN',
|
||||
'Jordan' => 'JOR',
|
||||
'Kazakhstan' => 'KAZ',
|
||||
'Kenya' => 'KEN',
|
||||
'Kiribati' => 'KIR',
|
||||
'Korea' => 'KOR',
|
||||
'Kuwait' => 'KUW',
|
||||
'Kyrgyzstan' => 'KGZ',
|
||||
'Laos' => 'LAO',
|
||||
'Latvia' => 'LAT',
|
||||
'Lebanon' => 'LIB',
|
||||
'Lesotho' => 'LES',
|
||||
'Liberia' => 'LBR',
|
||||
'Libya' => 'LBA',
|
||||
'Liechtenstein' => 'LIE',
|
||||
'Lithuania' => 'LTU',
|
||||
'Luxembourg' => 'LUX',
|
||||
'Macedonia' => 'MKD',
|
||||
'Malawi' => 'MAW',
|
||||
'Malaysia' => 'MAS',
|
||||
'Mali' => 'MLI',
|
||||
'Malta' => 'MLT',
|
||||
'Mauritania' => 'MTN',
|
||||
'Mauritius' => 'MRI',
|
||||
'Mexico' => 'MEX',
|
||||
'Moldova' => 'MDA',
|
||||
'Monaco' => 'MON',
|
||||
'Mongolia' => 'MGL',
|
||||
'Montenegro' => 'MNE',
|
||||
'Morocco' => 'MAR',
|
||||
'Mozambique' => 'MOZ',
|
||||
'Myanmar' => 'MYA',
|
||||
'Namibia' => 'NAM',
|
||||
'Nauru' => 'NRU',
|
||||
'Nepal' => 'NEP',
|
||||
'Netherlands' => 'NED',
|
||||
'New Zealand' => 'NZL',
|
||||
'Nicaragua' => 'NCA',
|
||||
'Niger' => 'NIG',
|
||||
'Nigeria' => 'NGR',
|
||||
'Norway' => 'NOR',
|
||||
'Oman' => 'OMA',
|
||||
'Other Countries' => 'OTH',
|
||||
'Pakistan' => 'PAK',
|
||||
'Palau' => 'PLW',
|
||||
'Palestine' => 'PLE',
|
||||
'Panama' => 'PAN',
|
||||
'Paraguay' => 'PAR',
|
||||
'Peru' => 'PER',
|
||||
'Philippines' => 'PHI',
|
||||
'Poland' => 'POL',
|
||||
'Portugal' => 'POR',
|
||||
'Puerto Rico' => 'PUR',
|
||||
'Qatar' => 'QAT',
|
||||
'Romania' => 'ROM', // actually ROU
|
||||
'Russia' => 'RUS',
|
||||
'Rwanda' => 'RWA',
|
||||
'Samoa' => 'SAM',
|
||||
'San Marino' => 'SMR',
|
||||
'Saudi Arabia' => 'KSA',
|
||||
'Senegal' => 'SEN',
|
||||
'Serbia' => 'SCG', // actually SRB
|
||||
'Sierra Leone' => 'SLE',
|
||||
'Singapore' => 'SIN',
|
||||
'Slovakia' => 'SVK',
|
||||
'Slovenia' => 'SLO',
|
||||
'Somalia' => 'SOM',
|
||||
'South Africa' => 'RSA',
|
||||
'Spain' => 'ESP',
|
||||
'Sri Lanka' => 'SRI',
|
||||
'Sudan' => 'SUD',
|
||||
'Suriname' => 'SUR',
|
||||
'Swaziland' => 'SWZ',
|
||||
'Sweden' => 'SWE',
|
||||
'Switzerland' => 'SUI',
|
||||
'Syria' => 'SYR',
|
||||
'Taiwan' => 'TWN',
|
||||
'Tajikistan' => 'TJK',
|
||||
'Tanzania' => 'TAN',
|
||||
'Thailand' => 'THA',
|
||||
'Togo' => 'TOG',
|
||||
'Tonga' => 'TGA',
|
||||
'Trinidad and Tobago' => 'TRI',
|
||||
'Tunisia' => 'TUN',
|
||||
'Turkey' => 'TUR',
|
||||
'Turkmenistan' => 'TKM',
|
||||
'Tuvalu' => 'TUV',
|
||||
'Uganda' => 'UGA',
|
||||
'Ukraine' => 'UKR',
|
||||
'United Arab Emirates' => 'UAE',
|
||||
'United Kingdom' => 'GBR',
|
||||
'United States of America' => 'USA',
|
||||
'Uruguay' => 'URU',
|
||||
'Uzbekistan' => 'UZB',
|
||||
'Vanuatu' => 'VAN',
|
||||
'Venezuela' => 'VEN',
|
||||
'Vietnam' => 'VIE',
|
||||
'Yemen' => 'YEM',
|
||||
'Zambia' => 'ZAM',
|
||||
'Zimbabwe' => 'ZIM',
|
||||
);
|
||||
|
||||
if (array_key_exists($country, $nations)) {
|
||||
$nation = $nations[$country];
|
||||
} else {
|
||||
$nation = 'OTH';
|
||||
if ($country != '')
|
||||
trigger_error('Could not map country: ' . $country, E_USER_WARNING);
|
||||
}
|
||||
return $nation;
|
||||
} // mapCountry
|
||||
|
||||
/**
|
||||
* Find TMX data for the given track
|
||||
* Created by Xymph
|
||||
*/
|
||||
require_once('includes/tmxinfofetcher.inc.php'); // provides access to TMX info
|
||||
function findTMXdata($uid, $envir, $exever, $records = false) {
|
||||
|
||||
// determine likely search order
|
||||
if ($envir == 'Stadium') {
|
||||
// check for old TMN
|
||||
if (strcmp($exever, '0.1.8.0') < 0)
|
||||
$sections = array('TMN', 'TMNF', 'TMU');
|
||||
// check for new TMF
|
||||
elseif (strcmp($exever, '2.11.0') >= 0)
|
||||
$sections = array('TMNF', 'TMU');
|
||||
else
|
||||
$sections = array('TMU'); // TMNF section opened after TMF beta
|
||||
} elseif ($envir == 'Bay' || $envir == 'Coast' || $envir == 'Island') {
|
||||
// check for old TMS
|
||||
if (strcmp($exever, '0.1.5.0') <= 0)
|
||||
$sections = array('TMS', 'TMU');
|
||||
else
|
||||
$sections = array('TMU'); // TMS section closed after TMU release
|
||||
} else { // $envir == 'Alpine' || 'Snow' || 'Desert' || 'Speed' || 'Rally'
|
||||
// check for old TMO
|
||||
if (strcmp($exever, '0.1.5.0') <= 0)
|
||||
$sections = array('TMO', 'TMU');
|
||||
else
|
||||
$sections = array('TMU'); // TMO section closed after TMU release
|
||||
}
|
||||
|
||||
// search TMX for track
|
||||
foreach ($sections as $section) {
|
||||
$tmxdata = new TMXInfoFetcher($section, $uid, $records);
|
||||
if ($tmxdata->name) {
|
||||
return $tmxdata;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} // findTMXdata
|
||||
|
||||
/**
|
||||
* Simple HTTP Get function with timeout
|
||||
* ok: return string || error: return false || timeout: return -1
|
||||
* if $openonly == true, don't read data but return true upon connect
|
||||
*/
|
||||
function http_get_file($url, $openonly = false) {
|
||||
global $aseco;
|
||||
|
||||
$url = parse_url($url);
|
||||
$port = isset($url['port']) ? $url['port'] : 80;
|
||||
$query = isset($url['query']) ? '?' . $url['query'] : '';
|
||||
|
||||
$fp = @fsockopen($url['host'], $port, $errno, $errstr, 4);
|
||||
if (!$fp)
|
||||
return false;
|
||||
if ($openonly) {
|
||||
fclose($fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
$uri = '';
|
||||
foreach (explode('/', $url['path']) as $subpath)
|
||||
$uri .= rawurlencode($subpath) . '/';
|
||||
$uri = substr($uri, 0, strlen($uri)-1); // strip trailing '/'
|
||||
|
||||
fwrite($fp, 'GET ' . $uri . $query . " HTTP/1.0\r\n" .
|
||||
'Host: ' . $url['host'] . "\r\n" .
|
||||
'User-Agent: XASECO-' . XASECO_VERSION . ' (' . PHP_OS . '; ' .
|
||||
$aseco->server->game . ")\r\n\r\n");
|
||||
stream_set_timeout($fp, 2);
|
||||
$res = '';
|
||||
$info['timed_out'] = false;
|
||||
while (!feof($fp) && !$info['timed_out']) {
|
||||
$res .= fread($fp, 512);
|
||||
$info = stream_get_meta_data($fp);
|
||||
}
|
||||
fclose($fp);
|
||||
|
||||
if ($info['timed_out']) {
|
||||
return -1;
|
||||
} else {
|
||||
if (substr($res, 9, 3) != '200')
|
||||
return false;
|
||||
$page = explode("\r\n\r\n", $res, 2);
|
||||
return $page[1];
|
||||
}
|
||||
} // http_get_file
|
||||
|
||||
/**
|
||||
* Return valid UTF-8 string, replacing faulty byte values with a given string
|
||||
* Created by (OoR-F)~fuckfish (fish@stabb.de)
|
||||
* http://www.tm-forum.com/viewtopic.php?p=117639#p117639
|
||||
* Based on the original tm_substr function by Slig (slig@free.fr)
|
||||
* Updated by Xymph; More info: http://en.wikipedia.org/wiki/UTF-8
|
||||
*/
|
||||
function validateUTF8String($input, $invalidRepl = '') {
|
||||
|
||||
$str = (string) $input;
|
||||
$len = strlen($str); // byte string length
|
||||
$pos = 0; // current byte pos in string
|
||||
$new = '';
|
||||
|
||||
while ($pos < $len) {
|
||||
$co = ord($str[$pos]);
|
||||
|
||||
// 4-6 bytes UTF8 => unsupported
|
||||
if ($co >= 240) {
|
||||
// bad multibyte char
|
||||
$new .= $invalidRepl;
|
||||
$pos++;
|
||||
|
||||
// 3 bytes UTF8 => 1110bbbb 10bbbbbb 10bbbbbb
|
||||
} elseif ($co >= 224) {
|
||||
if (($pos+2 < $len) &&
|
||||
(ord($str[$pos+1]) >= 128 && ord($str[$pos+1]) < 192) &&
|
||||
(ord($str[$pos+2]) >= 128 && ord($str[$pos+2]) < 192)) {
|
||||
// ok, it was 1 character, increase counters
|
||||
$new .= substr($str, $pos, 3);
|
||||
$pos += 3;
|
||||
} else {
|
||||
// bad multibyte char
|
||||
$new .= $invalidRepl;
|
||||
$pos++;
|
||||
}
|
||||
|
||||
// 2 bytes UTF8 => 110bbbbb 10bbbbbb
|
||||
} elseif ($co >= 194) {
|
||||
if (($pos+1 < $len) &&
|
||||
(ord($str[$pos+1]) >= 128 && ord($str[$pos+1]) < 192)) {
|
||||
// ok, it was 1 character, increase counters
|
||||
$new .= substr($str, $pos, 2);
|
||||
$pos += 2;
|
||||
} else {
|
||||
// bad multibyte char
|
||||
$new .= $invalidRepl;
|
||||
$pos++;
|
||||
}
|
||||
|
||||
// 2 bytes overlong encoding => unsupported
|
||||
} elseif ($co >= 192) {
|
||||
// bad multibyte char 1100000b
|
||||
$new .= $invalidRepl;
|
||||
$pos++;
|
||||
|
||||
// 1 byte ASCII => 0bbbbbbb, or invalid => 10bbbbbb or 11111bbb
|
||||
} else { // $co < 192
|
||||
// erroneous middle multibyte char?
|
||||
if ($co >= 128 || $co == 0)
|
||||
$new .= $invalidRepl;
|
||||
else
|
||||
$new .= $str[$pos];
|
||||
|
||||
$pos++;
|
||||
}
|
||||
}
|
||||
return $new;
|
||||
} // validateUTF8String
|
||||
|
||||
/**
|
||||
* Convert php.ini memory shorthand string to integer bytes
|
||||
* http://www.php.net/manual/en/function.ini-get.php#96996
|
||||
*/
|
||||
function shorthand2bytes($size_str) {
|
||||
|
||||
switch (substr($size_str, -1)) {
|
||||
case 'M': case 'm': return (int)$size_str * 1048576;
|
||||
case 'K': case 'k': return (int)$size_str * 1024;
|
||||
case 'G': case 'g': return (int)$size_str * 1073741824;
|
||||
default: return (int)$size_str;
|
||||
}
|
||||
} // return_bytes
|
||||
|
||||
/**
|
||||
* Convert boolean value to text string
|
||||
*/
|
||||
function bool2text($boolval) {
|
||||
|
||||
if ($boolval)
|
||||
return 'True';
|
||||
else
|
||||
return 'False';
|
||||
} // bool2text
|
||||
?>
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
// vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2:
|
||||
require('GbxRemote.inc.php');
|
||||
|
||||
/**
|
||||
* GBXChallInfo - Return GetCurrentChallengeInfo data for TrackMania tracks
|
||||
* Created by Xymph <tm@gamers.org>
|
||||
*
|
||||
* v1.2: Allow getting info from tracks already on the server w/o removing them
|
||||
* v1.1: Fix PHP notices about redefinition of constants
|
||||
* v1.0: Initial release
|
||||
*/
|
||||
|
||||
class GBXChallengeInfo {
|
||||
|
||||
public $name, $uid, $filename, $author, $envir, $mood,
|
||||
$bronzetm, $silvertm, $goldtm, $authortm,
|
||||
$coppers, $laprace, $nblaps, $nbcps, $nbrcps, $error;
|
||||
|
||||
/**
|
||||
* Fetches current ChallengeInfo for a GBX challenge
|
||||
* Loads track into server, selects it, gets info, and removes it from server
|
||||
*
|
||||
* @param String $filename
|
||||
* The challenge filename (must be a path below .../GameData/Tracks/)
|
||||
* @return GBXChallengeInfo
|
||||
* If $uid is empty, GBX data couldn't be extracted and $error contains
|
||||
* an error message
|
||||
*/
|
||||
public function GBXChallengeInfo($filename) {
|
||||
|
||||
$ip = 'localhost';
|
||||
$port = 5000;
|
||||
$user = 'SuperAdmin';
|
||||
$pass = 'YOUR_SUPERADMIN_PASSWORD';
|
||||
|
||||
$this->uid = '';
|
||||
$this->error = '';
|
||||
$client = new IXR_Client_Gbx;
|
||||
|
||||
// connect to the server
|
||||
if (!$client->InitWithIp($ip, $port)) {
|
||||
$this->error = 'Connection failed - Error ' . $client->getErrorCode() . ': ' . $client->getErrorMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
// log into the server
|
||||
if (!$client->query('Authenticate', $user, $pass)) {
|
||||
$this->error = 'Login failed - Error ' . $client->getErrorCode() . ': ' . $client->getErrorMessage();
|
||||
|
||||
} else {
|
||||
// add the challenge
|
||||
$ret = $client->query('AddChallenge', $filename);
|
||||
$already = ($client->getErrorMessage() == 'Challenge already added.');
|
||||
if (!$ret && !$already) {
|
||||
$this->error = 'AddChallenge failed - Error ' . $client->getErrorCode() . ': ' . $client->getErrorMessage();
|
||||
} else {
|
||||
|
||||
// select the challenge
|
||||
if (!$client->query('ChooseNextChallenge', $filename)) {
|
||||
$this->error = 'ChooseNextChallenge failed - Error ' . $client->getErrorCode() . ': ' . $client->getErrorMessage();
|
||||
|
||||
// switch to our challenge
|
||||
} elseif (!$client->query('NextChallenge')) {
|
||||
$this->error = 'NextChallenge 1 failed - Error ' . $client->getErrorCode() . ': ' . $client->getErrorMessage();
|
||||
} else {
|
||||
|
||||
// allow for challenge switch but time out after 5 seconds
|
||||
$retry = 5;
|
||||
while (true) {
|
||||
sleep(1);
|
||||
|
||||
// obtain challenge details
|
||||
if ($client->query('GetCurrentChallengeInfo')) {
|
||||
$info = $client->getResponse();
|
||||
// check for our challenge
|
||||
if ($info['FileName'] == $filename) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$this->error = 'GetCurrentChallengeInfo failed - Error ' . $client->getErrorCode() . ': ' . $client->getErrorMessage();
|
||||
break;
|
||||
}
|
||||
if ($retry-- == 0) {
|
||||
$this->error = 'GetCurrentChallengeInfo timed out after 5 seconds';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// extract our challenge details
|
||||
if ($this->error == '') {
|
||||
$this->name = $info['Name'];
|
||||
$this->uid = $info['UId'];
|
||||
$this->filename = $info['FileName'];
|
||||
$this->author = $info['Author'];
|
||||
$this->envir = $info['Environnement'];
|
||||
$this->mood = $info['Mood'];
|
||||
$this->bronzetm = $info['BronzeTime'];
|
||||
$this->silvertm = $info['SilverTime'];
|
||||
$this->goldtm = $info['GoldTime'];
|
||||
$this->authortm = $info['AuthorTime'];
|
||||
$this->coppers = $info['CopperPrice'];
|
||||
$this->laprace = $info['LapRace'];
|
||||
$this->nblaps = $info['NbLaps'];
|
||||
$this->nbcps = $info['NbCheckpoints'];
|
||||
$this->nbrcps = $info['NbCheckpoints'];
|
||||
|
||||
if ($this->laprace && $this->nblaps > 1)
|
||||
$this->nbrcps *= $this->nblaps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if challenge wasn't already there
|
||||
if (!$already) {
|
||||
// remove the challenge
|
||||
if (!$client->query('RemoveChallenge', $filename)) {
|
||||
$this->error = 'RemoveChallenge failed - Error ' . $client->getErrorCode() . ': ' . $client->getErrorMessage();
|
||||
}
|
||||
// switch away from our challenge
|
||||
sleep(5);
|
||||
if (!$client->query('NextChallenge')) {
|
||||
$this->error = 'NextChallenge 2 failed - Error ' . $client->getErrorCode() . ': ' . $client->getErrorMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$client->Terminate();
|
||||
}
|
||||
}
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* Jfreu's plugin 0.13d
|
||||
* Configuration settings.
|
||||
* This file is included by jfreu.plugin.php or jfreu.lite.php, so don't
|
||||
* list it in plugins.xml!
|
||||
* Updated by Xymph
|
||||
*/
|
||||
|
||||
//-> paths to config, vip/vip_team & bans files
|
||||
$conf_file = 'plugins/jfreu/jfreu.config.xml';
|
||||
$vips_file = 'plugins/jfreu/jfreu.vips.xml';
|
||||
$bans_file = 'plugins/jfreu/jfreu.bans.xml';
|
||||
|
||||
//-> Server's base name: (ex: '$000Jfreu')
|
||||
// Max. length: 26 chars (incl. colors & tags, and optional "TopXXX")
|
||||
$servername = 'YOUR SERVER NAME';
|
||||
//-> Word between the servername and the limit (usually " Top")
|
||||
$top = ' $449TOP';
|
||||
//-> Change the servername when the limit changes: "Servername TopXXX" (0 = OFF, 1 = ON)
|
||||
$autochangename = 0;
|
||||
|
||||
//-> ranklimit: ranklimiting default state (0 = OFF, 1 = ON)
|
||||
$ranklimit = 0;
|
||||
|
||||
//-> limit: ranklimit default value (when autorank is OFF)
|
||||
$limit = 500000;
|
||||
|
||||
//-> spec ranklimit
|
||||
$hardlimit = 1000000;
|
||||
|
||||
//-> autorank: autorank default state (0 = OFF, 1 = ON)
|
||||
$autorank = 0;
|
||||
|
||||
//-> offset (average + offset = Auto-RankLimit)
|
||||
$offset = 999;
|
||||
|
||||
//-> autorankminplayers (autorank disabled when not enough players)
|
||||
$autorankminplayers = 10;
|
||||
//-> autorankvip: include VIP/unSpec in autorank calculation (0 = OFF, 1 = ON)
|
||||
$autorankvip = 0;
|
||||
|
||||
//-> kick hirank when server is full and new player arrives (0 = OFF, 1 = ON)
|
||||
$kickhirank = 0;
|
||||
//-> maxplayers value for kickhirank (must be less than server's <max_players>)
|
||||
$maxplayers = 20;
|
||||
|
||||
//-> allow user /unspec vote (0 = OFF, 1 = ON)
|
||||
$unspecvote = 1;
|
||||
|
||||
//-> player join/leave messages
|
||||
$player_join = '{#server}>> {1}: {#highlite}{2}$z$s{#message} Nation: {#highlite}{3}{#message} Ladder: {#highlite}{4}';
|
||||
$player_joins = '{#server}>> {1}: {#highlite}{2}$z$s{#message} Nation: {#highlite}{3}{#message} Ladder: {#highlite}{4}{#message} Server: {#highlite}{5}';
|
||||
$player_left = '{#server}>> {#highlite}{1}$z$s{#message} has left the game. Played: {#highlite}{2}';
|
||||
|
||||
//-> random info messages at the end of the race (0 = OFF, 1 = in chat, 2 = in TMF message window)
|
||||
$infomessages = 1;
|
||||
//-> prefix for info messages
|
||||
$message_start = '$z$s$ff0>> [$f00INFO$ff0] $fff';
|
||||
|
||||
//-> random information messages (if you add a message don't forget to change the number) (999 messages max :-P)
|
||||
// $message1 = 'Jfreu\'s plugin: "http://reload.servegame.com/plugin/"';
|
||||
$message1 = 'Information about and download of this XASECO on ' . XASECO_TMN;
|
||||
$message2 = 'Use "/list" -> "/jukebox ##" to add a track in the jukebox.';
|
||||
$message3 = 'Please don\'t sound your horn throughout the entire track.';
|
||||
$message4 = 'When going AFK, please set your car to Spectator mode.';
|
||||
$message5 = 'Don\'t use Enter to skip intros - instead use Space & Enter';
|
||||
$message6 = 'For player & server info use the "/stats" and "/server" commands.';
|
||||
$message7 = 'Looking for the name of this server? Use the "/server" command.';
|
||||
$message8 = 'Use "/list nofinish" to find tracks you haven\'t completed yet, then /jukebox them!';
|
||||
$message9 = 'Use "/list norank" to find tracks you aren\'t ranked on, then /jukebox them!';
|
||||
$message10 = 'Can you beat the Gold time on all tracks? Use "/list nogold" to find out!';
|
||||
$message11 = 'Can you beat the Author time on all tracks? Use "/list noauthor" to find out!';
|
||||
$message12 = 'Wondering which tracks you haven\'t played recently? Use "/list norecent" to find out!';
|
||||
$message13 = 'Use the "/best" & "/worst" commands to find your best and worst records!';
|
||||
$message14 = 'Use the "/clans" & "/topclans" commands to see clan members and ranks!';
|
||||
$message15 = 'Use the "/ranks" commands to see the server ranks of all online players!';
|
||||
$message16 = 'Who is the most victorious player? Use "/topwins" to find out!';
|
||||
$message17 = 'Who has the most ranked records? Use "/toprecs" to find out!';
|
||||
$message18 = 'Wondering what tracks were played recently? Use the "/history" command.';
|
||||
$message19 = 'Looking for the next better ranked record to beat? Use "/nextrec"!';
|
||||
$message20 = 'Find the difference between your personal best and the track record with the "/diffrec" command!';
|
||||
$message21 = 'Check how many records were driven on the current track with the "/newrecs" command!';
|
||||
$message22 = 'Check how many records, and the 3 best ones, you have with the "/summary" command!';
|
||||
$message23 = 'Who has the most top-3 ranked records? Use "/topsums" to find out!';
|
||||
$message24 = 'Jukeboxed the wrong track? Use "/jukebox drop" to remove it!';
|
||||
$message25 = 'Forgot what someone said? Use "/chatlog" to check the chat history!';
|
||||
$message26 = 'Forgot what someone pm-ed you? Use "/pmlog" to check your PM history!';
|
||||
$message27 = 'Looking for the next better ranked player to beat? Use "/nextrank"!';
|
||||
$message28 = 'Use "/list newest <#>" to find the newest tracks added to the server, then /jukebox them!';
|
||||
$message29 = 'Find the longest and shortest tracks with the "/list longest / shortest" commands!';
|
||||
$message30 = 'Use "/mute" and "/unmute" to mute / unmute other players, and "/mutelist" to list them!';
|
||||
$message31 = 'Wondering when a player was last online? Use "/laston <login>" to find out!';
|
||||
$message32 = 'Looking for any player\'s world stats? Use the "/statsall <login>" command!';
|
||||
$message33 = 'Use checkpoints tracking in Rounds/Team/Cup modes with the "/cps" command!';
|
||||
$message34 = 'Find the TMX info & records for a track with the "/tmxinfo" & "/tmxrecs" commands!';
|
||||
$message35 = 'Looking for the name of the current track\'s song? Use the "/song" command!';
|
||||
$message36 = 'Looking for the name of the current track\'s mod? Use the "/mod" command!';
|
||||
$message37 = 'Use the "/style" command to select your personal window style!';
|
||||
$message38 = 'Use the "/recpanel" command to select your personal records panel!';
|
||||
$message39 = 'Use the "/votepanel" command to select your personal vote panel!';
|
||||
$message40 = 'Find out all about the Dedimania world records system with "/helpdedi"!';
|
||||
$message41 = 'Check out the XASECO[2] site at ' . XASECO_ORG . ' !';
|
||||
global $feature_votes;
|
||||
if ($feature_votes) {
|
||||
$message42 = 'Find out all about the chat-based voting commands with "/helpvote"!';
|
||||
}
|
||||
if (function_exists('send_window_message')) {
|
||||
$message43 = 'Missed a system message? Use "/msglog" to check the message history!';
|
||||
}
|
||||
|
||||
//-> Badwords checking (0 = OFF, 1 = ON)
|
||||
$badwords = 0;
|
||||
//-> Badwords banning (0 = OFF, 1 = ON)
|
||||
$badwordsban = 0;
|
||||
//-> Number of badwords allowed
|
||||
$badwordsnum = 3;
|
||||
//-> Banning period (minutes)
|
||||
$badwordstime = 10;
|
||||
|
||||
//-> Badwords to check for
|
||||
$badwordslist = array(
|
||||
'putain','ptain','klote','kIote','kanker','kenker',
|
||||
'arschl','wichs','fick','fikk','salop','siktirgit','gvd',
|
||||
'hitler','nutte','dick','cock','faitchier','bordel','shit',
|
||||
'encul','sucks','a.q','conerie','scheise','scheiße','scheis',
|
||||
'baskasole','cocugu','kodugumun','cazo','hoer','bitch',
|
||||
'penis','fotze','maul','frese','pizda','gay','fuck','tyfus',
|
||||
'sugi','cacat','pisat','labagiu','gaozar','muist','orospu',
|
||||
'pédé','cunt','godve','godfe','kut','kudt','lul','iui');
|
||||
|
||||
//-> novote (auto-cancel votes) (0 = OFF, 1 = ON)
|
||||
$novote = 0;
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* Ogg_Comments - Extract comments (ID3 tags) from .ogg files
|
||||
* Created by Xymph <tm@gamers.org>
|
||||
* Derived from Ogg.class.php v1.3e by Nicolas Ricquemaque <f1iqf@hotmail.com>
|
||||
* For more info see: http://opensource.grisambre.net/ogg/
|
||||
* Ogg format: http://en.wikipedia.org/wiki/Ogg
|
||||
* Comments : http://www.xiph.org/vorbis/doc/v-comment.html
|
||||
*
|
||||
* v1.1: Improved get_1block URL parsing; added User-Agent to the GET request
|
||||
* v1.0: Initial release
|
||||
*/
|
||||
|
||||
define('BLOCKSIZE', 512);
|
||||
|
||||
class Ogg_Comments {
|
||||
|
||||
public $comments = array();
|
||||
|
||||
/**
|
||||
* Fetches all comments from a .ogg local file or URL
|
||||
*
|
||||
* @param String $path
|
||||
* The .ogg file or URL
|
||||
* @param Boolean $utf8
|
||||
* If true, return fields in UTF-8, otherwise in ASCII/ISO-8859-1
|
||||
* @return Ogg_Comments
|
||||
* If $comments is empty, no .ogg file
|
||||
*/
|
||||
public function Ogg_Comments($path, $utf8 = false) {
|
||||
|
||||
// check for local file or URL
|
||||
if (strpos($path, '://') === false) {
|
||||
if (!$fp = @fopen($path, 'rb'))
|
||||
return false;
|
||||
$file = fread($fp, BLOCKSIZE);
|
||||
fclose($fp);
|
||||
if ($file === false)
|
||||
return false;
|
||||
} else {
|
||||
$file = $this->get_1block($path);
|
||||
if ($file === false || $file == -1)
|
||||
return false;
|
||||
}
|
||||
|
||||
// read OGG pages
|
||||
for ($pos = 0; ($pos = strpos($file, 'OggS', $pos)) !== false; $pos++) {
|
||||
// check stream version
|
||||
if (ord($file[$pos+4]) != 0)
|
||||
continue;
|
||||
|
||||
// compute offset of packet after header
|
||||
$offset = $pos + 27 + ord($file[$pos+26]);
|
||||
// check for second (== comments) packet
|
||||
if ($this->read_intle($file, $pos+18) == 1) {
|
||||
// check for vorbis comments
|
||||
if (ord($file[$offset]) != 0x03 ||
|
||||
substr($file, $offset+1, 6) != 'vorbis')
|
||||
continue;
|
||||
|
||||
// read vendor string
|
||||
$offset += 7;
|
||||
$vndlen = $this->read_intle($file, $offset);
|
||||
$this->comments['VENDOR'] = $this->decode_field(substr($file, $offset+4, $vndlen), $utf8);
|
||||
// read comments count
|
||||
$offset += 4 + $vndlen;
|
||||
$cmtcnt = $this->read_intle($file, $offset);
|
||||
|
||||
// read/parse all comment fields
|
||||
$offset += 4;
|
||||
for ($i = 0; $i < $cmtcnt; $i++) {
|
||||
$cmtlen = $this->read_intle($file, $offset);
|
||||
$comment = substr($file, $offset+4, $cmtlen);
|
||||
$offset += 4 + $cmtlen;
|
||||
// store field name=value pair
|
||||
$comment = explode('=', $comment, 2);
|
||||
// check for repeated field & append
|
||||
if (isset($this->comments[strtoupper($comment[0])]))
|
||||
$this->comments[strtoupper($comment[0])] .= ', ' . $this->decode_field($comment[1], $utf8);
|
||||
else
|
||||
$this->comments[strtoupper($comment[0])] = $this->decode_field($comment[1], $utf8);
|
||||
}
|
||||
}
|
||||
// check whether done
|
||||
if (isset($this->comments['VENDOR']))
|
||||
break;
|
||||
}
|
||||
} // Ogg_Comments
|
||||
|
||||
// Read 32-bits Little Endian integer
|
||||
private function read_intle(&$buf, $pos) {
|
||||
|
||||
return (ord($buf[$pos+0]) + (ord($buf[$pos+1]) << 8) +
|
||||
(ord($buf[$pos+2]) << 16) + (ord($buf[$pos+3]) << 24));
|
||||
} // read_intle
|
||||
|
||||
// Decode comment field into specified charset
|
||||
private function decode_field($str, $utf8) {
|
||||
|
||||
if ($utf8)
|
||||
// return UTF8 or encode it in UTF8
|
||||
return ((utf8_encode(utf8_decode($str)) == $str) ?
|
||||
$str : utf8_encode($str));
|
||||
else
|
||||
// decode it to ASCII or return ASCII
|
||||
return ((utf8_encode(utf8_decode($str)) == $str) ?
|
||||
utf8_decode($str) : $str);
|
||||
} // decode_field
|
||||
|
||||
// Simple HTTP Get 1 Block function with timeout
|
||||
// ok: return string || error: return false || timeout: return -1
|
||||
private function get_1block($url) {
|
||||
|
||||
$url = parse_url($url);
|
||||
$port = isset($url['port']) ? $url['port'] : 80;
|
||||
$query = isset($url['query']) ? '?' . $url['query'] : '';
|
||||
|
||||
$fp = @fsockopen($url['host'], $port, $errno, $errstr, 4);
|
||||
if (!$fp)
|
||||
return false;
|
||||
|
||||
$uri = '';
|
||||
foreach (explode('/', $url['path']) as $subpath)
|
||||
$uri .= rawurlencode($subpath) . '/';
|
||||
$uri = substr($uri, 0, strlen($uri)-1); // strip trailing '/'
|
||||
|
||||
fwrite($fp, 'GET ' . $uri . $query . " HTTP/1.0\r\n" .
|
||||
'Host: ' . $url['host'] . "\r\n" .
|
||||
'User-Agent: Ogg_Comments (' . PHP_OS . ")\r\n\r\n");
|
||||
stream_set_timeout($fp, 2);
|
||||
$res = '';
|
||||
$info['timed_out'] = false;
|
||||
for ($i = 0; $i < 2; $i++)
|
||||
if (feof($fp) || $info['timed_out']) {
|
||||
break;
|
||||
} else {
|
||||
$res .= fread($fp, BLOCKSIZE);
|
||||
$info = stream_get_meta_data($fp);
|
||||
}
|
||||
fclose($fp);
|
||||
|
||||
if ($info['timed_out']) {
|
||||
return -1;
|
||||
} else {
|
||||
if (substr($res, 9, 3) != '200')
|
||||
return false;
|
||||
$page = explode("\r\n\r\n", $res, 2);
|
||||
return trim($page[1]);
|
||||
}
|
||||
} // get_1block
|
||||
} // class Ogg_Comments
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,290 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* TMNDataFetcher - Fetch TMN ladder/nation/server stats for a login
|
||||
* Created by (OoR-F)~fuckfish (fish@stabb.de)
|
||||
* Updated by Xymph <tm@gamers.org>
|
||||
*
|
||||
* v1.8: Improved error reporting via $error; fixed file check in extendedInfo
|
||||
* processing; added magic __set_state function to support var_export()
|
||||
* v1.7: Improve handling of empty API responses
|
||||
* v1.6: Fixed $teamrank type into int; added User-Agent to the GET request
|
||||
* v1.5: Tweaked initial get_file return value check
|
||||
* v1.4: Fixed get_file return value checks; fixed $nationrank check
|
||||
* v1.3: Optimized get_file URL parsing
|
||||
* v1.2: Added get_file function to handle master server timeouts
|
||||
* v1.1: General code cleanup; added more comments; added $lastmatch,
|
||||
* $totalplayers, $nationplayers, $nationpos, $nationpoints,
|
||||
* $totalnations, $servernick, $serverdesc, $servernation;
|
||||
* renamed $actualserver to $serverlogin
|
||||
* v1.0: Initial release
|
||||
*/
|
||||
class TMNDataFetcher {
|
||||
|
||||
public $version, $extended, $error,
|
||||
$login, $nickname, $worldrank, $totalplayers,
|
||||
$points, $lastmatch, $wins, $losses, $draws,
|
||||
$stars, $stardays, $teamname, $teamrank, $totalteams,
|
||||
$nation, $nationrank, $nationplayers,
|
||||
$nationpos, $nationpoints, $totalnations,
|
||||
$online, $serverlogin, $servernick, $serverdesc, $servernation;
|
||||
|
||||
/**
|
||||
* Fetches a hell of a lot of data about a TMN login
|
||||
*
|
||||
* @param String $login
|
||||
* The TMN login to search for
|
||||
* @param Boolean $extendedInfo
|
||||
* If true, the script also searches for the server that the
|
||||
* player is on at the moment (also determines online-state)
|
||||
* @return TMNDataFetcher
|
||||
* If $nickname is empty, login was not found
|
||||
*/
|
||||
function TMNDataFetcher($login, $extendedInfo) {
|
||||
|
||||
$this->version = '0.1.7.9';
|
||||
$this->error = '';
|
||||
$this->extended = $extendedInfo;
|
||||
$this->login = strtolower($login);
|
||||
$this->getData();
|
||||
} // TMNDataFetcher
|
||||
|
||||
public static function __set_state($import) {
|
||||
|
||||
$tmn = new TMNDataFetcher('', true);
|
||||
|
||||
$tmn->version = $import['version'];
|
||||
$tmn->extended = $import['extended'];
|
||||
$tmn->error = '';
|
||||
$tmn->login = $import['login'];
|
||||
$tmn->nickname = $import['nickname'];
|
||||
$tmn->worldrank = $import['worldrank'];
|
||||
$tmn->totalplayers = $import['totalplayers'];
|
||||
$tmn->points = $import['points'];
|
||||
$tmn->lastmatch = $import['lastmatch'];
|
||||
$tmn->wins = $import['wins'];
|
||||
$tmn->losses = $import['losses'];
|
||||
$tmn->draws = $import['draws'];
|
||||
$tmn->stars = $import['stars'];
|
||||
$tmn->stardays = $import['stardays'];
|
||||
$tmn->teamname = $import['teamname'];
|
||||
$tmn->teamrank = $import['teamrank'];
|
||||
$tmn->totalteams = $import['totalteams'];
|
||||
$tmn->nation = $import['nation'];
|
||||
$tmn->nationrank = $import['nationrank'];
|
||||
$tmn->nationplayers = $import['nationplayers'];
|
||||
$tmn->nationpos = $import['nationpos'];
|
||||
$tmn->nationpoints = $import['nationpoints'];
|
||||
$tmn->totalnations = $import['totalnations'];
|
||||
$tmn->online = $import['online'];
|
||||
$tmn->serverlogin = $import['serverlogin'];
|
||||
$tmn->servernick = $import['servernick'];
|
||||
$tmn->serverdesc = $import['serverdesc'];
|
||||
$tmn->servernation = $import['servernation'];
|
||||
|
||||
return $tmn;
|
||||
} // __set_state
|
||||
|
||||
private function getData() {
|
||||
|
||||
$url = 'http://game.trackmanianations.com/online_game/getplayerinfos.php?ver=' . $this->version . '&lang=en&login=' . $this->login;
|
||||
$line = $this->get_file($url);
|
||||
if ($line === false) {
|
||||
$this->error = 'Connection or response error on ' . $url;
|
||||
return;
|
||||
} else if ($line === -1) {
|
||||
$this->error = 'Timed out while reading data from ' . $url;
|
||||
return;
|
||||
} else if ($line == '' || strpos($line, '<br>') !== false) {
|
||||
$this->error = 'No data returned from ' . $url;
|
||||
return;
|
||||
}
|
||||
|
||||
$array = explode(';', $line);
|
||||
if (!isset($array[6])) {
|
||||
$this->error = 'Cannot parse data returned data from ' . $url;
|
||||
return;
|
||||
}
|
||||
// 0 = $array[0];
|
||||
// login = $array[1];
|
||||
$this->nickname = urldecode($array[2]);
|
||||
$this->nation = $array[3];
|
||||
// empty = $array[4];
|
||||
$this->stars = $array[5];
|
||||
$this->stardays = $array[6];
|
||||
|
||||
$url = 'http://ladder.trackmanianations.com/ladder/getstats.php?ver=' . $this->version . '&laddertype=g&login=' . $this->login;
|
||||
$line = $this->get_file($url);
|
||||
if ($line === false) {
|
||||
$this->error = 'Connection or response error on ' . $url;
|
||||
return;
|
||||
} else if ($line === -1) {
|
||||
$this->error = 'Timed out while reading data from ' . $url;
|
||||
return;
|
||||
} else if ($line == '' || strpos($line, '<br>') !== false) {
|
||||
$this->error = 'No data returned from ' . $url;
|
||||
return;
|
||||
}
|
||||
|
||||
$array = explode(';', $line);
|
||||
if (!isset($array[10])) {
|
||||
$this->error = 'Cannot parse data returned data from ' . $url;
|
||||
return;
|
||||
}
|
||||
// 0 = $array[0];
|
||||
$this->totalplayers = $array[1];
|
||||
$this->wins = $array[2];
|
||||
$this->losses = $array[3];
|
||||
$this->draws = $array[4];
|
||||
$this->worldrank = $array[5];
|
||||
$this->points = $array[6];
|
||||
$this->lastmatch = $array[7];
|
||||
$this->teamname = urldecode($array[8]);
|
||||
$this->teamrank = (int)$array[9];
|
||||
$this->totalteams = $array[10];
|
||||
|
||||
$url = 'http://ladder.trackmanianations.com/ladder/getstats.php?ver=' . $this->version . '&laddertype=g&login=' . $this->login . '&country=' . $this->nation;
|
||||
$line = $this->get_file($url);
|
||||
if ($line === false) {
|
||||
$this->error = 'Connection or response error on ' . $url;
|
||||
return;
|
||||
} else if ($line === -1) {
|
||||
$this->error = 'Timed out while reading data from ' . $url;
|
||||
return;
|
||||
} else if ($line == '' || strpos($line, '<br>') !== false) {
|
||||
$this->error = 'No data returned from ' . $url;
|
||||
return;
|
||||
}
|
||||
|
||||
$array = explode(';', $line);
|
||||
// 0 = $array[1];
|
||||
if (isset($array[5]))
|
||||
$this->nationrank = $array[5];
|
||||
else
|
||||
$this->nationrank = '';
|
||||
// the remaining fields are the same as the world stats above
|
||||
|
||||
$url = 'http://ladder.trackmanianations.com/ladder/getrankings.php?ver=' . $this->version . '&laddertype=g&start=0&limit=0&country=' . $this->nation;
|
||||
$line = $this->get_file($url);
|
||||
if ($line === false) {
|
||||
$this->error = 'Connection or response error on ' . $url;
|
||||
return;
|
||||
} else if ($line === -1) {
|
||||
$this->error = 'Timed out while reading data from ' . $url;
|
||||
return;
|
||||
} else if ($line == '' || strpos($line, '<br>') !== false) {
|
||||
$this->error = 'No data returned from ' . $url;
|
||||
return;
|
||||
}
|
||||
|
||||
$array = explode(';', $line);
|
||||
if (!isset($array[1])) {
|
||||
$this->error = 'Cannot parse data returned data from ' . $url;
|
||||
return;
|
||||
}
|
||||
// 0 = $array[1];
|
||||
$this->nationplayers = $array[1];
|
||||
// 1;login;nickname;nation;points = $array[2-6];
|
||||
// 2;login;nickname;nation;points = $array[7-11]; etc.etc.
|
||||
|
||||
$url = 'http://ladder.trackmanianations.com/ladder/getcountriesrankings.php?ver=' . $this->version . '&laddertype=g&lang=en&start=0&limit=100';
|
||||
$line = $this->get_file($url);
|
||||
if ($line === false) {
|
||||
$this->error = 'Connection or response error on ' . $url;
|
||||
return;
|
||||
} else if ($line === -1) {
|
||||
$this->error = 'Timed out while reading data from ' . $url;
|
||||
return;
|
||||
} else if ($line == '' || strpos($line, '<br>') !== false) {
|
||||
$this->error = 'No data returned from ' . $url;
|
||||
return;
|
||||
}
|
||||
|
||||
$array = explode(';', $line);
|
||||
if (!isset($array[1])) {
|
||||
$this->error = 'Cannot parse data returned data from ' . $url;
|
||||
return;
|
||||
}
|
||||
// 0 = $array[1];
|
||||
$this->totalnations = $array[1];
|
||||
// 1;nation;points = $array[2-4];
|
||||
// 2;nation;points = $array[5-7]; etc.etc.
|
||||
$i = 2;
|
||||
while (isset($array[$i]) && $array[$i] != '') {
|
||||
if ($array[$i+1] == $this->nation) {
|
||||
$this->nationpos = $array[$i];
|
||||
$this->nationpoints = $array[$i+2];
|
||||
break;
|
||||
}
|
||||
$i += 3;
|
||||
}
|
||||
|
||||
$this->online = false;
|
||||
// check online status too?
|
||||
if ($this->extended) {
|
||||
$page = $this->get_file('http://game.trackmanianations.com/online_game/www_serverslist.php');
|
||||
if ($page === false || $page == -1 || $page == '')
|
||||
// no error message if main info was already fetched
|
||||
return;
|
||||
|
||||
$lines = explode('<host>', $page);
|
||||
foreach ($lines as $line) {
|
||||
if (stripos($line, '<player>' . $this->login . '</player>') !== false) {
|
||||
$this->online = true;
|
||||
$this->serverlogin = substr($line, 0, strpos($line, '</host>'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->online) {
|
||||
$page = $this->get_file('http://game.trackmanianations.com/online_game/browse_top.php?ver=0.1.7.9&lang=en&key=XXXX-XXXX-XXXX-XXXX-XXX&nb=100&page=1&flatall=1');
|
||||
if ($page === false || $page == -1 || $page == '')
|
||||
// no error message if main info was already fetched
|
||||
return;
|
||||
|
||||
$server = $this->serverlogin; // can't use object member inside pattern
|
||||
if (preg_match("/^${server};([^;]+);([^;]+);([A-Z]+);/m", $page, $fields)) {
|
||||
$this->serverdesc = $fields[1];
|
||||
$this->servernick = ($fields[2] != 'x' ? urldecode($fields[2]) : '');
|
||||
$this->servernation = $fields[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
} // getData
|
||||
|
||||
// Simple HTTP Get function with timeout
|
||||
// ok: return string || error: return false || timeout: return -1
|
||||
private function get_file($url) {
|
||||
|
||||
$url = parse_url($url);
|
||||
$port = isset($url['port']) ? $url['port'] : 80;
|
||||
$query = isset($url['query']) ? "?" . $url['query'] : "";
|
||||
|
||||
$fp = @fsockopen($url['host'], $port, $errno, $errstr, 4);
|
||||
if (!$fp)
|
||||
return false;
|
||||
|
||||
fwrite($fp, 'GET ' . $url['path'] . $query . " HTTP/1.0\r\n" .
|
||||
'Host: ' . $url['host'] . "\r\n" .
|
||||
'User-Agent: TMNDataFetcher (' . PHP_OS . ")\r\n\r\n");
|
||||
stream_set_timeout($fp, 2);
|
||||
$res = '';
|
||||
$info['timed_out'] = false;
|
||||
while (!feof($fp) && !$info['timed_out']) {
|
||||
$res .= fread($fp, 512);
|
||||
$info = stream_get_meta_data($fp);
|
||||
}
|
||||
fclose($fp);
|
||||
|
||||
if ($info['timed_out']) {
|
||||
return -1;
|
||||
} else {
|
||||
if (substr($res, 9, 3) != '200')
|
||||
return false;
|
||||
$page = explode("\r\n\r\n", $res, 2);
|
||||
return trim($page[1]);
|
||||
}
|
||||
} // get_file
|
||||
} // class TMNDataFetcher
|
||||
?>
|
|
@ -0,0 +1,297 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* TMXInfoFetcher - Fetch TMX info/records for TMO/TMS/TMN/TMU(F)/TMNF tracks
|
||||
* Created by Xymph <tm@gamers.org>
|
||||
* Inspired by TMNDataFetcher & "Stats for TMN Aseco+RASP"
|
||||
*
|
||||
* v1.19: Allowed 24-char UIDs too
|
||||
* v1.18: Added 'replayurl' to the entries in $recordslist
|
||||
* v1.17: Allowed 25-char UIDs too
|
||||
* v1.16: Improved error reporting via $error; parsed more comment formatting
|
||||
* v1.15: Added User-Agent to the GET request
|
||||
* v1.14: Fixed PHP Strict level warning
|
||||
* v1.13: Fixed handling of empty API responses
|
||||
* v1.12: Renamed $worldrec into $custimg to correct its meaning; fixed
|
||||
* $replayid check
|
||||
* v1.11: Added another check for valid $replayid
|
||||
* v1.10: Added magic __set_state function to support var_export()
|
||||
* v1.9: Fixed fetch records run-time warnings
|
||||
* v1.8: Optimized get_file URL parsing
|
||||
* v1.7: Added $worldrec (boolean); changed $visible to boolean; renamed
|
||||
* $download to $dloadurl, $imgurl to $imageurl & $imgurlsmall to
|
||||
* $thumburl; minor tweaks
|
||||
* v1.6: Added check for valid $replayid & $replayurl
|
||||
* v1.5: Added TMNF compatibility
|
||||
* v1.4: Added get_file function to handle TMX site timeouts
|
||||
* v1.3: Added $awards, $comments, $replayid, $replayurl; renamed $comment to
|
||||
* $acomment (to better distinguish author comment from # of comments)
|
||||
* v1.2: Allowed 26-char UIDs too; added $pageurl
|
||||
* v1.1: Allowed TMX IDs too
|
||||
* v1.0: Initial release
|
||||
*/
|
||||
class TMXInfoFetcher {
|
||||
|
||||
public $section, $prefix, $uid, $id, $records, $error,
|
||||
$name, $userid, $author, $uploaded, $updated,
|
||||
$visible, $type, $envir, $mood, $style, $routes,
|
||||
$length, $diffic, $lbrating, $awards, $comments, $custimg,
|
||||
$game, $acomment, $pageurl, $replayid, $replayurl,
|
||||
$imageurl, $thumburl, $dloadurl, $recordlist;
|
||||
|
||||
/**
|
||||
* Fetches a hell of a lot of data about a TMX track
|
||||
*
|
||||
* @param String $game
|
||||
* TMX section for 'TMO', 'TMS', 'TMN', 'TMU', 'TMNF'
|
||||
* @param String $id
|
||||
* The challenge UID to search for (if a 24-27 char alphanum string),
|
||||
* otherwise the TMX ID to search for (if a number)
|
||||
* @param Boolean $records
|
||||
* If true, the script also returns the world records (max. 10)
|
||||
* @return TMXInfoFetcher
|
||||
* If $error is not an empty string, it's an error message
|
||||
*/
|
||||
public function TMXInfoFetcher($game, $id, $records) {
|
||||
|
||||
$this->section = $game;
|
||||
switch ($game) {
|
||||
case 'TMO':
|
||||
$this->prefix = 'original';
|
||||
break;
|
||||
case 'TMS':
|
||||
$this->prefix = 'sunrise';
|
||||
break;
|
||||
case 'TMN':
|
||||
$this->prefix = 'nations';
|
||||
break;
|
||||
case 'TMU':
|
||||
$this->prefix = 'united';
|
||||
break;
|
||||
case 'TMNF':
|
||||
$this->prefix = 'tmnforever';
|
||||
break;
|
||||
default:
|
||||
$this->prefix = '';
|
||||
return;
|
||||
}
|
||||
|
||||
$this->error = '';
|
||||
$this->records = $records;
|
||||
// check for UID string
|
||||
if (preg_match('/^\w{24,27}$/', $id)) {
|
||||
$this->uid = $id;
|
||||
$this->getData(true);
|
||||
// check for TMX ID
|
||||
} elseif (is_numeric($id) && $id > 0) {
|
||||
$this->id = floor($id);
|
||||
$this->getData(false);
|
||||
}
|
||||
} // TMXInfoFetcher
|
||||
|
||||
public static function __set_state($import) {
|
||||
|
||||
$tmx = new TMXInfoFetcher('', 0, false);
|
||||
|
||||
$tmx->section = $import['section'];
|
||||
$tmx->prefix = $import['prefix'];
|
||||
$tmx->uid = $import['uid'];
|
||||
$tmx->id = $import['id'];
|
||||
$tmx->records = $import['records'];
|
||||
$tmx->error = '';
|
||||
$tmx->name = $import['name'];
|
||||
$tmx->userid = $import['userid'];
|
||||
$tmx->author = $import['author'];
|
||||
$tmx->uploaded = $import['uploaded'];
|
||||
$tmx->updated = $import['updated'];
|
||||
$tmx->visible = $import['visible'];
|
||||
$tmx->type = $import['type'];
|
||||
$tmx->envir = $import['envir'];
|
||||
$tmx->mood = $import['mood'];
|
||||
$tmx->style = $import['style'];
|
||||
$tmx->routes = $import['routes'];
|
||||
$tmx->length = $import['length'];
|
||||
$tmx->diffic = $import['diffic'];
|
||||
$tmx->lbrating = $import['lbrating'];
|
||||
$tmx->awards = $import['awards'];
|
||||
$tmx->comments = $import['comments'];
|
||||
$tmx->custimg = $import['custimg'];
|
||||
$tmx->game = $import['game'];
|
||||
$tmx->acomment = $import['acomment'];
|
||||
$tmx->pageurl = $import['pageurl'];
|
||||
$tmx->replayid = $import['replayid'];
|
||||
$tmx->replayurl = $import['replayurl'];
|
||||
$tmx->imageurl = $import['imageurl'];
|
||||
$tmx->thumburl = $import['thumburl'];
|
||||
$tmx->dloadurl = $import['dloadurl'];
|
||||
$tmx->recordlist = null;
|
||||
|
||||
return $tmx;
|
||||
} // __set_state
|
||||
|
||||
private function getData($isuid) {
|
||||
|
||||
// get main track info
|
||||
$url = 'http://' . $this->prefix . '.tm-exchange.com/apiget.aspx?action=apitrackinfo&' . ($isuid ? 'u' : '') . 'id=' . ($isuid ? $this->uid : $this->id);
|
||||
$file = $this->get_file($url);
|
||||
if ($file === false) {
|
||||
$this->error = 'Connection or response error on ' . $url;
|
||||
return;
|
||||
} else if ($file === -1) {
|
||||
$this->error = 'Timed out while reading data from ' . $url;
|
||||
return;
|
||||
} else if ($file == '') {
|
||||
$this->error = 'No data returned from ' . $url;
|
||||
return;
|
||||
}
|
||||
|
||||
// check for API error message
|
||||
if (strpos($file, chr(27)) !== false) {
|
||||
$this->error = 'Cannot decode main track info';
|
||||
return;
|
||||
}
|
||||
|
||||
// separate columns on Tabs
|
||||
$fields = explode(chr(9), $file);
|
||||
|
||||
if ($isuid)
|
||||
$this->id = $fields[0];
|
||||
|
||||
$this->name = $fields[1];
|
||||
$this->userid = $fields[2];
|
||||
$this->author = $fields[3];
|
||||
$this->uploaded = $fields[4];
|
||||
$this->updated = $fields[5];
|
||||
$this->visible = (strtolower($fields[6]) == 'true');
|
||||
$this->type = $fields[7];
|
||||
$this->envir = $fields[8];
|
||||
$this->mood = $fields[9];
|
||||
$this->style = $fields[10];
|
||||
$this->routes = $fields[11];
|
||||
$this->length = $fields[12];
|
||||
$this->diffic = $fields[13];
|
||||
$this->lbrating = ($fields[14] > 0 ? $fields[14] : 'Classic!');
|
||||
$this->game = $fields[15];
|
||||
|
||||
$search = array(chr(31), '[b]', '[/b]', '[i]', '[/i]', '[u]', '[/u]', '[url]', '[/url]');
|
||||
$replace = array('<br/>', '<b>', '</b>', '<i>', '</i>', '<u>', '</u>', '<i>', '</i>');
|
||||
$this->acomment = str_ireplace($search, $replace, $fields[16]);
|
||||
$this->acomment = preg_replace('/\[url=".*"\]/', '<i>', $this->acomment);
|
||||
|
||||
$this->pageurl = 'http://' . $this->prefix . '.tm-exchange.com/main.aspx?action=trackshow&id=' . $this->id;
|
||||
$this->imageurl = 'http://' . $this->prefix . '.tm-exchange.com/get.aspx?action=trackscreen&id=' . $this->id;
|
||||
$this->thumburl = 'http://' . $this->prefix . '.tm-exchange.com/get.aspx?action=trackscreensmall&id=' . $this->id;
|
||||
$this->dloadurl = 'http://' . $this->prefix . '.tm-exchange.com/get.aspx?action=trackgbx&id=' . $this->id;
|
||||
|
||||
$this->awards = 0;
|
||||
$this->comments = 0;
|
||||
$this->custimg = false;
|
||||
$this->replayid = 0;
|
||||
$this->replayurl = '';
|
||||
|
||||
// get misc. track info
|
||||
$url = 'http://' . $this->prefix . '.tm-exchange.com/apiget.aspx?action=apisearch&trackid=' . $this->id;
|
||||
$file = $this->get_file($url);
|
||||
if ($file === false || $file === -1 || $file == '')
|
||||
// no error message if main info was already fetched
|
||||
return;
|
||||
|
||||
// check for API error message
|
||||
if (strpos($file, chr(27)) !== false)
|
||||
return;
|
||||
|
||||
// separate columns on Tabs
|
||||
$fields = explode(chr(9), $file);
|
||||
|
||||
// id = $fields[0];
|
||||
// name = $fields[1];
|
||||
// userid = $fields[2];
|
||||
// author = $fields[3];
|
||||
// type = $fields[4];
|
||||
// envir = $fields[5];
|
||||
// mood = $fields[6];
|
||||
// style = $fields[7];
|
||||
// routes = $fields[8];
|
||||
// length = $fields[9];
|
||||
// diffic = $fields[10];
|
||||
// lbrating = ($fields[11] > 0 ? $fields[11] : 'Classic!');
|
||||
$this->awards = $fields[12];
|
||||
$this->comments = $fields[13];
|
||||
$this->custimg = (strtolower($fields[14]) == 'true');
|
||||
// game = $fields[15];
|
||||
$this->replayid = $fields[16];
|
||||
// unknown = $fields[17-21];
|
||||
// uploaded = $fields[22];
|
||||
// updated = $fields[23];
|
||||
|
||||
if ($this->replayid > 0) {
|
||||
$this->replayurl = 'http://' . $this->prefix . '.tm-exchange.com/get.aspx?action=recordgbx&id=' . $this->replayid;
|
||||
}
|
||||
|
||||
// fetch records too?
|
||||
$this->recordlist = array();
|
||||
if ($this->records) {
|
||||
$url = 'http://' . $this->prefix . '.tm-exchange.com/apiget.aspx?action=apitrackrecords&id=' . $this->id;
|
||||
$file = $this->get_file($url);
|
||||
if ($file === false || $file === -1 || $file == '')
|
||||
// no error message if main info was already fetched
|
||||
return;
|
||||
|
||||
$file = explode("\r\n", $file);
|
||||
$i = 0;
|
||||
while ($i < 10 && isset($file[$i]) && $file[$i] != '') {
|
||||
// separate columns on Tabs
|
||||
$fields = explode(chr(9), $file[$i]);
|
||||
$this->recordlist[$i++] = array(
|
||||
'replayid' => $fields[0],
|
||||
'userid' => $fields[1],
|
||||
'name' => $fields[2],
|
||||
'time' => $fields[3],
|
||||
'replayat' => $fields[4],
|
||||
'trackat' => $fields[5],
|
||||
'approved' => $fields[6],
|
||||
'score' => $fields[7],
|
||||
'expires' => $fields[8],
|
||||
'lockspan' => $fields[9],
|
||||
'replayurl'=> 'http://' . $this->prefix . '.tm-exchange.com/get.aspx?action=recordgbx&id=' . $fields[0],
|
||||
);
|
||||
}
|
||||
}
|
||||
} // getData
|
||||
|
||||
// Simple HTTP Get function with timeout
|
||||
// ok: return string || error: return false || timeout: return -1
|
||||
private function get_file($url) {
|
||||
|
||||
$url = parse_url($url);
|
||||
$port = isset($url['port']) ? $url['port'] : 80;
|
||||
$query = isset($url['query']) ? "?" . $url['query'] : "";
|
||||
|
||||
$fp = @fsockopen($url['host'], $port, $errno, $errstr, 4);
|
||||
if (!$fp)
|
||||
return false;
|
||||
|
||||
fwrite($fp, 'GET ' . $url['path'] . $query . " HTTP/1.0\r\n" .
|
||||
'Host: ' . $url['host'] . "\r\n" .
|
||||
'User-Agent: TMXInfoFetcher (' . PHP_OS . ")\r\n\r\n");
|
||||
stream_set_timeout($fp, 2);
|
||||
$res = '';
|
||||
$info['timed_out'] = false;
|
||||
while (!feof($fp) && !$info['timed_out']) {
|
||||
$res .= fread($fp, 512);
|
||||
$info = stream_get_meta_data($fp);
|
||||
}
|
||||
fclose($fp);
|
||||
|
||||
if ($info['timed_out']) {
|
||||
return -1;
|
||||
} else {
|
||||
if (substr($res, 9, 3) != '200')
|
||||
return false;
|
||||
$page = explode("\r\n\r\n", $res, 2);
|
||||
return trim($page[1]);
|
||||
}
|
||||
} // get_file
|
||||
} // class TMXInfoFetcher
|
||||
?>
|
|
@ -0,0 +1,288 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* TMXInfoSearcher - Search TMX info for TMO/TMS/TMN/TMU(F)/TMNF tracks
|
||||
* Created by Xymph <tm@gamers.org>
|
||||
* Based on TMXInfoFetcher & http://united.tm-exchange.com/main.aspx?action=threadshow&id=619302
|
||||
*
|
||||
* v1.7: Added Countable interface to searcher class
|
||||
* v1.6: Fixed an error checking bug
|
||||
* v1.5: Improved error reporting via $error
|
||||
* v1.4: Added User-Agent to the GET request
|
||||
* v1.3: Renamed $worldrec into $custimg to correct its meaning; fixed
|
||||
* $replayid check
|
||||
* v1.2: Fixed TMXInfo processing false $track
|
||||
* v1.1: Optimized get_file URL parsing
|
||||
* v1.0: Initial release
|
||||
*/
|
||||
class TMXInfoSearcher implements Iterator,Countable {
|
||||
|
||||
public $error;
|
||||
protected $tracks = array();
|
||||
private $section;
|
||||
private $prefix;
|
||||
|
||||
/**
|
||||
* Searches TMX for tracks matching name, author and/or environment;
|
||||
* or search TMX for the 10 most recent tracks
|
||||
*
|
||||
* @param String $game
|
||||
* TMX section for 'TMO', 'TMS', 'TMN', 'TMU', 'TMNF'
|
||||
* @param String $name
|
||||
* The track name to search for (partial, case-insensitive match)
|
||||
* @param String $author
|
||||
* The track author to search for (partial, case-insensitive match)
|
||||
* @param String $env
|
||||
* The environment to search for (exact case-insensitive match
|
||||
* from: Desert, Snow, Rally, Bay, Coast, Island, Stadium);
|
||||
* ignored when searching TMN or TMNF
|
||||
* @param Boolean $recent
|
||||
* If true, ignore search parameters and just return 10 newest tracks
|
||||
* (max. one per author)
|
||||
* @return TMXInfoSearcher
|
||||
* If ->valid() is false, no matching track was found;
|
||||
* otherwise, an iterator of TMXInfo objects for a 'foreach' loop.
|
||||
* Returns at most 500 tracks ($maxpage * 20) for TMNF/TMU(F),
|
||||
* and at most 20 tracks for the other TMX sections.
|
||||
*/
|
||||
public function __construct($game, $name, $author, $env, $recent) {
|
||||
|
||||
$this->section = $game;
|
||||
switch ($game) {
|
||||
case 'TMO':
|
||||
$this->prefix = 'original';
|
||||
break;
|
||||
case 'TMS':
|
||||
$this->prefix = 'sunrise';
|
||||
break;
|
||||
case 'TMN':
|
||||
$this->prefix = 'nations';
|
||||
$env = ''; // ignore possible environment
|
||||
break;
|
||||
case 'TMU':
|
||||
$this->prefix = 'united';
|
||||
break;
|
||||
case 'TMNF':
|
||||
$this->prefix = 'tmnforever';
|
||||
$env = ''; // ignore possible environment
|
||||
break;
|
||||
default:
|
||||
$this->prefix = '';
|
||||
$this->error = 'Unknown TMX section: ' . $game;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->error = '';
|
||||
if ($recent) {
|
||||
$this->tracks = $this->getRecent();
|
||||
} else {
|
||||
$this->tracks = $this->getList($name, $author, $env);
|
||||
}
|
||||
} // __construct
|
||||
|
||||
// define standard Iterator functions
|
||||
public function rewind() {
|
||||
reset($this->tracks);
|
||||
}
|
||||
public function current() {
|
||||
return new TMXInfo($this->section, $this->prefix, current($this->tracks));
|
||||
}
|
||||
public function next() {
|
||||
return new TMXInfo($this->section, $this->prefix, next($this->tracks));
|
||||
}
|
||||
public function key() {
|
||||
return key($this->tracks);
|
||||
}
|
||||
public function valid() {
|
||||
return (current($this->tracks) !== false);
|
||||
}
|
||||
// define standard Countable function
|
||||
public function count() {
|
||||
return count($this->tracks);
|
||||
}
|
||||
|
||||
private function getRecent() {
|
||||
|
||||
// get 10 most recent tracks
|
||||
$url = 'http://' . $this->prefix . '.tm-exchange.com/apiget.aspx?action=apirecent';
|
||||
$file = $this->get_file($url);
|
||||
if ($file === false) {
|
||||
$this->error = 'Connection or response error on ' . $url;
|
||||
return array();
|
||||
} else if ($file === -1) {
|
||||
$this->error = 'Timed out while reading data from ' . $url;
|
||||
return array();
|
||||
} else if ($file == '') {
|
||||
$this->error = 'No data returned from ' . $url;
|
||||
return array();
|
||||
}
|
||||
|
||||
// check for API error message
|
||||
if (strpos($file, chr(27)) !== false) {
|
||||
$this->error = 'Cannot decode recent track info from ' . $url;
|
||||
return array();
|
||||
}
|
||||
|
||||
// return list of tracks as array of strings
|
||||
return explode("\r\n", $file);
|
||||
} // getRecent
|
||||
|
||||
private function getList($name, $author, $env) {
|
||||
|
||||
// older TMX sections don't support multi-page results :(
|
||||
$maxpage = 1;
|
||||
if ($this->prefix == 'tmnforever' || $this->prefix == 'united')
|
||||
$maxpage = 25; // max. 500 tracks
|
||||
|
||||
// compile search URL
|
||||
$url = 'http://' . $this->prefix . '.tm-exchange.com/apiget.aspx?action=apisearch';
|
||||
if ($name != '')
|
||||
$url .= '&track=' . $name;
|
||||
if ($author != '')
|
||||
$url .= '&author=' . $author;
|
||||
if ($env != '')
|
||||
$url .= '&env=' . $env;
|
||||
$url .= '&page=';
|
||||
|
||||
$tracks = '';
|
||||
$page = 0;
|
||||
$done = false;
|
||||
|
||||
// get results 20 tracks at a time
|
||||
while ($page < $maxpage && !$done) {
|
||||
$file = $this->get_file($url . $page);
|
||||
if ($file === false) {
|
||||
$this->error = 'Connection or response error on ' . $url;
|
||||
return array();
|
||||
} else if ($file === -1) {
|
||||
$this->error = 'Timed out while reading data from ' . $url;
|
||||
return array();
|
||||
} else if ($file == '') {
|
||||
if ($tracks == '') {
|
||||
$this->error = 'No data returned from ' . $url;
|
||||
return array();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check for API error message
|
||||
if (strpos($file, chr(27)) !== false) {
|
||||
$this->error = 'Cannot decode searched track info from ' . $url;
|
||||
return array();
|
||||
}
|
||||
|
||||
// check for results
|
||||
if ($file != '') {
|
||||
// no line break before first page
|
||||
$tracks .= ($page++ > 0 ? "\r\n" : '') . $file;
|
||||
} else {
|
||||
$done = true;
|
||||
}
|
||||
}
|
||||
|
||||
// return list of tracks as array of strings
|
||||
if ($tracks != '')
|
||||
return explode("\r\n", $tracks);
|
||||
else
|
||||
return array();
|
||||
} // getList
|
||||
|
||||
// Simple HTTP Get function with timeout
|
||||
// ok: return string || error: return false || timeout: return -1
|
||||
private function get_file($url) {
|
||||
|
||||
$url = parse_url($url);
|
||||
$port = isset($url['port']) ? $url['port'] : 80;
|
||||
$query = isset($url['query']) ? "?" . $url['query'] : "";
|
||||
|
||||
$fp = @fsockopen($url['host'], $port, $errno, $errstr, 4);
|
||||
if (!$fp)
|
||||
return false;
|
||||
|
||||
fwrite($fp, 'GET ' . $url['path'] . $query . " HTTP/1.0\r\n" .
|
||||
'Host: ' . $url['host'] . "\r\n" .
|
||||
'User-Agent: TMXInfoSearcher (' . PHP_OS . ")\r\n\r\n");
|
||||
stream_set_timeout($fp, 2);
|
||||
$res = '';
|
||||
$info['timed_out'] = false;
|
||||
while (!feof($fp) && !$info['timed_out']) {
|
||||
$res .= fread($fp, 512);
|
||||
$info = stream_get_meta_data($fp);
|
||||
}
|
||||
fclose($fp);
|
||||
|
||||
if ($info['timed_out']) {
|
||||
return -1;
|
||||
} else {
|
||||
if (substr($res, 9, 3) != '200')
|
||||
return false;
|
||||
$page = explode("\r\n\r\n", $res, 2);
|
||||
return trim($page[1]);
|
||||
}
|
||||
} // get_file
|
||||
} // class TMXInfoSearcher
|
||||
|
||||
|
||||
class TMXInfo {
|
||||
|
||||
public $section, $prefix, $id, $name, $userid, $author,
|
||||
$type, $envir, $mood, $style, $routes, $length, $diffic,
|
||||
$lbrating, $awards, $comments, $custimg, $game, $uploaded, $updated,
|
||||
$pageurl, $replayid, $replayurl, $imageurl, $thumburl, $dloadurl;
|
||||
|
||||
/**
|
||||
* Returns track object with a hell of a lot of data from TMX track string
|
||||
*
|
||||
* @param String $section
|
||||
* TMX section
|
||||
* @param String $prefix
|
||||
* TMX URL prefix
|
||||
* @param String $track
|
||||
* The TMX track string from TMXInfoSearcher
|
||||
* @return TMXInfo
|
||||
*/
|
||||
public function TMXInfo($section, $prefix, $track) {
|
||||
|
||||
$this->section = $section;
|
||||
$this->prefix = $prefix;
|
||||
if ($track) {
|
||||
// separate columns on Tabs
|
||||
$fields = explode(chr(9), $track);
|
||||
|
||||
$this->id = $fields[0];
|
||||
$this->name = $fields[1];
|
||||
$this->userid = $fields[2];
|
||||
$this->author = $fields[3];
|
||||
$this->type = $fields[4];
|
||||
$this->envir = $fields[5];
|
||||
$this->mood = $fields[6];
|
||||
$this->style = $fields[7];
|
||||
$this->routes = $fields[8];
|
||||
$this->length = $fields[9];
|
||||
$this->diffic = $fields[10];
|
||||
$this->lbrating = ($fields[11] > 0 ? $fields[11] : 'Classic!');
|
||||
$this->awards = $fields[12];
|
||||
$this->comments = $fields[13];
|
||||
$this->custimg = (strtolower($fields[14]) == 'true');
|
||||
$this->game = $fields[15];
|
||||
$this->replayid = $fields[16];
|
||||
// unknown = $fields[17-21];
|
||||
$this->uploaded = $fields[22];
|
||||
$this->updated = $fields[23];
|
||||
|
||||
$this->pageurl = 'http://' . $prefix . '.tm-exchange.com/main.aspx?action=trackshow&id=' . $this->id;
|
||||
$this->imageurl = 'http://' . $prefix . '.tm-exchange.com/get.aspx?action=trackscreen&id=' . $this->id;
|
||||
$this->thumburl = 'http://' . $prefix . '.tm-exchange.com/get.aspx?action=trackscreensmall&id=' . $this->id;
|
||||
$this->dloadurl = 'http://' . $prefix . '.tm-exchange.com/get.aspx?action=trackgbx&id=' . $this->id;
|
||||
|
||||
if ($this->replayid > 0) {
|
||||
$this->replayurl = 'http://' . $prefix . '.tm-exchange.com/get.aspx?action=recordgbx&id=' . $this->replayid;
|
||||
} else {
|
||||
$this->replayurl = '';
|
||||
}
|
||||
}
|
||||
} // TMXInfo
|
||||
} // class TMXInfo
|
||||
?>
|
|
@ -0,0 +1,511 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
// Updated by Xymph
|
||||
|
||||
/**
|
||||
* Structure of a Record.
|
||||
*/
|
||||
class Record {
|
||||
var $player;
|
||||
var $challenge;
|
||||
var $score;
|
||||
var $date;
|
||||
var $checks;
|
||||
var $new;
|
||||
var $pos;
|
||||
} // class Record
|
||||
|
||||
/**
|
||||
* Manages a list of records.
|
||||
* Add records to the list and remove them.
|
||||
*/
|
||||
class RecordList {
|
||||
var $record_list;
|
||||
var $max;
|
||||
|
||||
// instantiates a record list with max $limit records
|
||||
function RecordList($limit) {
|
||||
$this->record_list = array();
|
||||
$this->max = $limit;
|
||||
}
|
||||
|
||||
function setLimit($limit) {
|
||||
$this->max = $limit;
|
||||
}
|
||||
|
||||
function getRecord($rank) {
|
||||
if (isset($this->record_list[$rank]))
|
||||
return $this->record_list[$rank];
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
function setRecord($rank, $record) {
|
||||
if (isset($this->record_list[$rank])) {
|
||||
return $this->record_list[$rank] = $record;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function moveRecord($from, $to) {
|
||||
moveArrayElement($this->record_list, $from, $to);
|
||||
}
|
||||
|
||||
function addRecord($record, $rank = -1) {
|
||||
|
||||
// if no rank was set for this record, then put it to the end of the list
|
||||
if ($rank == -1) {
|
||||
$rank = count($this->record_list);
|
||||
}
|
||||
|
||||
// do not insert a record behind the border of the list
|
||||
if ($rank >= $this->max) return;
|
||||
|
||||
// do not insert a record with no score
|
||||
if ($record->score <= 0) return;
|
||||
|
||||
// if the given object is a record
|
||||
if (get_class($record) == 'Record') {
|
||||
|
||||
// if records are getting too much, drop the last from the list
|
||||
if (count($this->record_list) >= $this->max) {
|
||||
array_pop($this->record_list);
|
||||
}
|
||||
|
||||
// insert the record at the specified position
|
||||
return insertArrayElement($this->record_list, $record, $rank);
|
||||
}
|
||||
}
|
||||
|
||||
function delRecord($rank = -1) {
|
||||
|
||||
// do not remove a record outside the current list
|
||||
if ($rank < 0 || $rank >= count($this->record_list)) return;
|
||||
|
||||
// remove the record from the specified position
|
||||
return removeArrayElement($this->record_list, $rank);
|
||||
}
|
||||
|
||||
function count() {
|
||||
return count($this->record_list);
|
||||
}
|
||||
|
||||
function clear() {
|
||||
$this->record_list = array();
|
||||
}
|
||||
} // class RecordList
|
||||
|
||||
|
||||
/**
|
||||
* Structure of a Player.
|
||||
* Can be instantiated with an RPC 'GetPlayerInfo' or
|
||||
* 'GetDetailedPlayerInfo' response.
|
||||
*/
|
||||
class Player {
|
||||
var $id;
|
||||
var $pid;
|
||||
var $login;
|
||||
var $nickname;
|
||||
var $teamname;
|
||||
var $ip;
|
||||
var $client;
|
||||
var $ipport;
|
||||
var $zone;
|
||||
var $nation;
|
||||
var $prevstatus;
|
||||
var $isspectator;
|
||||
var $isofficial;
|
||||
var $rights;
|
||||
var $language;
|
||||
var $avatar;
|
||||
var $teamid;
|
||||
var $unlocked;
|
||||
var $ladderrank;
|
||||
var $ladderscore;
|
||||
var $created;
|
||||
var $wins;
|
||||
var $newwins;
|
||||
var $timeplayed;
|
||||
var $tracklist;
|
||||
var $playerlist;
|
||||
var $msgs;
|
||||
var $pmbuf;
|
||||
var $mutelist;
|
||||
var $mutebuf;
|
||||
var $style;
|
||||
var $panels;
|
||||
var $speclogin;
|
||||
var $dedirank;
|
||||
|
||||
function getWins() {
|
||||
return $this->wins + $this->newwins;
|
||||
}
|
||||
|
||||
function getTimePlayed() {
|
||||
return $this->timeplayed + $this->getTimeOnline();
|
||||
}
|
||||
|
||||
function getTimeOnline() {
|
||||
return $this->created > 0 ? time() - $this->created : 0;
|
||||
}
|
||||
|
||||
// instantiates the player with an RPC response
|
||||
function Player($rpc_infos = null) {
|
||||
$this->id = 0;
|
||||
if ($rpc_infos) {
|
||||
$this->pid = $rpc_infos['PlayerId'];
|
||||
$this->login = $rpc_infos['Login'];
|
||||
$this->nickname = $rpc_infos['NickName'];
|
||||
$this->ipport = $rpc_infos['IPAddress'];
|
||||
$this->ip = preg_replace('/:\d+/', '', $rpc_infos['IPAddress']); // strip port
|
||||
$this->prevstatus = false;
|
||||
$this->isspectator = $rpc_infos['IsSpectator'];
|
||||
$this->isofficial = $rpc_infos['IsInOfficialMode'];
|
||||
$this->teamname = $rpc_infos['LadderStats']['TeamName'];
|
||||
if (isset($rpc_infos['Nation'])) { // TMN (TMS/TMO?)
|
||||
$this->zone = $rpc_infos['Nation'];
|
||||
$this->nation = $rpc_infos['Nation'];
|
||||
$this->ladderrank = $rpc_infos['LadderStats']['Ranking'];
|
||||
$this->ladderscore = $rpc_infos['LadderStats']['Score'];
|
||||
$this->client = '';
|
||||
$this->rights = false;
|
||||
$this->language = '';
|
||||
$this->avatar = '';
|
||||
$this->teamid = 0;
|
||||
} else { // TMF
|
||||
$this->zone = substr($rpc_infos['Path'], 6); // strip 'World|'
|
||||
$this->nation = explode('|', $rpc_infos['Path']);
|
||||
if (isset($this->nation[1]))
|
||||
$this->nation = $this->nation[1];
|
||||
else
|
||||
$this->nation = '';
|
||||
$this->ladderrank = $rpc_infos['LadderStats']['PlayerRankings'][0]['Ranking'];
|
||||
$this->ladderscore = round($rpc_infos['LadderStats']['PlayerRankings'][0]['Score'], 2);
|
||||
$this->client = $rpc_infos['ClientVersion'];
|
||||
$this->rights = ($rpc_infos['OnlineRights'] == 3); // United = true
|
||||
$this->language = $rpc_infos['Language'];
|
||||
$this->avatar = $rpc_infos['Avatar']['FileName'];
|
||||
$this->teamid = $rpc_infos['TeamId'];
|
||||
}
|
||||
$this->created = time();
|
||||
} else {
|
||||
// set defaults
|
||||
$this->pid = 0;
|
||||
$this->login = '';
|
||||
$this->nickname = '';
|
||||
$this->ipport = '';
|
||||
$this->ip = '';
|
||||
$this->prevstatus = false;
|
||||
$this->isspectator = false;
|
||||
$this->isofficial = false;
|
||||
$this->teamname = '';
|
||||
$this->zone = '';
|
||||
$this->nation = '';
|
||||
$this->ladderrank = 0;
|
||||
$this->ladderscore = 0;
|
||||
$this->rights = false;
|
||||
$this->created = 0;
|
||||
}
|
||||
$this->wins = 0;
|
||||
$this->newwins = 0;
|
||||
$this->timeplayed = 0;
|
||||
$this->unlocked = false;
|
||||
$this->pmbuf = array();
|
||||
$this->mutelist = array();
|
||||
$this->mutebuf = array();
|
||||
$this->style = array();
|
||||
$this->panels = array();
|
||||
$this->speclogin = '';
|
||||
$this->dedirank = 0;
|
||||
}
|
||||
} // class Player
|
||||
|
||||
/**
|
||||
* Manages players on the server.
|
||||
* Add player and remove them.
|
||||
*/
|
||||
class PlayerList {
|
||||
var $player_list;
|
||||
|
||||
// instantiates the empty player list
|
||||
function PlayerList() {
|
||||
$this->player_list = array();
|
||||
}
|
||||
|
||||
function nextPlayer() {
|
||||
if (is_array($this->player_list)) {
|
||||
$player_item = current($this->player_list);
|
||||
next($this->player_list);
|
||||
return $player_item;
|
||||
} else {
|
||||
$this->resetPlayers();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function resetPlayers() {
|
||||
if (is_array($this->player_list)) {
|
||||
reset($this->player_list);
|
||||
}
|
||||
}
|
||||
|
||||
function addPlayer($player) {
|
||||
if (get_class($player) == 'Player' && $player->login != '') {
|
||||
$this->player_list[$player->login] = $player;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function removePlayer($login) {
|
||||
if (isset($this->player_list[$login])) {
|
||||
$player = $this->player_list[$login];
|
||||
unset($this->player_list[$login]);
|
||||
} else {
|
||||
$player = false;
|
||||
}
|
||||
return $player;
|
||||
}
|
||||
|
||||
function getPlayer($login) {
|
||||
if (isset($this->player_list[$login]))
|
||||
return $this->player_list[$login];
|
||||
else
|
||||
return false;
|
||||
}
|
||||
} // class PlayerList
|
||||
|
||||
|
||||
/**
|
||||
* Can store challenge information.
|
||||
* You can instantiate with an RPC 'GetChallengeInfo' response.
|
||||
*/
|
||||
class Challenge {
|
||||
var $id;
|
||||
var $name;
|
||||
var $uid;
|
||||
var $filename;
|
||||
var $author;
|
||||
var $environment;
|
||||
var $mood;
|
||||
var $bronzetime;
|
||||
var $silvertime;
|
||||
var $goldtime;
|
||||
var $authortime;
|
||||
var $copperprice;
|
||||
var $laprace;
|
||||
var $forcedlaps;
|
||||
var $nblaps;
|
||||
var $nbchecks;
|
||||
var $score;
|
||||
var $starttime;
|
||||
var $gbx;
|
||||
var $tmx;
|
||||
|
||||
// instantiates the challenge with an RPC response
|
||||
function Challenge($rpc_infos = null) {
|
||||
$this->id = 0;
|
||||
if ($rpc_infos) {
|
||||
$this->name = stripNewlines($rpc_infos['Name']);
|
||||
$this->uid = $rpc_infos['UId'];
|
||||
$this->filename = $rpc_infos['FileName'];
|
||||
$this->author = $rpc_infos['Author'];
|
||||
$this->environment = $rpc_infos['Environnement'];
|
||||
$this->mood = $rpc_infos['Mood'];
|
||||
$this->bronzetime = $rpc_infos['BronzeTime'];
|
||||
$this->silvertime = $rpc_infos['SilverTime'];
|
||||
$this->goldtime = $rpc_infos['GoldTime'];
|
||||
$this->authortime = $rpc_infos['AuthorTime'];
|
||||
$this->copperprice = $rpc_infos['CopperPrice'];
|
||||
$this->laprace = $rpc_infos['LapRace'];
|
||||
$this->forcedlaps = 0;
|
||||
if (isset($rpc_infos['NbLaps']))
|
||||
$this->nblaps = $rpc_infos['NbLaps'];
|
||||
else
|
||||
$this->nblaps = 0;
|
||||
if (isset($rpc_infos['NbCheckpoints']))
|
||||
$this->nbchecks = $rpc_infos['NbCheckpoints'];
|
||||
else
|
||||
$this->nbchecks = 0;
|
||||
} else {
|
||||
// set defaults
|
||||
$this->name = 'undefined';
|
||||
}
|
||||
}
|
||||
} // class Challenge
|
||||
|
||||
|
||||
/**
|
||||
* Contains information about an RPC call.
|
||||
*/
|
||||
class RPCCall {
|
||||
var $index;
|
||||
var $id;
|
||||
var $callback;
|
||||
var $call;
|
||||
|
||||
// instantiates the RPC call with the parameters
|
||||
function RPCCall($id, $index, $callback, $call) {
|
||||
$this->id = $id;
|
||||
$this->index = $index;
|
||||
$this->callback = $callback;
|
||||
$this->call = $call;
|
||||
}
|
||||
} // class RPCCall
|
||||
|
||||
|
||||
/**
|
||||
* Contains information about a chat command.
|
||||
*/
|
||||
class ChatCommand {
|
||||
var $name;
|
||||
var $help;
|
||||
var $isadmin;
|
||||
|
||||
// instantiates the chat command with the parameters
|
||||
function ChatCommand($name, $help, $isadmin) {
|
||||
$this->name = $name;
|
||||
$this->help = $help;
|
||||
$this->isadmin = $isadmin;
|
||||
}
|
||||
} // class ChatCommand
|
||||
|
||||
|
||||
/**
|
||||
* Stores basic information of the server XASECO is running on.
|
||||
*/
|
||||
class Server {
|
||||
var $id;
|
||||
var $name;
|
||||
var $game;
|
||||
var $serverlogin;
|
||||
var $nickname;
|
||||
var $zone;
|
||||
var $rights;
|
||||
var $ip;
|
||||
var $port;
|
||||
var $timeout;
|
||||
var $version;
|
||||
var $build;
|
||||
var $packmask;
|
||||
var $laddermin;
|
||||
var $laddermax;
|
||||
var $login;
|
||||
var $pass;
|
||||
var $maxplay;
|
||||
var $maxspec;
|
||||
var $challenge;
|
||||
var $records;
|
||||
var $players;
|
||||
var $mutelist;
|
||||
var $gamestate;
|
||||
var $gameinfo;
|
||||
var $gamedir;
|
||||
var $trackdir;
|
||||
var $votetime;
|
||||
var $voterate;
|
||||
var $uptime;
|
||||
var $starttime;
|
||||
var $isrelay;
|
||||
var $relaymaster;
|
||||
var $relayslist;
|
||||
|
||||
// game states
|
||||
const RACE = 'race';
|
||||
const SCORE = 'score';
|
||||
|
||||
function getGame() {
|
||||
switch ($this->game) {
|
||||
case 'TmForever':
|
||||
return 'TMF';
|
||||
case 'TmNationsESWC':
|
||||
return 'TMN';
|
||||
case 'TmSunrise':
|
||||
return 'TMS';
|
||||
case 'TmOriginal':
|
||||
return 'TMO';
|
||||
default: // TMU was never supported
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
// instantiates the server with default parameters
|
||||
function Server($ip, $port, $login, $pass) {
|
||||
$this->ip = $ip;
|
||||
$this->port = $port;
|
||||
$this->login = $login;
|
||||
$this->pass = $pass;
|
||||
$this->starttime = time();
|
||||
}
|
||||
} // class Server
|
||||
|
||||
/**
|
||||
* Contains information to the current game which is played.
|
||||
*/
|
||||
class Gameinfo {
|
||||
var $mode;
|
||||
var $numchall;
|
||||
var $rndslimit;
|
||||
var $timelimit;
|
||||
var $teamlimit;
|
||||
var $lapslimit;
|
||||
var $cuplimit;
|
||||
var $forcedlaps;
|
||||
|
||||
const RNDS = 0;
|
||||
const TA = 1;
|
||||
const TEAM = 2;
|
||||
const LAPS = 3;
|
||||
const STNT = 4;
|
||||
const CUP = 5;
|
||||
|
||||
// returns current game mode as string
|
||||
function getMode() {
|
||||
switch ($this->mode) {
|
||||
case self::RNDS:
|
||||
return 'Rounds';
|
||||
case self::TA:
|
||||
return 'TimeAttack';
|
||||
case self::TEAM:
|
||||
return 'Team';
|
||||
case self::LAPS:
|
||||
return 'Laps';
|
||||
case self::STNT:
|
||||
return 'Stunts';
|
||||
case self::CUP:
|
||||
return 'Cup';
|
||||
default:
|
||||
return 'Undefined';
|
||||
}
|
||||
}
|
||||
|
||||
// instantiates the game info with an RPC response
|
||||
function Gameinfo($rpc_infos = null) {
|
||||
if ($rpc_infos) {
|
||||
$this->mode = $rpc_infos['GameMode'];
|
||||
$this->numchall = $rpc_infos['NbChallenge'];
|
||||
if (isset($rpc_infos['RoundsUseNewRules']) && $rpc_infos['RoundsUseNewRules'])
|
||||
$this->rndslimit = $rpc_infos['RoundsPointsLimitNewRules'];
|
||||
else
|
||||
$this->rndslimit = $rpc_infos['RoundsPointsLimit'];
|
||||
$this->timelimit = $rpc_infos['TimeAttackLimit'];
|
||||
if (isset($rpc_infos['TeamUseNewRules']) && $rpc_infos['TeamUseNewRules'])
|
||||
$this->teamlimit = $rpc_infos['TeamPointsLimitNewRules'];
|
||||
else
|
||||
$this->teamlimit = $rpc_infos['TeamPointsLimit'];
|
||||
$this->lapslimit = $rpc_infos['LapsTimeLimit'];
|
||||
if (isset($rpc_infos['CupPointsLimit']))
|
||||
$this->cuplimit = $rpc_infos['CupPointsLimit'];
|
||||
if (isset($rpc_infos['RoundsForcedLaps']))
|
||||
$this->forcedlaps = $rpc_infos['RoundsForcedLaps'];
|
||||
else
|
||||
$this->forcedlaps = 0;
|
||||
} else {
|
||||
$this->mode = -1;
|
||||
}
|
||||
}
|
||||
} // class Gameinfo
|
||||
?>
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
// Alternative base64 url compatible decode and encode functions
|
||||
// Written by Ferdinand Dosser
|
||||
// Updated by Xymph
|
||||
|
||||
// urlsafe base64 alternative encode
|
||||
function urlsafe_base64_encode($string) {
|
||||
|
||||
$data = base64_encode($string);
|
||||
$data = str_replace(array('+','/','='), array('-','_',''), $data);
|
||||
return $data;
|
||||
} // urlsafe_base64_encode
|
||||
|
||||
// urlsafe base64 alternative decode
|
||||
function urlsafe_base64_decode($string) {
|
||||
|
||||
$data = str_replace(array('-','_'), array('+','/'), $string);
|
||||
$mod4 = strlen($data) % 4;
|
||||
if ($mod4) {
|
||||
$data .= substr('====', $mod4);
|
||||
}
|
||||
return base64_decode($data);
|
||||
} // urlsafe_base64_decode
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* Builds an easy structured array out of a xml file.
|
||||
* Element names will be the keys and the data the values.
|
||||
*
|
||||
* Updated by Xymph
|
||||
*/
|
||||
|
||||
class Examsly {
|
||||
var $data;
|
||||
var $struct;
|
||||
var $parser;
|
||||
var $stack;
|
||||
var $utf8enc;
|
||||
|
||||
/**
|
||||
* Parses a XML structure into an array.
|
||||
*/
|
||||
function parseXml($source, $isfile = true, $utf8enc = false) {
|
||||
|
||||
// clear last results
|
||||
$this->stack = array();
|
||||
$this->struct = array();
|
||||
$this->utf8enc = $utf8enc;
|
||||
|
||||
// create the parser
|
||||
$this->parser = xml_parser_create();
|
||||
xml_set_object($this->parser, $this);
|
||||
xml_set_element_handler($this->parser, 'openTag', 'closeTag');
|
||||
xml_set_character_data_handler($this->parser, 'tagData');
|
||||
|
||||
// load the xml file
|
||||
if ($isfile)
|
||||
$this->data = @file_get_contents($source);
|
||||
else
|
||||
$this->data = $source;
|
||||
|
||||
// escape '&' characters
|
||||
$this->data = str_replace('&', '<![CDATA[&]]>', $this->data);
|
||||
|
||||
// parse xml file
|
||||
$parsed = xml_parse($this->parser, $this->data);
|
||||
|
||||
// display errors
|
||||
if (!$parsed) {
|
||||
$code = xml_get_error_code($this->parser);
|
||||
$err = xml_error_string($code);
|
||||
$line = xml_get_current_line_number($this->parser);
|
||||
trigger_error("[XML Error $code] $err on line $line", E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
return $this->struct;
|
||||
}
|
||||
|
||||
private function openTag($parser, $name, $attributes) {
|
||||
$this->stack[] = $name;
|
||||
$this->struct[$name] = '';
|
||||
}
|
||||
|
||||
private function tagData($parser, $data) {
|
||||
if (trim($data)) {
|
||||
$index = $this->stack[count($this->stack)-1];
|
||||
// use raw, don't decode '+' into space
|
||||
if ($this->utf8enc)
|
||||
$this->struct[$index] .= rawurldecode($data);
|
||||
else
|
||||
$this->struct[$index] .= utf8_decode(rawurldecode($data));
|
||||
}
|
||||
}
|
||||
|
||||
private function closeTag($parser, $name) {
|
||||
if (count($this->stack) > 1) {
|
||||
$from = array_pop($this->stack);
|
||||
$to = $this->stack[count($this->stack)-1];
|
||||
$this->struct[$to][$from][] = $this->struct[$from];
|
||||
unset($this->struct[$from]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array into an XML structure.
|
||||
*/
|
||||
function parseArray($array) {
|
||||
$xmlstring = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
|
||||
$xmlstring .= $this->parseArrayElements($array);
|
||||
return $xmlstring;
|
||||
}
|
||||
|
||||
private function parseArrayElements($array, $opt_tag = '') {
|
||||
|
||||
// read each element of the array
|
||||
for ($i = 0; $i < count($array); $i++) {
|
||||
|
||||
// check if array is associative
|
||||
if (is_numeric(key($array))) {
|
||||
$xml .= '<'.$opt_tag.'>';
|
||||
if (is_array(current($array))) {
|
||||
$xml .= $this->parseArrayElements(current($array), key($array));
|
||||
} else {
|
||||
// use raw, don't encode space into '+'
|
||||
$xml .= rawurlencode(utf8_encode(current($array)));
|
||||
}
|
||||
$xml .= '</'.$opt_tag.'>';
|
||||
} else {
|
||||
if (is_array(current($array))) {
|
||||
$xml .= $this->parseArrayElements(current($array), key($array));
|
||||
} else {
|
||||
$xml .= '<'.key($array).'>';
|
||||
// use raw, don't encode space into '+'
|
||||
$xml .= rawurlencode(utf8_encode(current($array)));
|
||||
$xml .= '</'.key($array).'>';
|
||||
}
|
||||
}
|
||||
next($array);
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,385 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// File: XMLRPC DB ACCESS 2.1
|
||||
// Date: 28.05.2009
|
||||
// Author: Gilles Masson
|
||||
// Updated: Xymph
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class XmlrpcDB {
|
||||
|
||||
//-----------------------------
|
||||
// Fields
|
||||
//-----------------------------
|
||||
|
||||
var $_webaccess;
|
||||
var $_url;
|
||||
var $_server;
|
||||
var $_callbacks;
|
||||
var $_requests;
|
||||
var $_auth_cb;
|
||||
var $_bad;
|
||||
var $_bad_time;
|
||||
var $_debug;
|
||||
|
||||
//-----------------------------
|
||||
// Methods
|
||||
//-----------------------------
|
||||
|
||||
function XmlrpcDB($webaccess, $url, $game, $login, $password, $tool, $version, $nation, $packmask = '') {
|
||||
|
||||
$this->_debug = 0; // max debug level = 3
|
||||
$this->_webaccess = $webaccess;
|
||||
$this->_url = $url;
|
||||
$this->_server = array('Game' => $game,
|
||||
'Login' => $login,
|
||||
'Password' => $password,
|
||||
'Tool' => $tool,
|
||||
'Version' => $version,
|
||||
'Nation' => $nation,
|
||||
'Packmask' => $packmask,
|
||||
'PlayersGame' => true
|
||||
);
|
||||
$this->_auth_cb = array('xmlrpc_auth_cb');
|
||||
|
||||
$this->_bad = false;
|
||||
$this->_bad_time = -1;
|
||||
// in case webaccess URL connection was previously in error, ask to retry
|
||||
$this->_webaccess->retry($this->_url);
|
||||
|
||||
// prepare to add requests
|
||||
$this->_initRequest();
|
||||
} // XmlrpcDB
|
||||
|
||||
// change the packmask value
|
||||
function setPackmask($packmask = '') {
|
||||
|
||||
$this->_server['Packmask'] = $packmask;
|
||||
} // setPackmask
|
||||
|
||||
// is the connection in recurrent error?
|
||||
function isBad() {
|
||||
|
||||
return $this->_bad;
|
||||
} // isBad
|
||||
|
||||
// get time since the error state was set
|
||||
function badTime() {
|
||||
|
||||
return (time() - $this->_bad_time);
|
||||
} // badTime
|
||||
|
||||
// stop the bad state: will try again at next RequestWait(),
|
||||
// sendRequestsWait() or sendRequests()
|
||||
function retry() {
|
||||
|
||||
$this->_bad = false;
|
||||
$this->_bad_time = -1;
|
||||
// set webaccess object to retry on that URL too
|
||||
$this->_webaccess->retry($this->_url);
|
||||
} // retry
|
||||
|
||||
// clear all requests, and get them if asked
|
||||
function clearRequests($get_requests = false) {
|
||||
|
||||
if ($get_requests) {
|
||||
$return = array($_requests, $_callbacks);
|
||||
$this->_initRequest();
|
||||
return $return;
|
||||
}
|
||||
$this->_initRequest();
|
||||
} // clearRequests
|
||||
|
||||
// add a request
|
||||
function addRequest($callback, $method) {
|
||||
|
||||
$args = func_get_args();
|
||||
$callback = array_shift($args);
|
||||
$method = array_shift($args);
|
||||
return $this->addRequestArray($callback, $method, $args);
|
||||
} // addRequest
|
||||
|
||||
// add a request
|
||||
function addRequestArray($callback, $method, $args) {
|
||||
|
||||
$this->_callbacks[] = $callback;
|
||||
$this->_requests[] = array('methodName' => $method, 'params' => $args);
|
||||
return count($this->_requests) - 1;
|
||||
} // addRequestArray
|
||||
|
||||
// send added requests, callbacks will be called when response come
|
||||
function sendRequests() {
|
||||
global $aseco;
|
||||
|
||||
if (count($this->_callbacks) > 1) {
|
||||
$this->addRequest(null, 'dedimania.WarningsAndTTR');
|
||||
$webdatas = $this->_makeXMLdatas();
|
||||
$response = $this->_webaccess->request($this->_url,
|
||||
array( array($this, '_callCB'), $this->_callbacks, $this->_requests),
|
||||
$webdatas, true);
|
||||
$this->_initRequest();
|
||||
if ($response === false) {
|
||||
if (!$this->_bad) {
|
||||
$this->_bad = true;
|
||||
$this->_bad_time = time();
|
||||
}
|
||||
if ($this->_debug > 2)
|
||||
$aseco->console_text('XmlrpcDB->sendRequests - this' . CRLF . print_r($this, true));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} // sendRequests
|
||||
|
||||
// send added requests, wait response, then call callbacks
|
||||
function sendRequestsWait() {
|
||||
global $aseco;
|
||||
|
||||
if (count($this->_callbacks) > 1) {
|
||||
$this->addRequest(null, 'dedimania.WarningsAndTTR');
|
||||
$webdatas = $this->_makeXMLdatas();
|
||||
$response = $this->_webaccess->request($this->_url,
|
||||
null, $webdatas, true);
|
||||
if ($response === false) {
|
||||
if (!$this->_bad) {
|
||||
$this->_bad = true;
|
||||
$this->_bad_time = time();
|
||||
}
|
||||
if ($this->_debug > 0)
|
||||
$aseco->console_text('XmlrpcDB->sendRequestsWait - this' . CRLF . print_r($this, true));
|
||||
$this->_initRequest();
|
||||
return false;
|
||||
} else {
|
||||
$this->_callCB($response, $this->_callbacks, $this->_requests);
|
||||
$this->_initRequest();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} // sendRequestsWait
|
||||
|
||||
// send a request, wait response, and return the response
|
||||
function RequestWait($method) {
|
||||
|
||||
$args = func_get_args();
|
||||
$method = array_shift($args);
|
||||
return $this->RequestWaitArray($method, $args);
|
||||
} // RequestWait
|
||||
|
||||
// send a request, wait response, and return the response
|
||||
function RequestWaitArray($method, $args) {
|
||||
global $aseco;
|
||||
|
||||
if ($this->sendRequestsWait() === false) {
|
||||
if (!$this->_bad) {
|
||||
$this->_bad = true;
|
||||
$this->_bad_time = time();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$reqnum = $this->addRequestArray(null, $method, $args);
|
||||
|
||||
$this->addRequest(null, 'dedimania.WarningsAndTTR');
|
||||
$webdatas = $this->_makeXMLdatas();
|
||||
$response = $this->_webaccess->request($this->_url, null, $webdatas, true);
|
||||
if (isset($response['Message']) && is_string($response['Message'])) {
|
||||
if ($this->_debug > 1)
|
||||
$aseco->console_text('XmlrpcDB->RequestWaitArray() - response[Message]' . CRLF . print_r($response['Message'], true));
|
||||
|
||||
$xmlrpc_message = new IXR_Message($response['Message']);
|
||||
if ($xmlrpc_message->parse() && $xmlrpc_message->messageType != 'fault') {
|
||||
if ($this->_debug > 1) {
|
||||
$aseco->console_text('XmlrpcDB->RequestWaitArray() - message' . CRLF . print_r($xmlrpc_message->message, true));
|
||||
$aseco->console_text('XmlrpcDB->RequestWaitArray() - params' . CRLF . print_r($xmlrpc_message->params, true));
|
||||
}
|
||||
|
||||
//$datas = array('methodName' => $xmlrpc_message->methodName, 'params' => $xmlrpc_message->params);
|
||||
$datas = $this->_makeResponseDatas($xmlrpc_message->methodName, $xmlrpc_message->params, $this->_requests);
|
||||
} else {
|
||||
if ($this->_debug > 0)
|
||||
$aseco->console_text('XmlrpcDB->RequestWaitArray() - message fault' . CRLF . print_r($xmlrpc_message->message, true));
|
||||
$datas = array();
|
||||
}
|
||||
} else {
|
||||
$datas = array();
|
||||
}
|
||||
|
||||
if ($this->_debug > 0)
|
||||
$aseco->console_text('XmlrpcDB->RequestWaitArray() - datas' . CRLF . print_r($datas, true));
|
||||
if (isset($datas['params']) && isset($datas['params'][$reqnum])) {
|
||||
$response['Data'] = $datas['params'][$reqnum];
|
||||
$param_end = end($datas['params']);
|
||||
if (isset($param_end['globalTTR']) && !isset($response['Data']['globalTTR']))
|
||||
$response['Data']['globalTTR'] = $param_end['globalTTR'];
|
||||
} else {
|
||||
$response['Data'] = $datas;
|
||||
}
|
||||
if ($this->_debug > 0)
|
||||
$aseco->console_text('XmlrpcDB->RequestWaitArray() - response[Data]' . CRLF . print_r($response['Data'], true));
|
||||
|
||||
$this->_initRequest();
|
||||
return $response;
|
||||
} // RequestWaitArray
|
||||
|
||||
// init the request and callback array
|
||||
function _initRequest() {
|
||||
|
||||
$this->_callbacks = array();
|
||||
$this->_requests = array();
|
||||
$this->addRequest($this->_auth_cb, 'dedimania.Authenticate', $this->_server);
|
||||
} // _initRequest
|
||||
|
||||
// make the xmlrpc string, encode it in base64, and pass it as value
|
||||
// to xmlrpc URL post parameter
|
||||
function _makeXMLdatas() {
|
||||
global $aseco;
|
||||
|
||||
$xmlrpc_request = new IXR_RequestStd('system.multicall', $this->_requests);
|
||||
if ($this->_debug > 1)
|
||||
$aseco->console_text('XmlrpcDB->_makeXMLdatas() - getXml()' . CRLF . print_r($xmlrpc_request->getXml(), true));
|
||||
return $xmlrpc_request->getXml();
|
||||
} // _makeXMLdatas
|
||||
|
||||
function _callCB($response, $callbacks, $requests) {
|
||||
global $aseco;
|
||||
|
||||
$globalTTR = 0;
|
||||
if (isset($response['Message']) && is_string($response['Message'])) {
|
||||
$xmlrpc_message = new IXR_Message($response['Message']);
|
||||
if ($xmlrpc_message->parse() && $xmlrpc_message->messageType != 'fault') {
|
||||
if ($this->_debug > 1)
|
||||
$aseco->console_text('XmlrpcDB->_callCB() - message' . CRLF . print_r($xmlrpc_message->message, true));
|
||||
|
||||
//$datas = array('methodName' => $xmlrpc_message->methodName, 'params' => $xmlrpc_message->params);
|
||||
$datas = $this->_makeResponseDatas($xmlrpc_message->methodName, $xmlrpc_message->params, $requests);
|
||||
|
||||
if (isset($datas['params']) && is_array($datas['params'])) {
|
||||
$param_end = end($datas['params']);
|
||||
if (isset($param_end['globalTTR']))
|
||||
$globalTTR = $param_end['globalTTR'];
|
||||
} else {
|
||||
if ($this->_debug > 0)
|
||||
$aseco->console_text('XmlrpcDB->_callCB() - message fault' . CRLF . print_r($xmlrpc_message->message, true));
|
||||
$datas = array();
|
||||
}
|
||||
} else {
|
||||
if ($this->_debug > 0)
|
||||
$aseco->console_text('XmlrpcDB->_callCB() - message fault' . CRLF . print_r($xmlrpc_message->message, true));
|
||||
$datas = array();
|
||||
}
|
||||
} else {
|
||||
if (!isset($response['Error']) ||
|
||||
(strpos($response['Error'], 'connection failed') === false && strpos($response['Error'], 'Request timeout') === false)) {
|
||||
$infos = array('Url'=>$this->_url, 'Requests'=>$requests, 'Callbacks'=>$callbacks, 'Response'=>$response);
|
||||
$serinfos = serialize($infos);
|
||||
$aseco->console_text('XmlrpcDB->_callCB() - no response message:' . CRLF . $serinfos);
|
||||
}
|
||||
$datas = array();
|
||||
}
|
||||
|
||||
for ($i = 0; $i < count($callbacks); $i++) {
|
||||
if ($callbacks[$i] != null) {
|
||||
$callback = $callbacks[$i][0];
|
||||
if (isset($datas['params']) && isset($datas['params'][$i])) {
|
||||
$response['Data'] = $datas['params'][$i];
|
||||
if (!isset($response['Data']['globalTTR']))
|
||||
$response['Data']['globalTTR'] = $globalTTR;
|
||||
} else {
|
||||
$response['Data'] = $datas;
|
||||
}
|
||||
$callbacks[$i][0] = $response;
|
||||
call_user_func_array($callback, $callbacks[$i]);
|
||||
}
|
||||
}
|
||||
} // _callCB
|
||||
|
||||
// build the datas array from XAseco or Dedimania server
|
||||
// remove the first array level into params if needed
|
||||
// add methodResponse name if needed
|
||||
// rename sub responses params array from [0] to ['params'] if needed
|
||||
function _makeResponseDatas($methodname, $params, $requests) {
|
||||
global $aseco;
|
||||
|
||||
if (is_array($params) && count($params) == 1 && is_array($params[0]))
|
||||
$params = $params[0];
|
||||
if ($this->_debug > 2)
|
||||
$aseco->console_text('XmlrpcDB->_makeResponseDatas() - requests' . CRLF . print_r($requests, true));
|
||||
if ($this->_debug > 1)
|
||||
$aseco->console_text('XmlrpcDB->_makeResponseDatas() - params' . CRLF . print_r($params, true));
|
||||
|
||||
if (is_array($params) && is_array($params[0]) && !isset($params[0]['methodResponse'])) {
|
||||
$params2 = array();
|
||||
foreach ($params as $key => $param) {
|
||||
$errors = null;
|
||||
if (isset($param['faultCode'])) {
|
||||
$errors[] = array('Code' => $param['faultCode'], 'Message' => $param['faultString']);
|
||||
}
|
||||
|
||||
if (isset($requests[$key]['methodName']))
|
||||
$methodresponse = $requests[$key]['methodName'];
|
||||
else
|
||||
$methodresponse = 'Unknown';
|
||||
|
||||
$ttr = 0.000001;
|
||||
|
||||
if (isset($param[0]))
|
||||
$param = $param[0];
|
||||
else
|
||||
$param = array();
|
||||
|
||||
$params2[$key] = array('methodResponse' => $methodresponse,
|
||||
'params' => $param,
|
||||
'errors' => $errors,
|
||||
'TTR' => $ttr,
|
||||
'globalTTR' => $ttr
|
||||
);
|
||||
|
||||
if ($methodresponse == 'dedimania.WarningsAndTTR') {
|
||||
if ($this->_debug > 1) {
|
||||
$aseco->console_text('XmlrpcDB->_makeResponseDatas() - param' . CRLF . print_r($param, true));
|
||||
$aseco->console_text('XmlrpcDB->_makeResponseDatas() - params2' . CRLF . print_r($params2, true));
|
||||
}
|
||||
$globalTTR = $param['globalTTR'];
|
||||
foreach ($param['methods'] as $key3 => $param3) {
|
||||
$key2 = 0;
|
||||
while ($key2 < count($params2) && $params2[$key2]['methodResponse'] != $param3['methodName']) {
|
||||
$params2[$key2]['globalTTR'] = $globalTTR;
|
||||
$key2++;
|
||||
}
|
||||
if ($this->_debug > 1)
|
||||
$aseco->console_text("XmlrpcDB->_makeResponseDatas() - key2=$key2 - key3=$key3 - param3" . CRLF . print_r($param3, true));
|
||||
if ($key2 < count($params2)) {
|
||||
$params2[$key2]['errors'] = $param3['errors'];
|
||||
$params2[$key2]['TTR'] = $param3['TTR'];
|
||||
$params2[$key2]['globalTTR'] = $globalTTR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->_debug > 1)
|
||||
$aseco->console_text('XmlrpcDB->_makeResponseDatas() - params2' . CRLF . print_r($params2, true));
|
||||
return array('methodName' => $methodname, 'params' => $params2);
|
||||
|
||||
} else {
|
||||
return array('methodName' => $methodname, 'params' => $params);
|
||||
}
|
||||
} // _makeResponseDatas
|
||||
} // class XmlrpcDB
|
||||
|
||||
|
||||
// Dedimania.Authenticate callback used to catch errors
|
||||
function xmlrpc_auth_cb($response) {
|
||||
global $aseco;
|
||||
|
||||
if (isset($response['Data']['errors']) && $response['Data']['errors'] != '') {
|
||||
if (is_array($response['Data']['errors']))
|
||||
$aseco->console('xmlrpc_auth_cb() - response[Data][errors]' . CRLF . print_r($response['Data']['errors'], true));
|
||||
else
|
||||
$aseco->console('xmlrpc_auth_cb() - response[Data][errors]' . CRLF . print_r($response, true));
|
||||
}
|
||||
} // xmlrpc_auth_cb
|
||||
?>
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<settings>
|
||||
<!-- MySQL Server Settings -->
|
||||
<mysql_server>@MYSQL_HOST@</mysql_server>
|
||||
<mysql_login>@MYSQL_LOGIN@</mysql_login>
|
||||
<mysql_password>@MYSQL_PASSWORD@</mysql_password>
|
||||
<mysql_database>@MYSQL_DATABASE@</mysql_database>
|
||||
<!-- Do you want XASECO to display newly driven records? -->
|
||||
<display>true</display>
|
||||
<!-- Limit the highest record that will be displayed to all? -->
|
||||
<!-- If lower than $maxrecs, records above this limit will -->
|
||||
<!-- only be displayed to the pertaining player -->
|
||||
<limit>50</limit>
|
||||
|
||||
<messages>
|
||||
<!-- record messages -->
|
||||
<record_new>{#server}>> {#highlite}{1}{#record} secured his/her {#rank}{2}{#record}. Local Record! {3}: {#highlite}{4}{#record} $n({#rank}{5}{#highlite}{6}{#record})</record_new>
|
||||
<record_equal>{#server}>> {#highlite}{1}{#record} equaled his/her {#rank}{2}{#record}. Local Record! {3}: {#highlite}{4}</record_equal>
|
||||
<record_new_rank>{#server}>> {#highlite}{1}{#record} gained the {#rank}{2}{#record}. Local Record! {3}: {#highlite}{4}{#record} $n({#rank}{5}{#highlite}{6}{#record})</record_new_rank>
|
||||
<record_first>{#server}>> {#highlite}{1}{#record} claimed the {#rank}{2}{#record}. Local Record! {3}: {#highlite}{4}</record_first>
|
||||
</messages>
|
||||
</settings>
|
|
@ -0,0 +1,60 @@
|
|||
-- Database: `aseco`
|
||||
--
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tablestructure for Table `challenges`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `challenges` (
|
||||
`Id` mediumint(9) NOT NULL auto_increment,
|
||||
`Uid` varchar(27) NOT NULL default '',
|
||||
`Date` datetime NOT NULL default '1970-01-01 00:00:00',
|
||||
`Name` varchar(100) NOT NULL default '',
|
||||
`Author` varchar(30) NOT NULL default '',
|
||||
`Environment` varchar(10) NOT NULL default '',
|
||||
`BronzeTime` int(11) NOT NULL default 0,
|
||||
`SilverTime` int(11) NOT NULL default 0,
|
||||
`GoldTime` int(11) NOT NULL default 0,
|
||||
`AuthorTime` int(11) NOT NULL default 0,
|
||||
PRIMARY KEY (`Id`),
|
||||
UNIQUE KEY `Uid` (`Uid`)
|
||||
) ENGINE=MyISAM;
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tablestructure for Table `players`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `players` (
|
||||
`Id` mediumint(9) NOT NULL auto_increment,
|
||||
`Login` varchar(50) NOT NULL default '',
|
||||
`Game` varchar(3) NOT NULL default '',
|
||||
`NickName` varchar(100) NOT NULL default '',
|
||||
`Nation` varchar(3) NOT NULL default '',
|
||||
`UpdatedAt` datetime NOT NULL default '1970-01-01 00:00:00',
|
||||
`Wins` mediumint(9) NOT NULL default 0,
|
||||
`TimePlayed` int(10) unsigned NOT NULL default 0,
|
||||
`TeamName` char(60) NOT NULL default '',
|
||||
PRIMARY KEY (`Id`),
|
||||
UNIQUE KEY `Login` (`Login`),
|
||||
KEY `Game` (`Game`)
|
||||
) ENGINE=MyISAM;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tablestructure for Table `records`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `records` (
|
||||
`Id` int(11) NOT NULL auto_increment,
|
||||
`ChallengeId` mediumint(9) NOT NULL default 0,
|
||||
`PlayerId` mediumint(9) NOT NULL default 0,
|
||||
`Score` int(11) NOT NULL default 0,
|
||||
`Date` datetime NOT NULL default '1970-01-01 00:00:00',
|
||||
`Checkpoints` text NOT NULL,
|
||||
PRIMARY KEY (`Id`),
|
||||
UNIQUE KEY `PlayerId` (`PlayerId`,`ChallengeId`),
|
||||
KEY `ChallengeId` (`ChallengeId`)
|
||||
) ENGINE=MyISAM;
|
|
@ -0,0 +1,18 @@
|
|||
-- Database: `aseco`
|
||||
--
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tablestructure for Table `players_extra`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `players_extra` (
|
||||
`playerID` mediumint(9) NOT NULL default 0,
|
||||
`cps` smallint(3) NOT NULL default -1,
|
||||
`dedicps` smallint(3) NOT NULL default -1,
|
||||
`donations` mediumint(9) NOT NULL default 0,
|
||||
`style` varchar(20) NOT NULL default '',
|
||||
`panels` varchar(255) NOT NULL default '',
|
||||
PRIMARY KEY (`playerID`),
|
||||
KEY `donations` (`donations`)
|
||||
) ENGINE=MyISAM;
|
|
@ -0,0 +1,47 @@
|
|||
-- Database: `aseco`
|
||||
--
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tablestructure for Table `rs_karma`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `rs_karma` (
|
||||
`Id` int(11) NOT NULL auto_increment,
|
||||
`ChallengeId` mediumint(9) NOT NULL default 0,
|
||||
`PlayerId` mediumint(9) NOT NULL default 0,
|
||||
`Score` tinyint(4) NOT NULL default 0,
|
||||
PRIMARY KEY (`Id`),
|
||||
UNIQUE KEY `PlayerId` (`PlayerId`,`ChallengeId`),
|
||||
KEY `ChallengeId` (`ChallengeId`)
|
||||
) ENGINE=MyISAM;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tablestructure for Table `rs_rank`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `rs_rank` (
|
||||
`playerID` mediumint(9) NOT NULL default 0,
|
||||
`avg` float NOT NULL default 0,
|
||||
KEY `playerID` (`playerID`)
|
||||
) ENGINE=MyISAM;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tablestructure for Table `rs_times`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `rs_times` (
|
||||
`ID` int(11) NOT NULL auto_increment,
|
||||
`challengeID` mediumint(9) NOT NULL default 0,
|
||||
`playerID` mediumint(9) NOT NULL default 0,
|
||||
`score` int(11) NOT NULL default 0,
|
||||
`date` int(10) unsigned NOT NULL default 0,
|
||||
`checkpoints` text NOT NULL,
|
||||
PRIMARY KEY (`ID`),
|
||||
KEY `playerID` (`playerID`,`challengeID`),
|
||||
KEY `challengeID` (`challengeID`)
|
||||
) ENGINE=MyISAM;
|
|
@ -0,0 +1,34 @@
|
|||
Panels
|
||||
======
|
||||
|
||||
This directory holds Admin, Donate, Records and Vote panel templates,
|
||||
managed by plugin.panels.php.
|
||||
Templates define the complete ManiaLink panel with position, size and
|
||||
fonts, so you have full control to develop custom panels.
|
||||
|
||||
To create a new template, copy an existing one to a new filename and
|
||||
edit that, as the existing set will be overwritten in future releases.
|
||||
|
||||
Use ManiaLink http://smurf1.free.fr/mle/index.xml
|
||||
and webpage http://smurf1.free.fr/mle/list.php
|
||||
to select styles and fonts. Note that not every (sub)style and font
|
||||
fits everywhere due to size variations.
|
||||
|
||||
New Admin templates must stick to manialink id="3" and preserve
|
||||
action="21" through action="27" for the buttons.
|
||||
|
||||
New Donate templates must stick to manialink id="6" and preserve
|
||||
action="30" through action="36" for the buttons.
|
||||
|
||||
New Record templates must stick to manialink id="4" and preserve the
|
||||
mapping of text="%PB%" to action="7", "%LCL%" to "8", "%DED%" to "9"
|
||||
and "%TMX%" to "10".
|
||||
|
||||
New Vote templates must stick to manialink id="5" and preserve
|
||||
action="18" for the Yes button and action="19" for the No button.
|
||||
|
||||
If you create a nice template for any panel that's sufficiently distinct
|
||||
from the standard ones, send it to me and I might include it in the
|
||||
next XAseco release. :)
|
||||
|
||||
Xymph
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="48.1 -28.5 0">
|
||||
<quad sizen="16 3.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="0.8 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="2.9 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="5.0 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="7.1 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="9.0 -0.2 2" sizen="2.4 3.3" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="10.8 -0.2 2" sizen="2.4 3.3" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="12.9 -0.3 2" sizen="2.4 3" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="34.1 -27.8 0">
|
||||
<quad sizen="30 4.2" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="1 -0.6 2" sizen="3 3" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="5 -0.6 2" sizen="3 3" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="9 -0.6 2" sizen="3 3" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="13 -0.6 2" sizen="3 3.1" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="17 -0.2 2" sizen="3.5 4" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="21 -0.2 2" sizen="3.5 4" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="25.2 -0.2 2" sizen="3.5 4" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="-56 -29.2 0">
|
||||
<quad sizen="16 3.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="0.8 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="2.9 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="5.0 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="7.1 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="9.0 -0.2 2" sizen="2.4 3.3" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="10.8 -0.2 2" sizen="2.4 3.3" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="12.9 -0.3 2" sizen="2.4 3" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="-56 -28.5 0">
|
||||
<quad sizen="30 4.2" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="1 -0.6 2" sizen="3 3" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="5 -0.6 2" sizen="3 3" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="9 -0.6 2" sizen="3 3" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="13 -0.6 2" sizen="3 3.1" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="17 -0.2 2" sizen="3.5 4" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="21 -0.2 2" sizen="3.5 4" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="25.2 -0.2 2" sizen="3.5 4" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="54.4 -33.5 0">
|
||||
<quad sizen="10.4 6.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="0.8 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="2.9 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="5.0 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="7.1 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="1.0 -2.9 2" sizen="2.5 3.4" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="3.5 -2.9 2" sizen="2.5 3.4" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="6.6 -3.0 2" sizen="2.3 3" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,11 @@
|
|||
<!-- admin panel made by nouseforname -->
|
||||
<manialink id="3"><frame posn="48.6 -35 5">
|
||||
<quad sizen="16 3.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="0.8 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="2.9 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="5.0 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="7.1 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="9.0 -0.2 2" sizen="2.4 3.3" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="10.8 -0.2 2" sizen="2.4 3.3" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="12.8 -0.3 2" sizen="2.4 3" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="-33.5 -45.6 0">
|
||||
<quad sizen="21.8 2.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="1 -0.4 2" sizen="1.7 1.7" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="4 -0.4 2" sizen="1.7 1.7" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="7 -0.4 2" sizen="1.7 1.7" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="10 -0.4 2" sizen="1.7 1.8" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="13 0.1 2" sizen="2.1 2.8" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="16 0.1 2" sizen="2.1 2.8" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="19.1 -0.2 2" sizen="1.8 2.1" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="-7.9 -34.9 0">
|
||||
<quad sizen="16 3.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="0.8 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="2.9 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="5.0 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="7.1 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="9.0 -0.2 2" sizen="2.4 3.3" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="10.8 -0.2 2" sizen="2.4 3.3" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="12.9 -0.3 2" sizen="2.4 3" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="-11.4 -34.2 0">
|
||||
<quad sizen="23 4.2" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="1 -0.6 2" sizen="3 3" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="4 -0.6 2" sizen="3 3" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="7 -0.6 2" sizen="3 3" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="10 -0.6 2" sizen="3 3.1" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="13 -0.1 2" sizen="3.5 4" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="16 -0.1 2" sizen="3.5 4" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="19.2 -0.2 2" sizen="3.2 3.5" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="-64.8 37.1 0">
|
||||
<quad sizen="14.1 3.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="1.1 -0.8 2" sizen="1.7 1.8" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="3.0 -0.8 2" sizen="1.7 1.8" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="4.9 -0.8 2" sizen="1.7 1.8" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="6.7 -0.8 2" sizen="1.7 1.8" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="8.5 -0.4 2" sizen="1.9 2.6" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="10.1 -0.4 2" sizen="1.9 2.6" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="11.9 -0.4 2" sizen="1.8 2.4" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="-64.8 37.1 0">
|
||||
<quad sizen="14.1 3.5" style="Bgs1" substyle="NavButton"/>
|
||||
<quad posn="1.1 -0.8 2" sizen="1.7 1.8" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="3.0 -0.8 2" sizen="1.7 1.8" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="4.9 -0.8 2" sizen="1.7 1.8" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="6.7 -0.8 2" sizen="1.7 1.8" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="8.5 -0.4 2" sizen="1.9 2.6" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="10.1 -0.4 2" sizen="1.9 2.6" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="11.9 -0.4 2" sizen="1.8 2.4" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="-64.8 5.5 0">
|
||||
<quad sizen="4.6 29.6" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="0.9 -1 2" sizen="3 3" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="1.0 -5 2" sizen="3 3" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="1.0 -9 2" sizen="3 3" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="1.0 -13 2" sizen="3 3.1" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="0.8 -16 2" sizen="3.4 5" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="0.8 -20 2" sizen="3.4 5" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="1.0 -25 2" sizen="3.2 4" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="60.1 5.5 0">
|
||||
<quad sizen="4.6 29.6" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="0.6 -1 2" sizen="3 3" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="0.7 -5 2" sizen="3 3" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="0.7 -9 2" sizen="3 3" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="0.6 -13 2" sizen="3 3.1" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="0.5 -16 2" sizen="3.4 5" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="0.5 -20 2" sizen="3.4 5" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="0.6 -25 2" sizen="3.2 4" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="-12.1 44.2 0">
|
||||
<quad sizen="16 3.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="0.8 -0.8 2" sizen="2 2" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="2.9 -0.8 2" sizen="2 2" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="5.0 -0.8 2" sizen="2 2" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="7.1 -0.8 2" sizen="2 2.1" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="9.0 -0.2 2" sizen="2.4 3.3" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="10.8 -0.2 2" sizen="2.4 3.3" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="13.0 -0.3 2" sizen="2.4 3" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="3"><frame posn="-12.1 44.2 0">
|
||||
<quad sizen="23 4.2" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="1 -0.6 2" sizen="3 3" style="Icons64x64_1" substyle="ClipRewind" action="21"/>
|
||||
<quad posn="4 -0.6 2" sizen="3 3" style="Icons64x64_1" substyle="ClipPause" action="22"/>
|
||||
<quad posn="7 -0.6 2" sizen="3 3" style="Icons64x64_1" substyle="ClipPlay" action="23"/>
|
||||
<quad posn="10 -0.6 2" sizen="3 3.1" style="Icons64x64_1" substyle="Refresh" action="24"/>
|
||||
<quad posn="13 -0.1 2" sizen="3.5 4" style="Icons64x64_1" substyle="ArrowGreen" action="25"/>
|
||||
<quad posn="16 -0.1 2" sizen="3.5 4" style="Icons64x64_1" substyle="ArrowRed" action="26"/>
|
||||
<quad posn="19.2 -0.2 2" sizen="3 3.5" style="Icons64x64_1" substyle="Buddy" action="27"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="6"><frame posn="11.7 -45.6 0">
|
||||
<quad sizen="40.8 2.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="1.5 -0.3 2" sizen="2 2" style="Icons128x128_1" substyle="Coppers"/>
|
||||
<label posn="4.5 -0.6 2" textsize="1" textcolor="dddf" text="$f6fDonate:"/>
|
||||
<format textsize="1" textcolor="ffff"/>
|
||||
<label posn="11 -0.6 2" sizen="2.4 1.5" text="%COP1% C" action="30"/>
|
||||
<label posn="14.5 -0.6 2" sizen="2.4 1.5" text="%COP2% C" action="31"/>
|
||||
<label posn="18 -0.6 2" sizen="3 1.5" text="%COP3% C" action="32"/>
|
||||
<label posn="22 -0.6 2" sizen="3 1.5" text="%COP4% C" action="33"/>
|
||||
<label posn="26 -0.6 2" sizen="3 1.5" text="%COP5% C" action="34"/>
|
||||
<label posn="30 -0.6 2" sizen="4 1.5" text="%COP6% C" action="35"/>
|
||||
<label posn="35 -0.6 2" sizen="4 1.5" text="%COP7% C" action="36"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="6"><frame posn="11.7 -45.6 0">
|
||||
<quad sizen="40.8 2.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="1.5 -0.3 2" sizen="2 2" style="Icons128x128_1" substyle="Coppers"/>
|
||||
<label posn="4.4 -0.6 2" textsize="1" textcolor="dddf" text="$ccc$s$oDonate:$fff"/>
|
||||
<format textsize="1" textcolor="ffff"/>
|
||||
<label posn="11 -0.6 2" sizen="2.4 1.5" style="TextRaceChrono" scale="1.25" text="$s$abc%COP1%C" action="30"/>
|
||||
<label posn="14.5 -0.6 2" sizen="2.4 1.5" style="TextRaceChrono" scale="1.25" text="$s$aaa%COP2%C" action="31"/>
|
||||
<label posn="18 -0.6 2" sizen="3 1.5" style="TextRaceChrono" scale="1.25" text="$s$a98%COP3%C" action="32"/>
|
||||
<label posn="22 -0.6 2" sizen="3 1.5" style="TextRaceChrono" scale="1.25" text="$s$a86%COP4%C" action="33"/>
|
||||
<label posn="26 -0.6 2" sizen="3 1.5" style="TextRaceChrono" scale="1.25" text="$s$a74%COP5%C" action="34"/>
|
||||
<label posn="30 -0.6 2" sizen="4 1.5" style="TextRaceChrono" scale="1.25" text="$s$a62%COP6%C" action="35"/>
|
||||
<label posn="35 -0.6 2" sizen="4 1.5" style="TextRaceChrono" scale="1.25" text="$s$a50%COP7%C" action="36"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="6"><frame posn="-64.8 5.5 0">
|
||||
<quad sizen="7.5 29.6" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="2 -0.5 2" sizen="4 4" style="Icons128x128_1" substyle="Coppers"/>
|
||||
<label posn="1 -5 2" textsize="2" textcolor="dddf" text="$f6fDonate:"/>
|
||||
<format textsize="2" textcolor="ffff"/>
|
||||
<label posn="6.5 -8 2" sizen="3.8 2" halign="right" text="%COP1% C" action="30"/>
|
||||
<label posn="6.5 -11 2" sizen="3.8 2" halign="right" text="%COP2% C" action="31"/>
|
||||
<label posn="6.5 -14 2" sizen="4.8 2" halign="right" text="%COP3% C" action="32"/>
|
||||
<label posn="6.5 -17 2" sizen="4.8 2" halign="right" text="%COP4% C" action="33"/>
|
||||
<label posn="6.5 -20 2" sizen="4.8 2" halign="right" text="%COP5% C" action="34"/>
|
||||
<label posn="6.5 -23 2" sizen="5.8 2" halign="right" text="%COP6% C" action="35"/>
|
||||
<label posn="6.5 -26 2" sizen="5.8 2" halign="right" text="%COP7% C" action="36"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="6"><frame posn="-64.8 5.5 0">
|
||||
<quad sizen="7.5 29.6" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="2 -0.5 2" sizen="4 4" style="Icons128x128_1" substyle="Coppers"/>
|
||||
<label posn="1 -5 2" style="TextCardSmallScores2Rank" text="$f6fDonate:"/>
|
||||
<format style="TextCardSmallScores2"/>
|
||||
<label posn="6.5 -8 2" sizen="3.8 2" halign="right" text="%COP1% C" action="30"/>
|
||||
<label posn="6.5 -11 2" sizen="3.8 2" halign="right" text="%COP2% C" action="31"/>
|
||||
<label posn="6.5 -14 2" sizen="4.8 2" halign="right" text="%COP3% C" action="32"/>
|
||||
<label posn="6.5 -17 2" sizen="4.8 2" halign="right" text="%COP4% C" action="33"/>
|
||||
<label posn="6.5 -20 2" sizen="4.8 2" halign="right" text="%COP5% C" action="34"/>
|
||||
<label posn="6.5 -23 2" sizen="5.8 2" halign="right" text="%COP6% C" action="35"/>
|
||||
<label posn="6.5 -26 2" sizen="5.8 2" halign="right" text="%COP7% C" action="36"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<!-- donate panel made by nouseforname -->
|
||||
<manialink id="6"><frame posn="-64.8 -4.5 0">
|
||||
<quad sizen="7.7 19.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<label posn="1 -0.8 2" style="TextCardSmallScores2Rank" text="$f6fDonate:"/>
|
||||
<format style="TextCardSmallScores2"/>
|
||||
<label posn="6.5 -3.5 2" sizen="3.8 2" halign="right" text="%COP1% C" action="30"/>
|
||||
<label posn="6.5 -5.7 2" sizen="3.8 2" halign="right" text="%COP2% C" action="31"/>
|
||||
<label posn="6.5 -7.9 2" sizen="4.8 2" halign="right" text="%COP3% C" action="32"/>
|
||||
<label posn="6.5 -10.1 2" sizen="4.8 2" halign="right" text="%COP4% C" action="33"/>
|
||||
<label posn="6.5 -12.3 2" sizen="4.8 2" halign="right" text="%COP5% C" action="34"/>
|
||||
<label posn="6.5 -14.5 2" sizen="5.8 2" halign="right" text="%COP6% C" action="35"/>
|
||||
<label posn="6.5 -16.7 2" sizen="5.8 2" halign="right" text="%COP7% C" action="36"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="6"><frame posn="57.2 5.5 0">
|
||||
<quad sizen="7.5 29.6" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="1.6 -0.5 2" sizen="4 4" style="Icons128x128_1" substyle="Coppers"/>
|
||||
<label posn="0.5 -5 2" textsize="2" textcolor="dddf" text="$f6fDonate:"/>
|
||||
<format textsize="2" textcolor="ffff"/>
|
||||
<label posn="6.3 -8 2" sizen="3.8 2" halign="right" text="%COP1% C" action="30"/>
|
||||
<label posn="6.3 -11 2" sizen="3.8 2" halign="right" text="%COP2% C" action="31"/>
|
||||
<label posn="6.3 -14 2" sizen="4.8 2" halign="right" text="%COP3% C" action="32"/>
|
||||
<label posn="6.3 -17 2" sizen="4.8 2" halign="right" text="%COP4% C" action="33"/>
|
||||
<label posn="6.3 -20 2" sizen="4.8 2" halign="right" text="%COP5% C" action="34"/>
|
||||
<label posn="6.3 -23 2" sizen="5.8 2" halign="right" text="%COP6% C" action="35"/>
|
||||
<label posn="6.3 -26 2" sizen="5.8 2" halign="right" text="%COP7% C" action="36"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="6"><frame posn="57.2 5.5 0">
|
||||
<quad sizen="7.5 29.6" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="1.6 -0.5 2" sizen="4 4" style="Icons128x128_1" substyle="Coppers"/>
|
||||
<label posn="0.5 -5 2" style="TextCardSmallScores2Rank" text="$f6fDonate:"/>
|
||||
<format style="TextCardSmallScores2"/>
|
||||
<label posn="6.3 -8 2" sizen="3.8 2" halign="right" text="%COP1% C" action="30"/>
|
||||
<label posn="6.3 -11 2" sizen="3.8 2" halign="right" text="%COP2% C" action="31"/>
|
||||
<label posn="6.3 -14 2" sizen="4.8 2" halign="right" text="%COP3% C" action="32"/>
|
||||
<label posn="6.3 -17 2" sizen="4.8 2" halign="right" text="%COP4% C" action="33"/>
|
||||
<label posn="6.3 -20 2" sizen="4.8 2" halign="right" text="%COP5% C" action="34"/>
|
||||
<label posn="6.3 -23 2" sizen="5.8 2" halign="right" text="%COP6% C" action="35"/>
|
||||
<label posn="6.3 -26 2" sizen="5.8 2" halign="right" text="%COP7% C" action="36"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<!-- donate panel made by nouseforname -->
|
||||
<manialink id="6"><frame posn="57.2 -4.5 0">
|
||||
<quad sizen="7.7 19.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<label posn="0.5 -0.8 2" style="TextCardSmallScores2Rank" text="$f6fDonate:"/>
|
||||
<format style="TextCardSmallScores2"/>
|
||||
<label posn="6.3 -3.5 2" sizen="3.8 2" halign="right" text="%COP1% C" action="30"/>
|
||||
<label posn="6.3 -5.7 2" sizen="3.8 2" halign="right" text="%COP2% C" action="31"/>
|
||||
<label posn="6.3 -7.9 2" sizen="4.8 2" halign="right" text="%COP3% C" action="32"/>
|
||||
<label posn="6.3 -10.1 2" sizen="4.8 2" halign="right" text="%COP4% C" action="33"/>
|
||||
<label posn="6.3 -12.3 2" sizen="4.8 2" halign="right" text="%COP5% C" action="34"/>
|
||||
<label posn="6.3 -14.5 2" sizen="5.8 2" halign="right" text="%COP6% C" action="35"/>
|
||||
<label posn="6.3 -16.7 2" sizen="5.8 2" halign="right" text="%COP7% C" action="36"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="6"><frame posn="-64.2 48.2 0">
|
||||
<quad sizen="39.5 2.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<quad posn="1 -0.2 2" sizen="2 2" style="Icons128x128_1" substyle="Coppers"/>
|
||||
<label posn="4 -0.4 2" textsize="1" textcolor="dddf" text="$f6fDonate:"/>
|
||||
<format textsize="1" textcolor="ffff"/>
|
||||
<label posn="10 -0.4 2" sizen="2.4 1.5" text="%COP1% C" action="30"/>
|
||||
<label posn="13.5 -0.4 2" sizen="2.4 1.5" text="%COP2% C" action="31"/>
|
||||
<label posn="17 -0.4 2" sizen="3 1.5" text="%COP3% C" action="32"/>
|
||||
<label posn="21 -0.4 2" sizen="3 1.5" text="%COP4% C" action="33"/>
|
||||
<label posn="25 -0.4 2" sizen="3 1.5" text="%COP5% C" action="34"/>
|
||||
<label posn="29 -0.4 2" sizen="4 1.5" text="%COP6% C" action="35"/>
|
||||
<label posn="34 -0.4 2" sizen="4 1.5" text="%COP7% C" action="36"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="14 11.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format style="TextCardSmallScores2Rank"/>
|
||||
<label posn="6.0 -1.0 2" sizen="4.5 2" halign="right" text="PB:"/>
|
||||
<label posn="6.0 -3.5 2" sizen="4.5 2" halign="right" text="Local:"/>
|
||||
<label posn="6.0 -6.0 2" sizen="4.5 2" halign="right" text="Dedi:"/>
|
||||
<label posn="6.0 -8.5 2" sizen="4.5 2" halign="right" text="TMX:"/>
|
||||
<format style="TextSubTitle2"/>
|
||||
<label posn="6.5 -1.0 2" sizen="6.5 2" halign="left" text="%PB%" action="7"/>
|
||||
<label posn="6.5 -3.5 2" sizen="6.5 2" halign="left" text="%LCL%" action="8"/>
|
||||
<label posn="6.5 -6.0 2" sizen="6.5 2" halign="left" text="%DED%" action="9"/>
|
||||
<label posn="6.5 -8.5 2" sizen="6.5 2" halign="left" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="14 11.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format style="TextCardSmallScores2Rank"/>
|
||||
<label posn="6.0 -1.0 2" sizen="4.5 2" halign="right" text="PB:"/>
|
||||
<label posn="6.0 -3.5 2" sizen="4.5 2" halign="right" text="Local:"/>
|
||||
<label posn="6.0 -6.0 2" sizen="4.5 2" halign="right" text="Dedi:"/>
|
||||
<label posn="6.0 -8.5 2" sizen="4.5 2" halign="right" text="TMX:"/>
|
||||
<format style="TextButtonMedium"/>
|
||||
<label posn="6.5 -1.0 2" sizen="6.5 2" halign="left" text="%PB%" action="7"/>
|
||||
<label posn="6.5 -3.5 2" sizen="6.5 2" halign="left" text="%LCL%" action="8"/>
|
||||
<label posn="6.5 -6.0 2" sizen="6.5 2" halign="left" text="%DED%" action="9"/>
|
||||
<label posn="6.5 -8.5 2" sizen="6.5 2" halign="left" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="14 11.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format style="TextCardSmallScores2Rank"/>
|
||||
<label posn="6.0 -1.0 2" sizen="4.5 2" halign="right" text="PB:"/>
|
||||
<label posn="6.0 -3.5 2" sizen="4.5 2" halign="right" text="Local:"/>
|
||||
<label posn="6.0 -6.0 2" sizen="4.5 2" halign="right" text="Dedi:"/>
|
||||
<label posn="6.0 -8.5 2" sizen="4.5 2" halign="right" text="TMX:"/>
|
||||
<format style="TextButtonSmall"/>
|
||||
<label posn="6.5 -1.0 2" sizen="6.5 2" halign="left" text="%PB%" action="7"/>
|
||||
<label posn="6.5 -3.5 2" sizen="6.5 2" halign="left" text="%LCL%" action="8"/>
|
||||
<label posn="6.5 -6.0 2" sizen="6.5 2" halign="left" text="%DED%" action="9"/>
|
||||
<label posn="6.5 -8.5 2" sizen="6.5 2" halign="left" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="14 11.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format style="TextCardSmallScores2Rank"/>
|
||||
<label posn="6.0 -1.0 2" sizen="4.5 2" halign="right" text="PB:"/>
|
||||
<label posn="6.0 -3.5 2" sizen="4.5 2" halign="right" text="Local:"/>
|
||||
<label posn="6.0 -6.0 2" sizen="4.5 2" halign="right" text="Dedi:"/>
|
||||
<label posn="6.0 -8.5 2" sizen="4.5 2" halign="right" text="TMX:"/>
|
||||
<format style="TextRaceValueSmall"/>
|
||||
<label posn="6.5 -1.0 2" sizen="6.5 2" halign="left" text="%PB%" action="7"/>
|
||||
<label posn="6.5 -3.5 2" sizen="6.5 2" halign="left" text="%LCL%" action="8"/>
|
||||
<label posn="6.5 -6.0 2" sizen="6.5 2" halign="left" text="%DED%" action="9"/>
|
||||
<label posn="6.5 -8.5 2" sizen="6.5 2" halign="left" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="14 11.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format style="TextCardSmallScores2Rank"/>
|
||||
<label posn="6.0 -1.0 2" sizen="4.5 2" halign="right" text="PB:"/>
|
||||
<label posn="6.0 -3.5 2" sizen="4.5 2" halign="right" text="Local:"/>
|
||||
<label posn="6.0 -6.0 2" sizen="4.5 2" halign="right" text="Dedi:"/>
|
||||
<label posn="6.0 -8.5 2" sizen="4.5 2" halign="right" text="TMX:"/>
|
||||
<format style="TextStaticSmall"/>
|
||||
<label posn="6.5 -1.0 2" sizen="6.5 2" halign="left" text="%PB%" action="7"/>
|
||||
<label posn="6.5 -3.5 2" sizen="6.5 2" halign="left" text="%LCL%" action="8"/>
|
||||
<label posn="6.5 -6.0 2" sizen="6.5 2" halign="left" text="%DED%" action="9"/>
|
||||
<label posn="6.5 -8.5 2" sizen="6.5 2" halign="left" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="14 11.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format style="TextCardSmallScores2Rank"/>
|
||||
<label posn="6.0 -1.0 2" sizen="4.5 2" halign="right" text="PB:"/>
|
||||
<label posn="6.0 -3.5 2" sizen="4.5 2" halign="right" text="Local:"/>
|
||||
<label posn="6.0 -6.0 2" sizen="4.5 2" halign="right" text="Dedi:"/>
|
||||
<label posn="6.0 -8.5 2" sizen="4.5 2" halign="right" text="TMX:"/>
|
||||
<format style="TextTitle3"/>
|
||||
<label posn="6.5 -1.0 2" sizen="6.5 2" halign="left" text="%PB%" action="7"/>
|
||||
<label posn="6.5 -3.5 2" sizen="6.5 2" halign="left" text="%LCL%" action="8"/>
|
||||
<label posn="6.5 -6.0 2" sizen="6.5 2" halign="left" text="%DED%" action="9"/>
|
||||
<label posn="6.5 -8.5 2" sizen="6.5 2" halign="left" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="14 11.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format style="TextCardSmallScores2Rank"/>
|
||||
<label posn="6.0 -1.0 2" sizen="4.5 2" halign="right" text="PB:"/>
|
||||
<label posn="6.0 -3.5 2" sizen="4.5 2" halign="right" text="Local:"/>
|
||||
<label posn="6.0 -6.0 2" sizen="4.5 2" halign="right" text="Dedi:"/>
|
||||
<label posn="6.0 -8.5 2" sizen="4.5 2" halign="right" text="TMX:"/>
|
||||
<format style="TextTips"/>
|
||||
<label posn="6.5 -1.0 2" sizen="6.5 2" halign="left" text="%PB%" action="7"/>
|
||||
<label posn="6.5 -3.5 2" sizen="6.5 2" halign="left" text="%LCL%" action="8"/>
|
||||
<label posn="6.5 -6.0 2" sizen="6.5 2" halign="left" text="%DED%" action="9"/>
|
||||
<label posn="6.5 -8.5 2" sizen="6.5 2" halign="left" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="14 11.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format style="TextCardSmallScores2Rank"/>
|
||||
<label posn="6.0 -1.0 2" sizen="4.5 2" halign="right" text="PB:"/>
|
||||
<label posn="6.0 -3.5 2" sizen="4.5 2" halign="right" text="Local:"/>
|
||||
<label posn="6.0 -6.0 2" sizen="4.5 2" halign="right" text="Dedi:"/>
|
||||
<label posn="6.0 -8.5 2" sizen="4.5 2" halign="right" text="TMX:"/>
|
||||
<format style="TextRaceChat"/>
|
||||
<label posn="6.5 -1.0 2" sizen="6.5 2" halign="left" text="%PB%" action="7"/>
|
||||
<label posn="6.5 -3.5 2" sizen="6.5 2" halign="left" text="%LCL%" action="8"/>
|
||||
<label posn="6.5 -6.0 2" sizen="6.5 2" halign="left" text="%DED%" action="9"/>
|
||||
<label posn="6.5 -8.5 2" sizen="6.5 2" halign="left" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="10.5 9" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format textsize="1" textcolor="dddf"/>
|
||||
<label posn="4.5 -1.5 2" sizen="3.5 2" halign="right" valign="center" text="PB:"/>
|
||||
<label posn="4.5 -3.5 2" sizen="3.5 2" halign="right" valign="center" text="Local:"/>
|
||||
<label posn="4.5 -5.5 2" sizen="3.5 2" halign="right" valign="center" text="Dedi:"/>
|
||||
<label posn="4.5 -7.5 2" sizen="3.5 2" halign="right" valign="center" text="TMX:"/>
|
||||
<format textsize="1" textcolor="ffff"/>
|
||||
<label posn="5.0 -1.5 2" sizen="4.9 2" halign="left" valign="center" text="%PB%" action="7"/>
|
||||
<label posn="5.0 -3.5 2" sizen="4.9 2" halign="left" valign="center" text="%LCL%" action="8"/>
|
||||
<label posn="5.0 -5.5 2" sizen="4.9 2" halign="left" valign="center" text="%DED%" action="9"/>
|
||||
<label posn="5.0 -7.5 2" sizen="4.9 2" halign="left" valign="center" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,11 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="10.5 7.1" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format textsize="1" textcolor="dddf"/>
|
||||
<label posn="4.5 -1.5 2" sizen="3.5 2" halign="right" valign="center" text="PB:"/>
|
||||
<label posn="4.5 -3.5 2" sizen="3.5 2" halign="right" valign="center" text="Local:"/>
|
||||
<label posn="4.5 -5.5 2" sizen="3.5 2" halign="right" valign="center" text="TMX:"/>
|
||||
<format textsize="1" textcolor="ffff"/>
|
||||
<label posn="5.0 -1.5 2" sizen="4.9 2" halign="left" valign="center" text="%PB%" action="7"/>
|
||||
<label posn="5.0 -3.5 2" sizen="4.9 2" halign="left" valign="center" text="%LCL%" action="8"/>
|
||||
<label posn="5.0 -5.5 2" sizen="4.9 2" halign="left" valign="center" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="14 11.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format textsize="2" textcolor="dddf"/>
|
||||
<label posn="6.0 -1.9 2" sizen="4.5 2" halign="right" valign="center" text="PB:"/>
|
||||
<label posn="6.0 -4.4 2" sizen="4.5 2" halign="right" valign="center" text="Local:"/>
|
||||
<label posn="6.0 -6.9 2" sizen="4.5 2" halign="right" valign="center" text="Dedi:"/>
|
||||
<label posn="6.0 -9.4 2" sizen="4.5 2" halign="right" valign="center" text="TMX:"/>
|
||||
<format textsize="2" textcolor="ffff"/>
|
||||
<label posn="6.5 -1.9 2" sizen="6.5 2" halign="left" valign="center" text="%PB%" action="7"/>
|
||||
<label posn="6.5 -4.4 2" sizen="6.5 2" halign="left" valign="center" text="%LCL%" action="8"/>
|
||||
<label posn="6.5 -6.9 2" sizen="6.5 2" halign="left" valign="center" text="%DED%" action="9"/>
|
||||
<label posn="6.5 -9.4 2" sizen="6.5 2" halign="left" valign="center" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,11 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="14 9.0" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format textsize="2" textcolor="dddf"/>
|
||||
<label posn="6.0 -1.9 2" sizen="4.5 2" halign="right" valign="center" text="PB:"/>
|
||||
<label posn="6.0 -4.4 2" sizen="4.5 2" halign="right" valign="center" text="Local:"/>
|
||||
<label posn="6.0 -6.9 2" sizen="4.5 2" halign="right" valign="center" text="TMX:"/>
|
||||
<format textsize="2" textcolor="ffff"/>
|
||||
<label posn="6.5 -1.9 2" sizen="6.5 2" halign="left" valign="center" text="%PB%" action="7"/>
|
||||
<label posn="6.5 -4.4 2" sizen="6.5 2" halign="left" valign="center" text="%LCL%" action="8"/>
|
||||
<label posn="6.5 -6.9 2" sizen="6.5 2" halign="left" valign="center" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,13 @@
|
|||
<manialink id="4"><frame posn="-64.8 23.3 0">
|
||||
<quad sizen="14 11.5" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<format style="TextCardSmallScores2Rank"/>
|
||||
<label posn="6.0 -1.0 2" sizen="4.5 2" halign="right" text="PB:"/>
|
||||
<label posn="6.0 -3.5 2" sizen="4.5 2" halign="right" text="Local:"/>
|
||||
<label posn="6.0 -6.0 2" sizen="4.5 2" halign="right" text="Dedi:"/>
|
||||
<label posn="6.0 -8.5 2" sizen="4.5 2" halign="right" text="TMX:"/>
|
||||
<format style="TextCardSmallScores2"/>
|
||||
<label posn="6.5 -1.0 2" sizen="6.5 2" halign="left" text="%PB%" action="7"/>
|
||||
<label posn="6.5 -3.5 2" sizen="6.5 2" halign="left" text="%LCL%" action="8"/>
|
||||
<label posn="6.5 -6.0 2" sizen="6.5 2" halign="left" text="%DED%" action="9"/>
|
||||
<label posn="6.5 -8.5 2" sizen="6.5 2" halign="left" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,12 @@
|
|||
<manialink id="4"><frame posn="53.5 -32.7 0">
|
||||
<format textsize="1" textcolor="dddf"/>
|
||||
<label posn="4.5 -0.8 2" sizen="4.5 2" halign="right" valign="center" text="PB:"/>
|
||||
<label posn="4.5 -2.6 2" sizen="4.5 2" halign="right" valign="center" text="Local:"/>
|
||||
<label posn="4.5 -4.4 2" sizen="4.5 2" halign="right" valign="center" text="Dedi:"/>
|
||||
<label posn="4.5 -6.2 2" sizen="4.5 2" halign="right" valign="center" text="TMX:"/>
|
||||
<format textsize="1" textcolor="ffff"/>
|
||||
<label posn="5.0 -0.8 2" sizen="6.5 2" halign="left" valign="center" text="%PB%" action="7"/>
|
||||
<label posn="5.0 -2.6 2" sizen="6.5 2" halign="left" valign="center" text="%LCL%" action="8"/>
|
||||
<label posn="5.0 -4.4 2" sizen="6.5 2" halign="left" valign="center" text="%DED%" action="9"/>
|
||||
<label posn="5.0 -6.2 2" sizen="6.5 2" halign="left" valign="center" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,10 @@
|
|||
<manialink id="4"><frame posn="53.5 -32.7 0">
|
||||
<format textsize="1" textcolor="dddf"/>
|
||||
<label posn="4.5 -0.8 2" sizen="4.5 2" halign="right" valign="center" text="PB:"/>
|
||||
<label posn="4.5 -2.6 2" sizen="4.5 2" halign="right" valign="center" text="Local:"/>
|
||||
<label posn="4.5 -4.4 2" sizen="4.5 2" halign="right" valign="center" text="TMX:"/>
|
||||
<format textsize="1" textcolor="ffff"/>
|
||||
<label posn="5.0 -0.8 2" sizen="6.5 2" halign="left" valign="center" text="%PB%" action="7"/>
|
||||
<label posn="5.0 -2.6 2" sizen="6.5 2" halign="left" valign="center" text="%LCL%" action="8"/>
|
||||
<label posn="5.0 -4.4 2" sizen="6.5 2" halign="left" valign="center" text="%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,12 @@
|
|||
<manialink id="4"><frame posn="53.5 -32.7 0">
|
||||
<format textsize="1" textcolor="dddf"/>
|
||||
<label posn="4.5 -0.8 2" sizen="4.5 2" halign="right" valign="center" text="$da2PB:"/>
|
||||
<label posn="4.5 -2.6 2" sizen="4.5 2" halign="right" valign="center" text="$fffLocal:"/>
|
||||
<label posn="4.5 -4.4 2" sizen="4.5 2" halign="right" valign="center" text="$dddDedi:"/>
|
||||
<label posn="4.5 -6.2 2" sizen="4.5 2" halign="right" valign="center" text="$bbbTMX:"/>
|
||||
<format textsize="1" textcolor="ffff"/>
|
||||
<label posn="4.75 -0.75 2" sizen="6.5 2" halign="left" valign="center" style="TextRaceChrono" text="$da2%PB%" action="7"/>
|
||||
<label posn="5.0 -2.7 2" sizen="6.5 2" halign="left" valign="center" style="TextRaceChrono" scale="0.8" text="$fff%LCL%" action="8"/>
|
||||
<label posn="5.0 -4.5 2" sizen="6.5 2" halign="left" valign="center" style="TextRaceChrono" scale="0.8" text="$ddd%DED%" action="9"/>
|
||||
<label posn="5.0 -6.3 2" sizen="6.5 2" halign="left" valign="center" style="TextRaceChrono" scale="0.8" text="$bbb%TMX%" action="10"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,18 @@
|
|||
<manialink id="9">
|
||||
<frame posn="-63.9 -33.1 0">
|
||||
<format textsize="1" textcolor="ddd"/>
|
||||
<quad sizen="10 2.2" posn="2 0 0" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<label posn="7 -0.3" sizen="8 2" halign="center" textcolor="fff" text="Your Stats"/>
|
||||
<quad sizen="14 11.2" posn="0 -1.9 0" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<label posn="6.8 -2.7" halign="right" text="Rank:"/>
|
||||
<label posn="7.2 -2.7" sizen="6 2" textcolor="fff" text="%RANK%"/>
|
||||
<label posn="6.8 -4.7" halign="right" text="Avg:"/>
|
||||
<label posn="7.2 -4.7" textcolor="fff" text="%AVG%"/>
|
||||
<label posn="6.8 -6.7" halign="right" text="Records:"/>
|
||||
<label posn="7.2 -6.7" textcolor="fff" text="%RECS%"/>
|
||||
<label posn="6.8 -8.7" halign="right" text="Wins:"/>
|
||||
<label posn="7.2 -8.7" textcolor="fff" text="%WINS%"/>
|
||||
<label posn="6.8 -10.7" halign="right" text="Played:"/>
|
||||
<label posn="7.2 -10.7" textcolor="fff" text="%PLAY%"/>
|
||||
</frame>
|
||||
</manialink>
|
|
@ -0,0 +1,20 @@
|
|||
<manialink id="9">
|
||||
<frame posn="-63.9 -33.1 0">
|
||||
<format textsize="1" textcolor="ddd"/>
|
||||
<quad sizen="10 2.2" posn="2 0 0" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<label posn="7 -0.3" sizen="8 2" halign="center" textcolor="ffc" text="Your Stats"/>
|
||||
<quad sizen="14 13" posn="0 -1.9 0" style="Bgs1InRace" substyle="NavButton"/>
|
||||
<label posn="6.8 -2.7" halign="right" text="Rank:"/>
|
||||
<label posn="7.2 -2.7" sizen="6 2" textcolor="fff" text="%RANK%"/>
|
||||
<label posn="6.8 -4.7" halign="right" text="Avg:"/>
|
||||
<label posn="7.2 -4.7" textcolor="fff" text="%AVG%"/>
|
||||
<label posn="6.8 -6.7" halign="right" text="Records:"/>
|
||||
<label posn="7.2 -6.7" textcolor="fff" text="%RECS%"/>
|
||||
<label posn="6.8 -8.7" halign="right" text="Wins:"/>
|
||||
<label posn="7.2 -8.7" textcolor="fff" text="%WINS%"/>
|
||||
<label posn="6.8 -10.7" halign="right" text="Played:"/>
|
||||
<label posn="7.2 -10.7" textcolor="fff" text="%PLAY%"/>
|
||||
<label posn="6.8 -12.7" halign="right" text="Donations:"/>
|
||||
<label posn="7.2 -12.7" textcolor="fff" text="%DONS%"/>
|
||||
</frame>
|
||||
</manialink>
|
|
@ -0,0 +1,7 @@
|
|||
<manialink id="5"><frame posn="-56.8 -45.6 0">
|
||||
<quad sizen="10 2.5" style="Bgs1InRace" substyle="BgButtonSmall" halign="center" action="18" actionkey="1"/>
|
||||
<label sizen="5 1.5" posn="0 -0.3 2" style="TextButtonSmall" halign="center" text="%YES%"/>
|
||||
</frame><frame posn="-46 -45.6 0">
|
||||
<quad sizen="10 2.5" style="Bgs1InRace" substyle="BgButtonSmall" halign="center" action="19" actionkey="2"/>
|
||||
<label sizen="5 1.5" posn="0 -0.3 2" style="TextButtonSmall" halign="center" text="%NO%"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,7 @@
|
|||
<manialink id="5"><frame posn="-5 -30 0">
|
||||
<quad sizen="10 3.5" style="Bgs1InRace" substyle="BgButtonSmall" halign="center" action="18" actionkey="1"/>
|
||||
<label sizen="5 2.5" posn="0 -0.8 2" style="TextButtonSmall" halign="center" text="%YES%"/>
|
||||
</frame><frame posn="5.5 -30 0">
|
||||
<quad sizen="10 3.5" style="Bgs1InRace" substyle="BgButtonSmall" halign="center" action="19" actionkey="2"/>
|
||||
<label sizen="5 2.5" posn="0 -0.8 2" style="TextButtonSmall" halign="center" text="%NO%"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,8 @@
|
|||
<!-- vote panel made by nouseforname -->
|
||||
<manialink id="5"><frame posn="-5 -30 0">
|
||||
<quad sizen="10 3.5" style="Bgs1InRace" substyle="NavButton" halign="center" action="18" actionkey="1"/>
|
||||
<label sizen="5 2.5" posn="0 -0.8 2" style="TextButtonSmall" halign="center" text="%YES%"/>
|
||||
</frame><frame posn="5.5 -30 0">
|
||||
<quad sizen="10 3.5" style="Bgs1InRace" substyle="NavButton" halign="center" action="19" actionkey="2"/>
|
||||
<label sizen="5 2.5" posn="0 -0.8 2" style="TextButtonSmall" halign="center" text="%NO%"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,7 @@
|
|||
<manialink id="5"><frame posn="-45 37.1 0">
|
||||
<quad sizen="10 3.5" style="Bgs1InRace" substyle="BgButtonSmall" halign="center" action="18" actionkey="1"/>
|
||||
<label sizen="5 2.5" posn="0 -0.8 2" style="TextButtonSmall" halign="center" text="%YES%"/>
|
||||
</frame><frame posn="-34.5 37.1 0">
|
||||
<quad sizen="10 3.5" style="Bgs1InRace" substyle="BgButtonSmall" halign="center" action="19" actionkey="2"/>
|
||||
<label sizen="5 2.5" posn="0 -0.8 2" style="TextButtonSmall" halign="center" text="%NO%"/>
|
||||
</frame></manialink>
|
|
@ -0,0 +1,7 @@
|
|||
<manialink id="5"><frame posn="-5.8 40 0">
|
||||
<quad sizen="10 3.5" style="Bgs1InRace" substyle="BgButtonSmall" halign="center" action="18" actionkey="1"/>
|
||||
<label sizen="5 2.5" posn="0 -0.8 2" style="TextButtonSmall" halign="center" text="%YES%"/>
|
||||
</frame><frame posn="4.7 40 0">
|
||||
<quad sizen="10 3.5" style="Bgs1InRace" substyle="BgButtonSmall" halign="center" action="19" actionkey="2"/>
|
||||
<label sizen="5 2.5" posn="0 -0.8 2" style="TextButtonSmall" halign="center" text="%NO%"/>
|
||||
</frame></manialink>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,941 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* Chat plugin.
|
||||
* Shows new/online Dedimania world records and their relations on the
|
||||
* current track.
|
||||
* Created by Xymph
|
||||
*
|
||||
* Dependencies: requires plugin.dedimania.php, plugin.checkpoints.php
|
||||
* used by plugin.dedimania.php
|
||||
*/
|
||||
|
||||
Aseco::addChatCommand('helpdedi', 'Displays info about the Dedimania records system');
|
||||
Aseco::addChatCommand('dedihelp', 'Displays info about the Dedimania records system');
|
||||
Aseco::addChatCommand('dedirecs', 'Displays all Dedimania records on current track');
|
||||
if (!INHIBIT_RECCMDS) {
|
||||
Aseco::addChatCommand('dedinew', 'Shows newly driven Dedimania records');
|
||||
Aseco::addChatCommand('dedilive', 'Shows Dedimania records of online players');
|
||||
Aseco::addChatCommand('dedipb', 'Shows your Dedimania personal best on current track');
|
||||
Aseco::addChatCommand('dedifirst', 'Shows first Dedimania record on current track');
|
||||
Aseco::addChatCommand('dedilast', 'Shows last Dedimania record on current track');
|
||||
Aseco::addChatCommand('dedinext', 'Shows next better Dedimania record to beat');
|
||||
Aseco::addChatCommand('dedidiff', 'Shows your difference to first Dedimania record');
|
||||
Aseco::addChatCommand('dedirange', 'Shows difference first to last Dedimania record');
|
||||
}
|
||||
Aseco::addChatCommand('dedicps', 'Sets Dedimania record checkspoints tracking');
|
||||
Aseco::addChatCommand('dedistats', 'Displays Dedimania track statistics');
|
||||
Aseco::addChatCommand('dedicptms', 'Displays all Dedimania records\' checkpoint times');
|
||||
Aseco::addChatCommand('dedisectms', 'Displays all Dedimania records\' sector times');
|
||||
|
||||
function chat_dedihelp($aseco, $command) { chat_helpdedi($aseco, $command); }
|
||||
function chat_helpdedi($aseco, $command) {
|
||||
|
||||
// compile & display help message
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$help = '{#dedimsg}Dedimania$g is an online World Records database for {#black}all$g' . LF;
|
||||
$help .= 'TrackMania games. See its official site at:' . LF;
|
||||
$help .= '{#black}http://www.dedimania.com/SITE/$g and the records database:' . LF;
|
||||
$help .= '{#black}http://www.dedimania.com/tmstats/?do=stat$g .' . LF . LF;
|
||||
$help .= 'Dedimania records are stored per game (TMN, TMU, etc)' . LF;
|
||||
$help .= 'and mode (TimeAttack, Rounds, etc) and shared between' . LF;
|
||||
$help .= 'all servers that operate with Dedimania support.' . LF . LF;
|
||||
$help .= 'The available Dedimania commands are similar to local' . LF;
|
||||
$help .= 'record commands:' . LF;
|
||||
$help .= '{#black}/dedirecs$g, {#black}/dedinew$g, {#black}/dedilive$g, {#black}/dedipb$g, {#black}/dedicps$g, {#black}/dedistats$g,' . LF;
|
||||
$help .= '{#black}/dedifirst$g, {#black}/dedilast$g, {#black}/dedinext$g, {#black}/dedidiff$g, {#black}/dedirange$g' . LF;
|
||||
$help .= 'See the {#black}/helpall$g command for detailed descriptions.';
|
||||
|
||||
// display popup message
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $command['author']->login, $aseco->formatColors($help), 'OK', '', 0);
|
||||
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$header = 'Dedimania information:';
|
||||
$data = array();
|
||||
$data[] = array('{#dedimsg}Dedimania$g is an online World Records database for {#black}all');
|
||||
$data[] = array('TrackMania games. See its official site at:');
|
||||
$data[] = array('{#black}$l[http://www.dedimania.com/SITE/]http://www.dedimania.com/SITE/$l$g and the records database:');
|
||||
$data[] = array('{#black}$l[http://www.dedimania.com/tmstats/?do=stat]http://www.dedimania.com/tmstats/?do=stat$l$g .');
|
||||
$data[] = array();
|
||||
$data[] = array('Dedimania records are stored per game (TMN, TMU, etc)');
|
||||
$data[] = array('and mode (TimeAttack, Rounds, etc) and shared between');
|
||||
$data[] = array('all servers that operate with Dedimania support.');
|
||||
$data[] = array();
|
||||
$data[] = array('The available Dedimania commands are similar to local');
|
||||
$data[] = array('record commands:');
|
||||
$data[] = array('{#black}/dedirecs$g, {#black}/dedinew$g, {#black}/dedilive$g, {#black}/dedipb$g, {#black}/dedicps$g, {#black}/dedistats$g,');
|
||||
$data[] = array('{#black}/dedifirst$g, {#black}/dedilast$g, {#black}/dedinext$g, {#black}/dedidiff$g, {#black}/dedirange$g');
|
||||
$data[] = array();
|
||||
$data[] = array('See the {#black}/helpall$g command for detailed descriptions.');
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink($command['author']->login, $header, array('Icons64x64_1', 'TrackInfo', -0.01), $data, array(0.95), 'OK');
|
||||
}
|
||||
} // chat_helpdedi
|
||||
|
||||
function chat_dedirecs($aseco, $command) {
|
||||
global $dedi_db;
|
||||
|
||||
$player = $command['author'];
|
||||
$login = $player->login;
|
||||
$dedi_recs = $dedi_db['Challenge']['Records'];
|
||||
|
||||
// split params into array
|
||||
$arglist = explode(' ', strtolower(preg_replace('/ +/', ' ', $command['params'])));
|
||||
|
||||
// process optional relations commands
|
||||
if ($arglist[0] == 'help') {
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$help = '{#black}/dedirecs <option>$g shows Dedimania records and relations' . LF;
|
||||
$help .= ' - {#black}help$g, displays this help information' . LF;
|
||||
$help .= ' - {#black}pb$g, your personal best on current track' . LF;
|
||||
$help .= ' - {#black}new$g, newly driven records' . LF;
|
||||
$help .= ' - {#black}live$g, records of online players' . LF;
|
||||
$help .= ' - {#black}first$g, first ranked record on current track' . LF;
|
||||
$help .= ' - {#black}last$g, last ranked record on current track' . LF;
|
||||
$help .= ' - {#black}next$g, next better ranked record to beat' . LF;
|
||||
$help .= ' - {#black}diff$g, your difference to first ranked record' . LF;
|
||||
$help .= ' - {#black}range$g, difference first to last ranked record' . LF;
|
||||
$help .= LF . 'Without an option, the normal records list is displayed.';
|
||||
|
||||
// display popup message
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $aseco->formatColors($help), 'OK', '', 0);
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$header = '{#black}/dedirecs <option>$g shows Dedimania records and relations:';
|
||||
$help = array();
|
||||
$help[] = array('...', '{#black}help',
|
||||
'Displays this help information');
|
||||
$help[] = array('...', '{#black}pb',
|
||||
'Shows your personal best on current track');
|
||||
$help[] = array('...', '{#black}new',
|
||||
'Shows newly driven records');
|
||||
$help[] = array('...', '{#black}live',
|
||||
'Shows records of online players');
|
||||
$help[] = array('...', '{#black}first',
|
||||
'Shows first ranked record on current track');
|
||||
$help[] = array('...', '{#black}last',
|
||||
'Shows last ranked record on current track');
|
||||
$help[] = array('...', '{#black}next',
|
||||
'Shows next better ranked record to beat');
|
||||
$help[] = array('...', '{#black}diff',
|
||||
'Shows your difference to first ranked record');
|
||||
$help[] = array('...', '{#black}range',
|
||||
'Shows difference first to last ranked record');
|
||||
$help[] = array();
|
||||
$help[] = array('Without an option, the normal records list is displayed.');
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink($login, $header, array('Icons64x64_1', 'TrackInfo', -0.01), $help, array(1.2, 0.05, 0.3, 0.85), 'OK');
|
||||
}
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'pb') {
|
||||
chat_dedipb($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'new') {
|
||||
chat_dedinew($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'live') {
|
||||
chat_dedilive($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'first') {
|
||||
chat_dedifirst($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'last') {
|
||||
chat_dedilast($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'next') {
|
||||
chat_dedinext($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'diff') {
|
||||
chat_dedidiff($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'range') {
|
||||
chat_dedirange($aseco, $command);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$total = count($dedi_recs)) {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No Dedimania records found!'), $login);
|
||||
return;
|
||||
}
|
||||
$maxrank = max($dedi_db['ServerMaxRank'], $player->dedirank);
|
||||
|
||||
// display popup window for TMN
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$head = 'Current TOP ' . $maxrank . ' Dedimania Records:' . LF;
|
||||
$msg = '';
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = 1;
|
||||
|
||||
// create list of records
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$cur_record = $dedi_recs[$i];
|
||||
$nick = $cur_record['NickName'];
|
||||
if (!$aseco->settings['lists_colornicks'])
|
||||
$nick = stripColors($nick);
|
||||
$msg .= str_pad($i+1, 2, '0', STR_PAD_LEFT) . '. {#black}'
|
||||
. str_pad($nick, 20) . '$z - '
|
||||
. ((isset($cur_record['NewBest']) && $cur_record['NewBest']) ? '{#black}': '')
|
||||
. formatTime($cur_record['Best']) . LF;
|
||||
if (++$lines > 9) {
|
||||
$player->msgs[] = $aseco->formatColors($head . $msg);
|
||||
$lines = 0;
|
||||
$msg = '';
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if ($msg != '')
|
||||
$player->msgs[] = $aseco->formatColors($head . $msg);
|
||||
|
||||
// display popup message
|
||||
if (count($player->msgs) == 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $player->msgs[1], 'OK', '', 0);
|
||||
} else { // > 2
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $player->msgs[1], 'Close', 'Next', 0);
|
||||
}
|
||||
|
||||
// display ManiaLink window for TMF
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$head = 'Current TOP ' . $maxrank . ' Dedimania Records:';
|
||||
$msg = array();
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
// reserve extra width for $w tags
|
||||
$extra = ($aseco->settings['lists_colornicks'] ? 0.2 : 0);
|
||||
if ($dedi_db['ShowRecLogins'])
|
||||
$player->msgs[0] = array(1, $head, array(1.2+$extra, 0.1, 0.45+$extra, 0.4, 0.25), array('BgRaceScore2', 'Podium'));
|
||||
else
|
||||
$player->msgs[0] = array(1, $head, array(0.8+$extra, 0.1, 0.45+$extra, 0.25), array('BgRaceScore2', 'Podium'));
|
||||
|
||||
// create list of records
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$cur_record = $dedi_recs[$i];
|
||||
$nick = $cur_record['NickName'];
|
||||
if (!$aseco->settings['lists_colornicks'])
|
||||
$nick = stripColors($nick);
|
||||
if ($dedi_db['ShowRecLogins']) {
|
||||
$msg[] = array(str_pad($i+1, 2, '0', STR_PAD_LEFT) . '.',
|
||||
'{#black}' . $nick,
|
||||
'{#login}' . $cur_record['Login'],
|
||||
((isset($cur_record['NewBest']) && $cur_record['NewBest']) ? '{#black}': '') .
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$cur_record['Best'] : formatTime($cur_record['Best'])));
|
||||
} else {
|
||||
$msg[] = array(str_pad($i+1, 2, '0', STR_PAD_LEFT) . '.',
|
||||
'{#black}' . $nick,
|
||||
((isset($cur_record['NewBest']) && $cur_record['NewBest']) ? '{#black}': '') .
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$cur_record['Best'] : formatTime($cur_record['Best'])));
|
||||
}
|
||||
if (++$lines > 14) {
|
||||
$player->msgs[] = $msg;
|
||||
$lines = 0;
|
||||
$msg = array();
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if (!empty($msg))
|
||||
$player->msgs[] = $msg;
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink_multi($player);
|
||||
|
||||
// show chat message for TMO & TMS
|
||||
} else {
|
||||
$top = 4;
|
||||
$msg = $aseco->formatColors("{#server}> Current TOP $top Dedimania Records:{#highlite}");
|
||||
// create list of records
|
||||
$total = ($total <= $top ? $total : $top);
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$cur_record = $dedi_recs[$i];
|
||||
$msg .= LF . ($i+1) . '. ' . str_pad(stripColors($cur_record['NickName']), 15)
|
||||
. ' - ' . formatTime($cur_record['Best']);
|
||||
}
|
||||
// show chat message
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $msg, $login);
|
||||
}
|
||||
} // chat_dedirecs
|
||||
|
||||
|
||||
/*
|
||||
* Universal function to generate list of Dedimania records for current track.
|
||||
* Called by chat_dedinew, chat_dedilive, endRace & beginRace (plugin.dedimania.php).
|
||||
* Show to a player if $login defined, otherwise show to all players.
|
||||
* $mode = 0 (only new), 1 (top-8 & online players at start of track),
|
||||
* 2 (top-6 & online during track), 3 (top-8 & new at end of track)
|
||||
* In modes 1/2/3 the last Dedimania record is also shown
|
||||
* top-8 is configurable via $dedi_db['ShowMinRecs']; top-6 is ShowMinRecs-2
|
||||
*/
|
||||
function show_dedirecs($aseco, $name, $uid, $dedi_recs, $login, $mode, $window) {
|
||||
global $dedi_db, $dedi_debug;
|
||||
|
||||
$records = '$n'; // use narrow font
|
||||
|
||||
if ($dedi_debug > 2)
|
||||
$aseco->console_text('show_dedirecs - dedi_recs' . CRLF . print_r($dedi_recs, true));
|
||||
|
||||
// check for records
|
||||
if (!isset($dedi_recs) || ($total = count($dedi_recs)) == 0) {
|
||||
$totalnew = -1;
|
||||
} else {
|
||||
// check whether to show range
|
||||
if ($dedi_db['ShowRecsRange']) {
|
||||
// get the first & last Dedimania records
|
||||
$first = $dedi_recs[0];
|
||||
$last = $dedi_recs[$total-1];
|
||||
// compute difference between records
|
||||
if ($aseco->server->gameinfo->mode != Gameinfo::STNT) {
|
||||
$diff = $last['Best'] - $first['Best'];
|
||||
$sec = floor($diff/1000);
|
||||
$hun = ($diff - ($sec * 1000)) / 10;
|
||||
} else { // Stunts
|
||||
$diff = $first['Best'] - $last['Best'];
|
||||
}
|
||||
}
|
||||
|
||||
// get list of online players
|
||||
$players = array();
|
||||
foreach ($aseco->server->players->player_list as $pl) {
|
||||
$players[] = $pl->login;
|
||||
}
|
||||
|
||||
// collect new records and records by online players
|
||||
$totalnew = 0;
|
||||
|
||||
// go through each record
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$cur_record = $dedi_recs[$i];
|
||||
|
||||
// if the record is new then display it
|
||||
if (isset($cur_record['NewBest']) && $cur_record['NewBest']) {
|
||||
$totalnew++;
|
||||
$record_msg = formatText($aseco->getChatMessage('RANKING_RECORD_NEW_ON'),
|
||||
$i+1,
|
||||
stripColors($cur_record['NickName']),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$cur_record['Best'] : formatTime($cur_record['Best'])));
|
||||
// always show new record
|
||||
$records .= $record_msg;
|
||||
} else {
|
||||
// check if player is online
|
||||
if (in_array($cur_record['Login'], $players) && $cur_record['Game'] ==
|
||||
($aseco->server->getGame() == 'TMF' ? 'TMU' : $aseco->server->getGame())) {
|
||||
$record_msg = formatText($aseco->getChatMessage('RANKING_RECORD_ON'),
|
||||
$i+1,
|
||||
stripColors($cur_record['NickName']),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$cur_record['Best'] : formatTime($cur_record['Best'])));
|
||||
// check if last Dedimania record
|
||||
if ($mode != 0 && $i == $total-1) {
|
||||
$records .= $record_msg;
|
||||
}
|
||||
// check if always show (start of/during track)
|
||||
elseif ($mode == 1 || $mode == 2) {
|
||||
$records .= $record_msg;
|
||||
}
|
||||
else {
|
||||
// show record if < ShowMinRecs (end of track)
|
||||
if ($mode == 3 && $i < $dedi_db['ShowMinRecs']) {
|
||||
$records .= $record_msg;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$record_msg = formatText($aseco->getChatMessage('RANKING_RECORD'),
|
||||
$i+1,
|
||||
stripColors($cur_record['NickName']),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$cur_record['Best'] : formatTime($cur_record['Best'])));
|
||||
// check if last Dedimania record
|
||||
if ($mode != 0 && $i == $total-1) {
|
||||
$records .= $record_msg;
|
||||
}
|
||||
// show offline record if < ShowMinRecs-2 (during track)
|
||||
elseif (($mode == 2 && $i < $dedi_db['ShowMinRecs']-2) ||
|
||||
// show offline record if < ShowMinRecs (start/end of track)
|
||||
(($mode == 1 || $mode == 3) && $i < $dedi_db['ShowMinRecs'])) {
|
||||
$records .= $record_msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// define wording of the ranking message
|
||||
switch ($mode) {
|
||||
case 0:
|
||||
$timing = 'during';
|
||||
break;
|
||||
case 1:
|
||||
$timing = 'before';
|
||||
break;
|
||||
case 2:
|
||||
$timing = 'during';
|
||||
break;
|
||||
case 3:
|
||||
$timing = 'after';
|
||||
break;
|
||||
}
|
||||
|
||||
// hyperlink track name
|
||||
$name = stripColors($name);
|
||||
if ($aseco->server->getGame() == 'TMF')
|
||||
$name = '$l[http://www.dedimania.com/tmstats/?do=stat&Show=RECORDS&RecOrder3=RANK-ASC&Uid=' . $uid . ']' . $name . '$l';
|
||||
|
||||
// define the ranking message
|
||||
if ($totalnew > 0) {
|
||||
$message = formatText($dedi_db['Messages']['RANKING_NEW'][0],
|
||||
$name, $timing, $totalnew);
|
||||
}
|
||||
elseif ($totalnew == 0 && $records != '$n') {
|
||||
// check whether to show range
|
||||
if ($dedi_db['ShowRecsRange']) {
|
||||
$message = formatText($dedi_db['Messages']['RANKING_RANGE'][0],
|
||||
$name, $timing,
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$diff : sprintf("%d.%02d", $sec, $hun)));
|
||||
} else {
|
||||
$message = formatText($dedi_db['Messages']['RANKING'][0],
|
||||
$name, $timing);
|
||||
}
|
||||
}
|
||||
elseif ($totalnew == 0 && $records == '$n') {
|
||||
$message = formatText($dedi_db['Messages']['RANKING_NONEW'][0],
|
||||
$name, $timing);
|
||||
}
|
||||
else { // $totalnew == -1
|
||||
$message = formatText($dedi_db['Messages']['RANKING_NONE'][0],
|
||||
$name, $timing);
|
||||
}
|
||||
|
||||
// append the records if any
|
||||
if ($records != '$n') {
|
||||
$records = substr($records, 0, strlen($records)-2); // strip trailing ", "
|
||||
$message .= LF . $records;
|
||||
}
|
||||
|
||||
// show to player or all
|
||||
if ($login) {
|
||||
// strip 1 leading '>' to indicate a player message instead of system-wide
|
||||
$message = str_replace('{#server}>> ', '{#server}> ', $message);
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||
} else {
|
||||
if ($window == 2 && function_exists('send_window_message'))
|
||||
send_window_message($aseco, $message, ($mode == 3));
|
||||
else
|
||||
$aseco->client->query('ChatSendServerMessage', $aseco->formatColors($message));
|
||||
}
|
||||
} // show_dedirecs
|
||||
|
||||
function chat_dedinew($aseco, $command) {
|
||||
global $dedi_db;
|
||||
|
||||
// show only newly driven records
|
||||
show_dedirecs($aseco, $aseco->server->challenge->name, $aseco->server->challenge->uid, $dedi_db['Challenge']['Records'], $command['author']->login, 0, 0);
|
||||
} // chat_dedinew
|
||||
|
||||
function chat_dedilive($aseco, $command) {
|
||||
global $dedi_db;
|
||||
|
||||
// show online & ShowMinRecs-2 records
|
||||
show_dedirecs($aseco, $aseco->server->challenge->name, $aseco->server->challenge->uid, $dedi_db['Challenge']['Records'], $command['author']->login, 2, 0);
|
||||
} // chat_dedilive
|
||||
|
||||
function chat_dedipb($aseco, $command) {
|
||||
global $dedi_db;
|
||||
|
||||
$login = $command['author']->login;
|
||||
$dedi_recs = $dedi_db['Challenge']['Records'];
|
||||
|
||||
$found = false;
|
||||
// find Dedimania record
|
||||
for ($i = 0; $i < count($dedi_recs); $i++) {
|
||||
$rec = $dedi_recs[$i];
|
||||
if ($rec['Login'] == $login && $rec['Game'] ==
|
||||
($aseco->server->getGame() == 'TMF' ? 'TMU' : $aseco->server->getGame())) {
|
||||
$score = $rec['Best'];
|
||||
$rank = $i;
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
$message = formatText($dedi_db['Messages']['PB'][0],
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$score : formatTime($score)), $rank+1);
|
||||
$message = $aseco->formatColors($message);
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $message, $login);
|
||||
} else {
|
||||
$message = $dedi_db['Messages']['PB_NONE'][0];
|
||||
$message = $aseco->formatColors($message);
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $message, $login);
|
||||
}
|
||||
} // chat_dedipb
|
||||
|
||||
function chat_dedifirst($aseco, $command) {
|
||||
global $dedi_db;
|
||||
|
||||
$dedi_recs = $dedi_db['Challenge']['Records'];
|
||||
|
||||
if (!empty($dedi_recs)) {
|
||||
// get the first Dedimania record
|
||||
$record = $dedi_recs[0];
|
||||
|
||||
// show chat message
|
||||
$message = formatText($dedi_db['Messages']['FIRST_RECORD'][0])
|
||||
. formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||
1,
|
||||
stripColors($record['NickName']),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$record['Best'] : formatTime($record['Best'])));
|
||||
|
||||
$message = substr($message, 0, strlen($message)-2); // strip trailing ", "
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $command['author']->login);
|
||||
} else {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No Dedimania records found!'), $command['author']->login);
|
||||
}
|
||||
} // chat_dedifirst
|
||||
|
||||
function chat_dedilast($aseco, $command) {
|
||||
global $dedi_db;
|
||||
|
||||
$dedi_recs = $dedi_db['Challenge']['Records'];
|
||||
|
||||
if ($total = count($dedi_recs)) {
|
||||
// get the last Dedimania record
|
||||
$record = $dedi_recs[$total-1];
|
||||
|
||||
// show chat message
|
||||
$message = formatText($dedi_db['Messages']['LAST_RECORD'][0])
|
||||
. formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||
$total,
|
||||
stripColors($record['NickName']),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$record['Best'] : formatTime($record['Best'])));
|
||||
|
||||
$message = substr($message, 0, strlen($message)-2); // strip trailing ", "
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $command['author']->login);
|
||||
} else {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No Dedimania records found!'), $command['author']->login);
|
||||
}
|
||||
} // chat_dedilast
|
||||
|
||||
function chat_dedinext($aseco, $command) {
|
||||
global $dedi_db;
|
||||
|
||||
$login = $command['author']->login;
|
||||
$dedi_recs = $dedi_db['Challenge']['Records'];
|
||||
|
||||
if ($total = count($dedi_recs)) {
|
||||
$found = false;
|
||||
// find Dedimania record
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$rec = $dedi_recs[$i];
|
||||
if ($rec['Login'] == $login && $rec['Game'] ==
|
||||
($aseco->server->getGame() == 'TMF' ? 'TMU' : $aseco->server->getGame())) {
|
||||
$rank = $i;
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
// get current and next better Dedimania records
|
||||
$nextrank = ($rank > 0 ? $rank-1 : 0);
|
||||
$record = $dedi_recs[$rank];
|
||||
$next = $dedi_recs[$nextrank];
|
||||
|
||||
// compute difference to next record
|
||||
if ($aseco->server->gameinfo->mode != Gameinfo::STNT) {
|
||||
$diff = $record['Best'] - $next['Best'];
|
||||
$sec = floor($diff/1000);
|
||||
$hun = ($diff - ($sec * 1000)) / 10;
|
||||
} else { // Stunts mode
|
||||
$diff = $next['Best'] - $record['Best'];
|
||||
}
|
||||
|
||||
// show chat message
|
||||
$message1 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||
$rank+1,
|
||||
stripColors($record['NickName']),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$record['Best'] : formatTime($record['Best'])));
|
||||
$message1 = substr($message1, 0, strlen($message1)-2); // strip trailing ", "
|
||||
$message2 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||
$nextrank+1,
|
||||
stripColors($next['NickName']),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$next['Best'] : formatTime($next['Best'])));
|
||||
$message2 = substr($message2, 0, strlen($message2)-2); // strip trailing ", "
|
||||
$message = formatText($dedi_db['Messages']['DIFF_RECORD'][0],
|
||||
$message1, $message2,
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$diff : sprintf("%d.%02d", $sec, $hun)));
|
||||
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||
} else {
|
||||
// look for unranked time instead
|
||||
$order = ($aseco->server->gameinfo->mode == Gameinfo::STNT ? 'DESC' : 'ASC');
|
||||
$query = 'SELECT score FROM rs_times
|
||||
WHERE playerID=' . $command['author']->id . ' AND
|
||||
challengeID=' . $aseco->server->challenge->id . '
|
||||
ORDER BY score ' . $order . ' LIMIT 1';
|
||||
$result = mysql_query($query);
|
||||
if (mysql_num_rows($result) > 0) {
|
||||
$unranked = mysql_fetch_object($result);
|
||||
$found = true;
|
||||
}
|
||||
mysql_free_result($result);
|
||||
|
||||
if ($found) {
|
||||
// get the last Dedimania record
|
||||
$last = $dedi_recs[$total-1];
|
||||
|
||||
// compute difference to next record
|
||||
if ($aseco->server->gameinfo->mode != Gameinfo::STNT) {
|
||||
$sign = ($unranked->score < $last['Best'] ? '-' : '');
|
||||
$diff = abs($unranked->score - $last['Best']);
|
||||
$sec = floor($diff/1000);
|
||||
$hun = ($diff - ($sec * 1000)) / 10;
|
||||
} else { // Stunts mode
|
||||
$diff = $last['Best'] - $unranked->score;
|
||||
}
|
||||
|
||||
// show chat message
|
||||
$message1 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||
'PB',
|
||||
stripColors($command['author']->nickname),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$unranked->score : formatTime($unranked->score)));
|
||||
$message1 = substr($message1, 0, strlen($message1)-2); // strip trailing ", "
|
||||
$message2 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||
$total,
|
||||
stripColors($last['NickName']),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$last['Best'] : formatTime($last['Best'])));
|
||||
$message2 = substr($message2, 0, strlen($message2)-2); // strip trailing ", "
|
||||
$message = formatText($dedi_db['Messages']['DIFF_RECORD'][0],
|
||||
$message1, $message2,
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$diff : sprintf("%s%d.%02d", $sign, $sec, $hun)));
|
||||
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||
} else {
|
||||
$message = '{#server}> {#error}You don\'t have Dedimania a record on this track yet... use {#highlite}$i/dedilast';
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No Dedimania records found!'), $login);
|
||||
}
|
||||
} // chat_dedinext
|
||||
|
||||
function chat_dedidiff($aseco, $command) {
|
||||
global $dedi_db;
|
||||
|
||||
$login = $command['author']->login;
|
||||
$dedi_recs = $dedi_db['Challenge']['Records'];
|
||||
|
||||
if ($total = count($dedi_recs)) {
|
||||
$found = false;
|
||||
// find Dedimania record
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$rec = $dedi_recs[$i];
|
||||
if ($rec['Login'] == $login && $rec['Game'] ==
|
||||
($aseco->server->getGame() == 'TMF' ? 'TMU' : $aseco->server->getGame())) {
|
||||
$rank = $i;
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
// get current and first Dedimania records
|
||||
$record = $dedi_recs[$rank];
|
||||
$first = $dedi_recs[0];
|
||||
|
||||
// compute difference to first record
|
||||
if ($aseco->server->gameinfo->mode != Gameinfo::STNT) {
|
||||
$diff = $record['Best'] - $first['Best'];
|
||||
$sec = floor($diff/1000);
|
||||
$hun = ($diff - ($sec * 1000)) / 10;
|
||||
} else { // Stunts mode
|
||||
$diff = $first['Best'] - $record['Best'];
|
||||
}
|
||||
|
||||
// show chat message
|
||||
$message1 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||
$rank+1,
|
||||
stripColors($record['NickName']),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$record['Best'] : formatTime($record['Best'])));
|
||||
$message1 = substr($message1, 0, strlen($message1)-2); // strip trailing ", "
|
||||
$message2 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||
1,
|
||||
stripColors($first['NickName']),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$first['Best'] : formatTime($first['Best'])));
|
||||
$message2 = substr($message2, 0, strlen($message2)-2); // strip trailing ", "
|
||||
$message = formatText($dedi_db['Messages']['DIFF_RECORD'][0],
|
||||
$message1, $message2,
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$diff : sprintf("%d.%02d", $sec, $hun)));
|
||||
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||
} else {
|
||||
$message = '{#server}> {#error}You don\'t have a Dedimania record on this track yet... use {#highlite}$i/dedilast';
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||
}
|
||||
} else {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No Dedimania records found!'), $login);
|
||||
}
|
||||
} // chat_dedidiff
|
||||
|
||||
function chat_dedirange($aseco, $command) {
|
||||
global $dedi_db;
|
||||
|
||||
$dedi_recs = $dedi_db['Challenge']['Records'];
|
||||
|
||||
if ($total = count($dedi_recs)) {
|
||||
// get the first & last Dedimania records
|
||||
$first = $dedi_recs[0];
|
||||
$last = $dedi_recs[$total-1];
|
||||
|
||||
// compute difference between records
|
||||
if ($aseco->server->gameinfo->mode != Gameinfo::STNT) {
|
||||
$diff = $last['Best'] - $first['Best'];
|
||||
$sec = floor($diff/1000);
|
||||
$hun = ($diff - ($sec * 1000)) / 10;
|
||||
} else { // Stunts mode
|
||||
$diff = $first['Best'] - $last['Best'];
|
||||
}
|
||||
|
||||
// show chat message
|
||||
$message1 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||
1,
|
||||
stripColors($first['NickName']),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$first['Best'] : formatTime($first['Best'])));
|
||||
$message1 = substr($message1, 0, strlen($message1)-2); // strip trailing ", "
|
||||
$message2 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||
$total,
|
||||
stripColors($last['NickName']),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$last['Best'] : formatTime($last['Best'])));
|
||||
$message2 = substr($message2, 0, strlen($message2)-2); // strip trailing ", "
|
||||
$message = formatText($dedi_db['Messages']['DIFF_RECORD'][0],
|
||||
$message1, $message2,
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$diff : sprintf("%d.%02d", $sec, $hun)));
|
||||
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $command['author']->login);
|
||||
} else {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No Dedimania records found!'), $command['author']->login);
|
||||
}
|
||||
} // chat_dedirange
|
||||
|
||||
function chat_dedicps($aseco, $command) {
|
||||
global $dedi_db, $checkpoints; // from plugin.checkpoints.php
|
||||
|
||||
$login = $command['author']->login;
|
||||
|
||||
if ($aseco->settings['display_checkpoints']) {
|
||||
if (isset($checkpoints[$login]) && $checkpoints[$login]->loclrec != -1) {
|
||||
// set Dedimania checkpoints tracking
|
||||
$param = $command['params'];
|
||||
if (strtolower($param) == 'off') {
|
||||
$checkpoints[$login]->dedirec = -1;
|
||||
$message = '{#server}> {#dedimsg}Dedimania checkpoints tracking: {#highlite}OFF';
|
||||
}
|
||||
elseif ($param == '') {
|
||||
$checkpoints[$login]->dedirec = 0;
|
||||
$message = '{#server}> {#dedimsg}Dedimania checkpoints tracking: {#highlite}ON {#dedimsg}(your own or the last record)';
|
||||
}
|
||||
elseif (is_numeric($param) && $param > 0 && $param <= max($dedi_db['ServerMaxRank'], $command['author']->dedirank)) {
|
||||
$checkpoints[$login]->dedirec = intval($param);
|
||||
$message = '{#server}> {#dedimsg}Dedimania checkpoints tracking record: {#highlite}' . $checkpoints[$login]->dedirec;
|
||||
}
|
||||
else {
|
||||
$message = '{#server}> {#error}No such Dedimania record {#highlite}$i ' . $param;
|
||||
}
|
||||
} else {
|
||||
$message = '{#server}> {#error}You must first enable checkpoints tracking with {#highlite}$i /cps';
|
||||
}
|
||||
} else {
|
||||
$message = '{#server}> {#error}Dedimania checkpoints tracking permanently disabled by server';
|
||||
}
|
||||
// show chat message
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||
} // chat_dedicps
|
||||
|
||||
function chat_dedistats($aseco, $command) {
|
||||
global $dedi_db;
|
||||
|
||||
$login = $command['author']->login;
|
||||
|
||||
// compile & display stats message
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$stats = '{#dedimsg}Dedimania$g Stats: {#black}' . stripColors($aseco->server->challenge->name) . LF . LF;
|
||||
$stats .= '$gServer MaxRank: {#black}$n' . $dedi_db['ServerMaxRank'] . '$m' . LF;
|
||||
$stats .= '$gYour MaxRank : {#black}$n' . $command['author']->dedirank . '$m' . LF . LF;
|
||||
$stats .= '$gUID : {#black}$n' . $dedi_db['Challenge']['Uid'] . '$m' . LF;
|
||||
$stats .= '$gTotal Races : {#black}' . $dedi_db['Challenge']['TotalRaces'] . LF;
|
||||
$stats .= '$gTotal Players : {#black}' . $dedi_db['Challenge']['TotalPlayers'] . LF;
|
||||
$stats .= '$gAvg. Players : {#black}' . ($dedi_db['Challenge']['TotalRaces'] > 0 ? round($dedi_db['Challenge']['TotalPlayers'] / $dedi_db['Challenge']['TotalRaces'], 2) : 0);
|
||||
|
||||
// display popup message
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $aseco->formatColors($stats), 'OK', '', 0);
|
||||
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$header = 'Dedimania Stats: {#black}' . stripColors($aseco->server->challenge->name);
|
||||
$stats = array();
|
||||
$stats[] = array('Server MaxRank', '{#black}' . $dedi_db['ServerMaxRank']);
|
||||
$stats[] = array('Your MaxRank', '{#black}' . $command['author']->dedirank);
|
||||
$stats[] = array();
|
||||
$stats[] = array('UID', '{#black}' . $dedi_db['Challenge']['Uid']);
|
||||
$stats[] = array('Total Races', '{#black}' . $dedi_db['Challenge']['TotalRaces']);
|
||||
$stats[] = array('Total Players', '{#black}' . $dedi_db['Challenge']['TotalPlayers']);
|
||||
$stats[] = array('Avg. Players', '{#black}' . ($dedi_db['Challenge']['TotalRaces'] > 0 ? round($dedi_db['Challenge']['TotalPlayers'] / $dedi_db['Challenge']['TotalRaces'], 2) : 0));
|
||||
$stats[] = array();
|
||||
$stats[] = array(' {#black}$l[http://dedimania.com/tmstats/?do=stat&RecOrder3=RANK-ASC&Uid=' . $dedi_db['Challenge']['Uid'] . '&Show=RECORDS]View all Dedimania records for this track$l');
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink($login, $header, array('Icons64x64_1', 'Maximize', -0.01), $stats, array(1.0, 0.3, 0.7), 'OK');
|
||||
}
|
||||
} // chat_dedistats
|
||||
|
||||
function chat_dedicptms($aseco, $command) {
|
||||
chat_dedisectms($aseco, $command, false);
|
||||
} // chat_dedicptms
|
||||
|
||||
function chat_dedisectms($aseco, $command, $diff = true) {
|
||||
global $dedi_db;
|
||||
|
||||
$player = $command['author'];
|
||||
$login = $player->login;
|
||||
$dedi_recs = $dedi_db['Challenge']['Records'];
|
||||
|
||||
if (!$total = count($dedi_recs)) {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No Dedimania records found!'), $login);
|
||||
return;
|
||||
}
|
||||
$maxrank = max($dedi_db['ServerMaxRank'], $player->dedirank);
|
||||
$cpscnt = count($dedi_recs[0]['Checks']);
|
||||
|
||||
// display popup window for TMN
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$head = 'Current TOP ' . $maxrank . ' Dedimania ' . ($diff ? 'Sector' : 'CP') . ' Times (' . $cpscnt . '):' . LF;
|
||||
$cpsmax = 9;
|
||||
$msg = '';
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = 1;
|
||||
|
||||
// create list of records
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$cur_record = $dedi_recs[$i];
|
||||
$msg .= str_pad($i+1, 2, '0', STR_PAD_LEFT) . '. '
|
||||
. ((isset($cur_record['NewBest']) && $cur_record['NewBest']) ? '{#black}' : '')
|
||||
. formatTime($cur_record['Best']);
|
||||
// append up to $cpsmax sector/CP times
|
||||
if (!empty($cur_record['Checks'])) {
|
||||
$j = 1;
|
||||
$pr = 0;
|
||||
$msg .= '$n';
|
||||
foreach ($cur_record['Checks'] as $cp) {
|
||||
$msg .= ' ' . formatTime($cp - $pr);
|
||||
if ($diff) $pr = $cp;
|
||||
if (++$j > $cpsmax) {
|
||||
if ($cpscnt > $cpsmax) $msg .= ' +';
|
||||
break;
|
||||
}
|
||||
}
|
||||
$msg .= '$m';
|
||||
}
|
||||
$msg .= LF;
|
||||
if (++$lines > 9) {
|
||||
$player->msgs[] = $aseco->formatColors($head . $msg);
|
||||
$lines = 0;
|
||||
$msg = '';
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if ($msg != '')
|
||||
$player->msgs[] = $aseco->formatColors($head . $msg);
|
||||
|
||||
// display popup message
|
||||
if (count($player->msgs) == 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $player->msgs[1], 'OK', '', 0);
|
||||
} else { // > 2
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $player->msgs[1], 'Close', 'Next', 0);
|
||||
}
|
||||
|
||||
// display ManiaLink window for TMF
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$head = 'Current TOP ' . $maxrank . ' Dedimania ' . ($diff ? 'Sector' : 'CP') . ' Times (' . $cpscnt . '):';
|
||||
$cpsmax = 12;
|
||||
// compute widths
|
||||
$width = 0.1 + 0.18 + min($cpscnt, $cpsmax) * 0.1 + ($cpscnt > $cpsmax ? 0.06 : 0.0);
|
||||
if ($width < 1.0) $width = 1.0;
|
||||
$widths = array($width, 0.1, 0.18);
|
||||
for ($i = 0; $i < min($cpscnt, $cpsmax); $i++)
|
||||
$widths[] = 0.1; // cp
|
||||
if ($cpscnt > $cpsmax)
|
||||
$widths[] = 0.06;
|
||||
|
||||
$msg = array();
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = array(1, $head, $widths, array('BgRaceScore2', 'Podium'));
|
||||
|
||||
// create list of records
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$cur_record = $dedi_recs[$i];
|
||||
$line = array();
|
||||
$line[] = str_pad($i+1, 2, '0', STR_PAD_LEFT) . '.';
|
||||
$line[] = ((isset($cur_record['NewBest']) && $cur_record['NewBest']) ? '{#black}' : '')
|
||||
. formatTime($cur_record['Best']);
|
||||
// append up to $cpsmax sector/CP times
|
||||
if (!empty($cur_record['Checks'])) {
|
||||
$j = 1;
|
||||
$pr = 0;
|
||||
foreach ($cur_record['Checks'] as $cp) {
|
||||
$line[] = '$n' . formatTime($cp - $pr);
|
||||
if ($diff) $pr = $cp;
|
||||
if (++$j > $cpsmax) {
|
||||
if ($cpscnt > $cpsmax) $line[] = '+';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$msg[] = $line;
|
||||
if (++$lines > 14) {
|
||||
$player->msgs[] = $msg;
|
||||
$lines = 0;
|
||||
$msg = array();
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if (!empty($msg))
|
||||
$player->msgs[] = $msg;
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink_multi($player);
|
||||
|
||||
// show chat message for TMO & TMS
|
||||
} else {
|
||||
$msg = $aseco->formatColors('{#server}> {#error}No Dedimania ' . ($diff ? 'sector' : 'CP') . ' times available');
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $msg, $login);
|
||||
}
|
||||
} // chat_dedisectms
|
||||
?>
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* Chat plugin.
|
||||
* Displays help for public chat commands.
|
||||
* Updated by Xymph
|
||||
*
|
||||
* Dependencies: none
|
||||
*/
|
||||
|
||||
Aseco::addChatCommand('help', 'Shows all available commands');
|
||||
Aseco::addChatCommand('helpall', 'Displays help for available commands');
|
||||
|
||||
function chat_help($aseco, $command) {
|
||||
|
||||
// show normal chat commands on command line
|
||||
showHelp($command['author'], $aseco->chat_commands, 'chat', false, false);
|
||||
|
||||
// add extra explanation?
|
||||
if ($aseco->settings['help_explanation']) {
|
||||
$message = $aseco->getChatMessage('HELP_EXPLANATION');
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $command['author']->login);
|
||||
}
|
||||
} // chat_help
|
||||
|
||||
function chat_helpall($aseco, $command) {
|
||||
|
||||
// display normal chat commands in popup with descriptions
|
||||
showHelp($command['author'], $aseco->chat_commands, 'chat', false, true, 0.3);
|
||||
} // chat_helpall
|
||||
?>
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* Chat plugin.
|
||||
* Shows last online info.
|
||||
* Created by Xymph
|
||||
*
|
||||
* Dependencies: none
|
||||
*/
|
||||
|
||||
Aseco::addChatCommand('laston', 'Shows when a player was last online');
|
||||
|
||||
function chat_laston($aseco, $command) {
|
||||
|
||||
$player = $command['author'];
|
||||
$target = $player;
|
||||
|
||||
// get player login or ID
|
||||
if ($command['params'] != '')
|
||||
if (!$target = $aseco->getPlayerParam($player, $command['params'], true))
|
||||
return;
|
||||
|
||||
// obtain last online timestamp
|
||||
$query = 'SELECT UpdatedAt FROM players
|
||||
WHERE login=' . quotedString($target->login);
|
||||
$result = mysql_query($query);
|
||||
$laston = mysql_fetch_row($result);
|
||||
mysql_free_result($result);
|
||||
|
||||
// show chat message (strip seconds off timestamp)
|
||||
$message = '{#server}> Player {#highlite}' . $target->nickname .
|
||||
'$z$s{#server} was last online on: {#highlite}' .
|
||||
preg_replace('/:\d\d$/', '', $laston[0]);
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||
} // chat_laston
|
||||
?>
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* Chat plugin.
|
||||
* Re-displays last closed multi-page window.
|
||||
* Created by Xymph
|
||||
*
|
||||
* Dependencies: none
|
||||
*/
|
||||
|
||||
Aseco::addChatCommand('lastwin', 'Re-opens the last closed multi-page window');
|
||||
|
||||
function chat_lastwin($aseco, $command) {
|
||||
|
||||
$player = $command['author'];
|
||||
$login = $player->login;
|
||||
|
||||
if (!isset($player->msgs) || empty($player->msgs)) {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No multi-page window available!'), $login);
|
||||
return;
|
||||
}
|
||||
|
||||
// redisplay popup window for TMN
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$player->msgs[0] = 1; // reset page #
|
||||
// display popup message
|
||||
if (count($player->msgs) == 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $player->msgs[1], 'OK', '', 0);
|
||||
} else { // > 2
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $player->msgs[1], 'Close', 'Next', 0);
|
||||
}
|
||||
|
||||
// redisplay ManiaLink window for TMF
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
// display ManiaLink message
|
||||
display_manialink_multi($player);
|
||||
}
|
||||
} // chat_lastwin
|
||||
?>
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* Chat plugin.
|
||||
* Builds a chat message starting with the player's nickname.
|
||||
* Updated by Xymph
|
||||
*
|
||||
* Dependencies: none
|
||||
*/
|
||||
|
||||
Aseco::addChatCommand('me', 'Can be used to express emotions');
|
||||
|
||||
function chat_me($aseco, $command) {
|
||||
|
||||
$player = $command['author'];
|
||||
|
||||
// check if on global mute list
|
||||
if (in_array($player->login, $aseco->server->mutelist)) {
|
||||
$message = formatText($aseco->getChatMessage('MUTED'), '/me');
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||
return;
|
||||
}
|
||||
|
||||
// replace parameters
|
||||
$message = formatText('$i{1}$z$s$i {#emotic}{2}',
|
||||
$player->nickname, $command['params']);
|
||||
// show chat message
|
||||
$aseco->client->query('ChatSendServerMessage', $aseco->formatColors($message));
|
||||
} // chat_me
|
||||
?>
|
|
@ -0,0 +1,141 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* Chat plugin.
|
||||
* Displays main list of players.
|
||||
* Updated by Xymph
|
||||
*
|
||||
* Dependencies: none
|
||||
*/
|
||||
|
||||
Aseco::addChatCommand('players', 'Displays current list of nicks/logins');
|
||||
|
||||
// handles action id's "2001"-"2200" for /stats
|
||||
Aseco::registerEvent('onPlayerManialinkPageAnswer', 'event_players');
|
||||
|
||||
function chat_players($aseco, $command) {
|
||||
|
||||
// use only first parameter
|
||||
$command['params'] = explode(' ', $command['params'], 2);
|
||||
$player = $command['author'];
|
||||
$player->playerlist = array();
|
||||
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$head = 'Players On This Server:' . LF . 'Id {#nick}Nick $g/{#login} Login $g/{#black} $nNation$m'. LF;
|
||||
$msg = '';
|
||||
$pid = 1;
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = 1;
|
||||
// create list of players, optionally by (sub)string
|
||||
foreach ($aseco->server->players->player_list as $pl) {
|
||||
if (strlen($command['params'][0]) == 0 ||
|
||||
stripos(stripColors($pl->nickname), $command['params'][0]) !== false ||
|
||||
stripos($pl->login, $command['params'][0]) !== false) {
|
||||
$plarr = array();
|
||||
$plarr['login'] = $pl->login;
|
||||
$player->playerlist[] = $plarr;
|
||||
|
||||
$msg .= '$g' . str_pad($pid, 2, '0', STR_PAD_LEFT) . '. {#black}' .
|
||||
str_ireplace('$w', '', $pl->nickname) . '$z / ' .
|
||||
($aseco->isAnyAdmin($pl) ? '{#logina}' : '{#login}') . $pl->login .
|
||||
'$g / {#black}$n' . $pl->nation . '$m' . LF;
|
||||
$pid++;
|
||||
if (++$lines > 9) {
|
||||
$player->msgs[] = $aseco->formatColors($head . $msg);
|
||||
$lines = 0;
|
||||
$msg = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if ($msg != '')
|
||||
$player->msgs[] = $aseco->formatColors($head . $msg);
|
||||
|
||||
// display popup message
|
||||
if (count($player->msgs) == 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'OK', '', 0);
|
||||
} elseif (count($player->msgs) > 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'Close', 'Next', 0);
|
||||
} else { // == 1
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No player(s) found!'), $player->login);
|
||||
}
|
||||
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$head = 'Players On This Server:';
|
||||
$msg = array();
|
||||
$msg[] = array('Id', '{#nick}Nick $g/{#login} Login', '{#black}Nation');
|
||||
$pid = 1;
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = array(1, $head, array(1.3, 0.1, 0.9, 0.3), array('Icons128x128_1', 'Buddies'));
|
||||
// create list of players, optionally by (sub)string
|
||||
foreach ($aseco->server->players->player_list as $pl) {
|
||||
if (strlen($command['params'][0]) == 0 ||
|
||||
stripos(stripColors($pl->nickname), $command['params'][0]) !== false ||
|
||||
stripos($pl->login, $command['params'][0]) !== false) {
|
||||
$plarr = array();
|
||||
$plarr['login'] = $pl->login;
|
||||
$player->playerlist[] = $plarr;
|
||||
|
||||
// format nickname & login
|
||||
$ply = '{#black}' . $pl->nickname . '$z / ' .
|
||||
($aseco->isAnyAdmin($pl) ? '{#logina}' : '{#login}') . $pl->login;
|
||||
// add clickable button
|
||||
if ($aseco->settings['clickable_lists'] && $pid <= 200)
|
||||
$ply = array($ply, $pid+2000); // action id
|
||||
|
||||
$nat = $pl->nation;
|
||||
if (strlen($nat) > 14)
|
||||
$nat = mapCountry($nat);
|
||||
$msg[] = array(str_pad($pid, 2, '0', STR_PAD_LEFT) . '.',
|
||||
$ply, '{#black}' . $nat);
|
||||
$pid++;
|
||||
if (++$lines > 14) {
|
||||
$player->msgs[] = $msg;
|
||||
$lines = 0;
|
||||
$msg = array();
|
||||
$msg[] = array('Id', '{#nick}Nick $g/{#login} Login', '{#black}Nation');
|
||||
}
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if (count($msg) > 1)
|
||||
$player->msgs[] = $msg;
|
||||
|
||||
// display ManiaLink message
|
||||
if (count($player->msgs) > 1) {
|
||||
display_manialink_multi($player);
|
||||
} else { // == 1
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No player(s) found!'), $player->login);
|
||||
}
|
||||
}
|
||||
} // chat_players
|
||||
|
||||
|
||||
// called @ onPlayerManialinkPageAnswer
|
||||
// Handles ManiaLink player responses
|
||||
// [0]=PlayerUid, [1]=Login, [2]=Answer
|
||||
function event_players($aseco, $answer) {
|
||||
|
||||
// leave actions outside 2001 - 2200 to other handlers
|
||||
if ($answer[2] >= 2001 && $answer[2] <= 2200) {
|
||||
// get player
|
||||
$player = $aseco->server->players->getPlayer($answer[1]);
|
||||
$target = $player->playerlist[$answer[2]-2001]['login'];
|
||||
|
||||
// log clicked command
|
||||
$aseco->console('player {1} clicked command "/stats {2}"',
|
||||
$player->login, $target);
|
||||
|
||||
// close main window because /stats can take a while
|
||||
mainwindow_off($aseco, $player->login);
|
||||
// /stats selected player
|
||||
$command = array();
|
||||
$command['author'] = $player;
|
||||
$command['params'] = $target;
|
||||
chat_stats($aseco, $command);
|
||||
}
|
||||
} // event_players
|
||||
?>
|
|
@ -0,0 +1,217 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* Chat plugin.
|
||||
* Displays more lists of players.
|
||||
* Created by Xymph
|
||||
*
|
||||
* Dependencies: none
|
||||
*/
|
||||
|
||||
Aseco::addChatCommand('ranks', 'Displays list of online ranks/nicks');
|
||||
Aseco::addChatCommand('clans', 'Displays list of online clans/nicks');
|
||||
Aseco::addChatCommand('topclans', 'Displays top 10 best ranked clans');
|
||||
|
||||
function chat_ranks($aseco, $command) {
|
||||
global $rasp;
|
||||
|
||||
$player = $command['author'];
|
||||
$ranks = array();
|
||||
|
||||
// sort players by rank, insuring rankless are last by sorting on INT_MAX
|
||||
foreach ($aseco->server->players->player_list as $pl) {
|
||||
$rank = $rasp->getRank($pl->login);
|
||||
$ranks[$pl->login] = $rank != 'None' ?
|
||||
(integer) preg_replace('/\/.*/', '', $rank) :
|
||||
PHP_INT_MAX;
|
||||
}
|
||||
asort($ranks);
|
||||
|
||||
// compile the message
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$head = 'Online Ranks ({#login}rank $g/{#nick} nick$g):' . LF;
|
||||
$msg = '';
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = 1;
|
||||
foreach ($ranks as $pl => $rk) {
|
||||
$play = $aseco->server->players->getPlayer($pl);
|
||||
$msg .= '$z{#login}' . ($rk != PHP_INT_MAX ? $rk : '{#grey}<none>') . '$g / {#black}' . $play->nickname . LF;
|
||||
if (++$lines > 9) {
|
||||
$player->msgs[] = $aseco->formatColors($head . $msg);
|
||||
$lines = 0;
|
||||
$msg = '';
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if ($msg != '')
|
||||
$player->msgs[] = $aseco->formatColors($head . $msg);
|
||||
|
||||
// display popup message
|
||||
if (count($player->msgs) == 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'OK', '', 0);
|
||||
} else { // > 2
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'Close', 'Next', 0);
|
||||
}
|
||||
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$head = 'Online Ranks ({#login}rank $g/{#nick} nick$g):';
|
||||
$msg = array();
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = array(1, $head, array(0.8, 0.15, 0.65), array('Icons128x128_1', 'Buddies'));
|
||||
foreach ($ranks as $pl => $rk) {
|
||||
$play = $aseco->server->players->getPlayer($pl);
|
||||
$msg[] = array('{#login}' . ($rk != PHP_INT_MAX ? $rk : '{#grey}<none>'),
|
||||
'{#black}' . $play->nickname);
|
||||
if (++$lines > 14) {
|
||||
$player->msgs[] = $msg;
|
||||
$lines = 0;
|
||||
$msg = array();
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if (!empty($msg))
|
||||
$player->msgs[] = $msg;
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink_multi($player);
|
||||
}
|
||||
} // chat_ranks
|
||||
|
||||
function chat_clans($aseco, $command) {
|
||||
|
||||
$player = $command['author'];
|
||||
$clans = array();
|
||||
|
||||
// sort players by clan, insuring clanless are last by sorting on chr(255)
|
||||
foreach ($aseco->server->players->player_list as $pl) {
|
||||
$clans[$pl->login] = $pl->teamname ? $pl->teamname : chr(255);
|
||||
}
|
||||
asort($clans);
|
||||
|
||||
// compile the message
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$head = 'Online Clans ({#login}clan $g/{#nick} nick$g):' . LF;
|
||||
$msg = '';
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = 1;
|
||||
foreach ($clans as $pl => $tm) {
|
||||
$play = $aseco->server->players->getPlayer($pl);
|
||||
$msg .= '$z{#login}' . ($tm != chr(255) ? $tm : '{#grey}<none>') . '$z / {#black}' . $play->nickname . LF;
|
||||
if (++$lines > 9) {
|
||||
$player->msgs[] = $aseco->formatColors($head . $msg);
|
||||
$lines = 0;
|
||||
$msg = '';
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if ($msg != '')
|
||||
$player->msgs[] = $aseco->formatColors($head . $msg);
|
||||
|
||||
// display popup message
|
||||
if (count($player->msgs) == 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'OK', '', 0);
|
||||
} else { // > 2
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'Close', 'Next', 0);
|
||||
}
|
||||
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$head = 'Online Clans ({#login}clan $g/{#nick} nick$g):';
|
||||
$msg = array();
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = array(1, $head, array(1.3, 0.65, 0.65), array('Icons128x128_1', 'Buddies'));
|
||||
foreach ($clans as $pl => $tm) {
|
||||
$play = $aseco->server->players->getPlayer($pl);
|
||||
$msg[] = array('{#login}' . ($tm != chr(255) ? $tm : '{#grey}<none>'),
|
||||
'{#black}' . $play->nickname);
|
||||
if (++$lines > 14) {
|
||||
$player->msgs[] = $msg;
|
||||
$lines = 0;
|
||||
$msg = array();
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if (!empty($msg))
|
||||
$player->msgs[] = $msg;
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink_multi($player);
|
||||
}
|
||||
} // chat_clans
|
||||
|
||||
function chat_topclans($aseco, $command) {
|
||||
|
||||
$player = $command['author'];
|
||||
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$msg = 'Current TOP 10 Clans $n(min. ' . $aseco->settings['topclans_minplayers'] . ' players)$m:';
|
||||
$top = 10;
|
||||
$bgn = '{#black}'; // clanname begin
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$header = 'Current TOP 10 Clans $n(min. ' . $aseco->settings['topclans_minplayers'] . ' players)$m:';
|
||||
$top = 10;
|
||||
$bgn = '{#black}'; // clanname begin
|
||||
} else { // TMS/TMO
|
||||
$msg = '{#server}> Current TOP 4 Clans $n(min. ' . $aseco->settings['topclans_minplayers'] . ' players)$m:{#highlite}';
|
||||
$top = 4;
|
||||
$bgn = '{#highlite}';
|
||||
$end = '{#highlite}';
|
||||
}
|
||||
|
||||
// find best ranked
|
||||
$query = 'SELECT TeamName, count, teamrank FROM (
|
||||
SELECT TeamName, COUNT(avg) AS count, SUM(avg)/COUNT(avg) AS teamrank
|
||||
FROM players,rs_rank WHERE players.id=rs_rank.playerid
|
||||
GROUP BY TeamName) as sub
|
||||
WHERE sub.count>=' . $aseco->settings['topclans_minplayers'] . '
|
||||
ORDER BY sub.teamrank LIMIT ' . $top;
|
||||
$res = mysql_query($query);
|
||||
|
||||
if (mysql_num_rows($res) == 0) {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No clan(s) found!'), $player->login);
|
||||
mysql_free_result($res);
|
||||
return false;
|
||||
}
|
||||
|
||||
// compile the message with sorted clans
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$i = 1;
|
||||
while ($row = mysql_fetch_object($res)) {
|
||||
$msg .= LF . $i . '. ' . $bgn . str_pad($row->TeamName . '$z $n(' . $row->count . ')$m', 35)
|
||||
. ' - ' . sprintf("%4.1F", $row->teamrank/10000);
|
||||
$i++;
|
||||
}
|
||||
|
||||
// display popup message
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $aseco->formatColors($msg), 'OK', '', 0);
|
||||
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$i = 1;
|
||||
while ($row = mysql_fetch_object($res)) {
|
||||
$msg[] = array($i . '.',
|
||||
$bgn . $row->TeamName . '$z $n(' . $row->count . ')$m',
|
||||
sprintf("%4.1F", $row->teamrank/10000));
|
||||
$i++;
|
||||
}
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink($player->login, $header, array('BgRaceScore2', 'Podium'), $msg, array(0.95, 0.1, 0.7, 0.15), 'OK');
|
||||
|
||||
} else { // TMS/TMO
|
||||
$i = 1;
|
||||
while ($row = mysql_fetch_object($res)) {
|
||||
$msg .= LF . $i . '. ' . $bgn . str_pad(stripColors($row->TeamName)
|
||||
. $end . ' $n(' . $row->count . ')$m', 25)
|
||||
. ' - ' . sprintf("%4.1F", $row->teamrank/10000);
|
||||
$i++;
|
||||
}
|
||||
// show chat message
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($msg), $player->login);
|
||||
}
|
||||
mysql_free_result($res);
|
||||
} // chat_topclans
|
||||
?>
|
|
@ -0,0 +1,210 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* Chat plugin.
|
||||
* Displays all records of the current track.
|
||||
* Updated by Xymph
|
||||
*
|
||||
* Dependencies: none
|
||||
*/
|
||||
|
||||
Aseco::addChatCommand('recs', 'Displays all records on current track');
|
||||
|
||||
function chat_recs($aseco, $command) {
|
||||
|
||||
$player = $command['author'];
|
||||
$login = $player->login;
|
||||
|
||||
// split params into array
|
||||
$arglist = explode(' ', strtolower(preg_replace('/ +/', ' ', $command['params'])));
|
||||
|
||||
// process optional relations commands
|
||||
if ($arglist[0] == 'help') {
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$help = '{#black}/recs <option>$g shows local records and relations' . LF;
|
||||
$help .= ' - {#black}help$g, displays this help information' . LF;
|
||||
$help .= ' - {#black}pb$g, your personal best on current track' . LF;
|
||||
$help .= ' - {#black}new$g, newly driven records' . LF;
|
||||
$help .= ' - {#black}live$g, records of online players' . LF;
|
||||
$help .= ' - {#black}first$g, first ranked record on current track' . LF;
|
||||
$help .= ' - {#black}last$g, last ranked record on current track' . LF;
|
||||
$help .= ' - {#black}next$g, next better ranked record to beat' . LF;
|
||||
$help .= ' - {#black}diff$g, your difference to first ranked record' . LF;
|
||||
$help .= ' - {#black}range$g, difference first to last ranked record' . LF;
|
||||
$help .= LF . 'Without an option, the normal records list is displayed.';
|
||||
|
||||
// display popup message
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $aseco->formatColors($help), 'OK', '', 0);
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$header = '{#black}/recs <option>$g shows local records and relations:';
|
||||
$help = array();
|
||||
$help[] = array('...', '{#black}help',
|
||||
'Displays this help information');
|
||||
$help[] = array('...', '{#black}pb',
|
||||
'Shows your personal best on current track');
|
||||
$help[] = array('...', '{#black}new',
|
||||
'Shows newly driven records');
|
||||
$help[] = array('...', '{#black}live',
|
||||
'Shows records of online players');
|
||||
$help[] = array('...', '{#black}first',
|
||||
'Shows first ranked record on current track');
|
||||
$help[] = array('...', '{#black}last',
|
||||
'Shows last ranked record on current track');
|
||||
$help[] = array('...', '{#black}next',
|
||||
'Shows next better ranked record to beat');
|
||||
$help[] = array('...', '{#black}diff',
|
||||
'Shows your difference to first ranked record');
|
||||
$help[] = array('...', '{#black}range',
|
||||
'Shows difference first to last ranked record');
|
||||
$help[] = array();
|
||||
$help[] = array('Without an option, the normal records list is displayed.');
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink($login, $header, array('Icons64x64_1', 'TrackInfo', -0.01), $help, array(1.1, 0.05, 0.3, 0.75), 'OK');
|
||||
}
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'pb') {
|
||||
chat_pb($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'new') {
|
||||
chat_newrecs($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'live') {
|
||||
chat_liverecs($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'first') {
|
||||
chat_firstrec($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'last') {
|
||||
chat_lastrec($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'next') {
|
||||
chat_nextrec($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'diff') {
|
||||
chat_diffrec($aseco, $command);
|
||||
return;
|
||||
}
|
||||
elseif ($arglist[0] == 'range') {
|
||||
chat_recrange($aseco, $command);
|
||||
return;
|
||||
}
|
||||
|
||||
// check for relay server
|
||||
if ($aseco->server->isrelay) {
|
||||
$message = formatText($aseco->getChatMessage('NOTONRELAY'));
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$total = $aseco->server->records->count()) {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No records found!'), $login);
|
||||
return;
|
||||
}
|
||||
|
||||
// display popup window for TMN
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$head = 'Current TOP ' . $aseco->server->records->max . ' Local Records:' . LF;
|
||||
$msg = '';
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = 1;
|
||||
|
||||
// create list of records
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$cur_record = $aseco->server->records->getRecord($i);
|
||||
$nick = $cur_record->player->nickname;
|
||||
if (!$aseco->settings['lists_colornicks'])
|
||||
$nick = stripColors($nick);
|
||||
$msg .= str_pad($i+1, 2, '0', STR_PAD_LEFT) . '. {#black}'
|
||||
. str_pad($nick, 20) . '$z - '
|
||||
. ($cur_record->new ? '{#black}' : '')
|
||||
. formatTime($cur_record->score) . LF;
|
||||
if (++$lines > 9) {
|
||||
$player->msgs[] = $aseco->formatColors($head . $msg);
|
||||
$lines = 0;
|
||||
$msg = '';
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if ($msg != '')
|
||||
$player->msgs[] = $aseco->formatColors($head . $msg);
|
||||
|
||||
// display popup message
|
||||
if (count($player->msgs) == 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $player->msgs[1], 'OK', '', 0);
|
||||
} else { // > 2
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $player->msgs[1], 'Close', 'Next', 0);
|
||||
}
|
||||
|
||||
// display ManiaLink window for TMF
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$head = 'Current TOP ' . $aseco->server->records->max . ' Local Records:';
|
||||
$msg = array();
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
// reserve extra width for $w tags
|
||||
$extra = ($aseco->settings['lists_colornicks'] ? 0.2 : 0);
|
||||
if ($aseco->settings['show_rec_logins'])
|
||||
$player->msgs[0] = array(1, $head, array(1.2+$extra, 0.1, 0.45+$extra, 0.4, 0.25), array('BgRaceScore2', 'Podium'));
|
||||
else
|
||||
$player->msgs[0] = array(1, $head, array(0.8+$extra, 0.1, 0.45+$extra, 0.25), array('BgRaceScore2', 'Podium'));
|
||||
|
||||
// create list of records
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$cur_record = $aseco->server->records->getRecord($i);
|
||||
$nick = $cur_record->player->nickname;
|
||||
if (!$aseco->settings['lists_colornicks'])
|
||||
$nick = stripColors($nick);
|
||||
if ($aseco->settings['show_rec_logins']) {
|
||||
$msg[] = array(str_pad($i+1, 2, '0', STR_PAD_LEFT) . '.',
|
||||
'{#black}' . $nick,
|
||||
'{#login}' . $cur_record->player->login,
|
||||
($cur_record->new ? '{#black}' : '') .
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$cur_record->score : formatTime($cur_record->score)));
|
||||
} else {
|
||||
$msg[] = array(str_pad($i+1, 2, '0', STR_PAD_LEFT) . '.',
|
||||
'{#black}' . $nick,
|
||||
($cur_record->new ? '{#black}' : '') .
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$cur_record->score : formatTime($cur_record->score)));
|
||||
}
|
||||
if (++$lines > 14) {
|
||||
$player->msgs[] = $msg;
|
||||
$lines = 0;
|
||||
$msg = array();
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if (!empty($msg))
|
||||
$player->msgs[] = $msg;
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink_multi($player);
|
||||
|
||||
// show chat message for TMO & TMS
|
||||
} else {
|
||||
$top = 4;
|
||||
$msg = $aseco->formatColors("{#server}> Current TOP $top Local Records:{#highlite}");
|
||||
|
||||
// create list of records
|
||||
$total = ($total <= $top ? $total : $top);
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$cur_record = $aseco->server->records->getRecord($i);
|
||||
$msg .= LF . ($i+1) . '. ' . str_pad(stripColors($cur_record->player->nickname), 15)
|
||||
. ' - ' . formatTime($cur_record->score);
|
||||
}
|
||||
// show chat message
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $msg, $login);
|
||||
}
|
||||
} // chat_recs
|
||||
?>
|
|
@ -0,0 +1,888 @@
|
|||
<?php
|
||||
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||
|
||||
/**
|
||||
* Chat plugin.
|
||||
* Shows new/online records of the current track, and displays related lists.
|
||||
* Created by Xymph
|
||||
*
|
||||
* Dependencies: used by chat.stats.php, plugin.rasp_jukebox.php
|
||||
*/
|
||||
|
||||
if (!INHIBIT_RECCMDS) {
|
||||
Aseco::addChatCommand('newrecs', 'Shows newly driven records');
|
||||
Aseco::addChatCommand('liverecs', 'Shows records of online players');
|
||||
}
|
||||
Aseco::addChatCommand('best', 'Displays your best records');
|
||||
Aseco::addChatCommand('worst', 'Displays your worst records');
|
||||
Aseco::addChatCommand('summary', 'Shows summary of all your records');
|
||||
Aseco::addChatCommand('topsums', 'Displays top 100 of top-3 record holders');
|
||||
Aseco::addChatCommand('toprecs', 'Displays top 100 ranked records holders');
|
||||
|
||||
/*
|
||||
* Universal function to generate list of records for current track.
|
||||
* Called by chat_newrecs, chat_liverecs, endRace & beginRace (aseco.php).
|
||||
* Show to a player if $login defined, otherwise show to all players.
|
||||
* $mode = 0 (only new), 1 (top-8 & online players at start of track),
|
||||
* 2 (top-6 & online during track), 3 (top-8 & new at end of track)
|
||||
* In modes 1/2/3 the last ranked record is also shown
|
||||
* top-8 is configurable via 'show_min_recs'; top-6 is show_min_recs-2
|
||||
*/
|
||||
function show_trackrecs($aseco, $login, $mode, $window) {
|
||||
|
||||
$records = '$n'; // use narrow font
|
||||
|
||||
// check for records
|
||||
if (($total = $aseco->server->records->count()) == 0) {
|
||||
$totalnew = -1;
|
||||
} else {
|
||||
// check whether to show range
|
||||
if ($aseco->settings['show_recs_range']) {
|
||||
// get the first & last ranked records
|
||||
$first = $aseco->server->records->getRecord(0);
|
||||
$last = $aseco->server->records->getRecord($total-1);
|
||||
// compute difference between records
|
||||
if ($aseco->server->gameinfo->mode != Gameinfo::STNT) {
|
||||
$diff = $last->score - $first->score;
|
||||
$sec = floor($diff/1000);
|
||||
$hun = ($diff - ($sec * 1000)) / 10;
|
||||
} else { // Stunts
|
||||
$diff = $first->score - $last->score;
|
||||
}
|
||||
}
|
||||
|
||||
// get list of online players
|
||||
$players = array();
|
||||
foreach ($aseco->server->players->player_list as $pl) {
|
||||
$players[] = $pl->login;
|
||||
}
|
||||
|
||||
// collect new records and records by online players
|
||||
$totalnew = 0;
|
||||
// go through each record
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$cur_record = $aseco->server->records->getRecord($i);
|
||||
|
||||
// if the record is new then display it
|
||||
if ($cur_record->new) {
|
||||
$totalnew++;
|
||||
$record_msg = formatText($aseco->getChatMessage('RANKING_RECORD_NEW_ON'),
|
||||
$i+1,
|
||||
stripColors($cur_record->player->nickname),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$cur_record->score : formatTime($cur_record->score)));
|
||||
// always show new record
|
||||
$records .= $record_msg;
|
||||
} else {
|
||||
// check if player is online
|
||||
if (in_array($cur_record->player->login, $players)) {
|
||||
$record_msg = formatText($aseco->getChatMessage('RANKING_RECORD_ON'),
|
||||
$i+1,
|
||||
stripColors($cur_record->player->nickname),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$cur_record->score : formatTime($cur_record->score)));
|
||||
// check if last ranked record
|
||||
if ($mode != 0 && $i == $total-1) {
|
||||
$records .= $record_msg;
|
||||
}
|
||||
// check if always show (start of/during track)
|
||||
elseif ($mode == 1 || $mode == 2) {
|
||||
$records .= $record_msg;
|
||||
}
|
||||
else {
|
||||
// show record if < show_min_recs (end of track)
|
||||
if ($mode == 3 && $i < $aseco->settings['show_min_recs']) {
|
||||
$records .= $record_msg;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$record_msg = formatText($aseco->getChatMessage('RANKING_RECORD'),
|
||||
$i+1,
|
||||
stripColors($cur_record->player->nickname),
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$cur_record->score : formatTime($cur_record->score)));
|
||||
// check if last ranked record
|
||||
if ($mode != 0 && $i == $total-1) {
|
||||
$records .= $record_msg;
|
||||
}
|
||||
// show offline record if < show_min_recs-2 (during track)
|
||||
elseif (($mode == 2 && $i < $aseco->settings['show_min_recs']-2) ||
|
||||
// show offline record if < show_min_recs (start/end of track)
|
||||
(($mode == 1 || $mode == 3) && $i < $aseco->settings['show_min_recs'])) {
|
||||
$records .= $record_msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// define wording of the ranking message
|
||||
switch ($mode) {
|
||||
case 0:
|
||||
$timing = 'during';
|
||||
break;
|
||||
case 1:
|
||||
$timing = 'before';
|
||||
break;
|
||||
case 2:
|
||||
$timing = 'during';
|
||||
break;
|
||||
case 3:
|
||||
$timing = 'after';
|
||||
break;
|
||||
}
|
||||
|
||||
$name = stripColors($aseco->server->challenge->name);
|
||||
if ($aseco->server->getGame() == 'TMF' &&
|
||||
isset($aseco->server->challenge->tmx->name) && $aseco->server->challenge->tmx->name != '')
|
||||
$name = '$l[http://' . $aseco->server->challenge->tmx->prefix .
|
||||
'.tm-exchange.com/main.aspx?action=trackshow&id=' .
|
||||
$aseco->server->challenge->tmx->id . ']' . $name . '$l';
|
||||
|
||||
// define the ranking message
|
||||
if ($totalnew > 0) {
|
||||
$message = formatText($aseco->getChatMessage('RANKING_NEW'),
|
||||
$name, $timing, $totalnew);
|
||||
}
|
||||
elseif ($totalnew == 0 && $records != '$n') {
|
||||
// check whether to show range
|
||||
if ($aseco->settings['show_recs_range']) {
|
||||
$message = formatText($aseco->getChatMessage('RANKING_RANGE'),
|
||||
$name, $timing,
|
||||
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||
$diff : sprintf("%d.%02d", $sec, $hun)));
|
||||
} else {
|
||||
$message = formatText($aseco->getChatMessage('RANKING'),
|
||||
$name, $timing);
|
||||
}
|
||||
}
|
||||
elseif ($totalnew == 0 && $records == '$n') {
|
||||
$message = formatText($aseco->getChatMessage('RANKING_NONEW'),
|
||||
$name, $timing);
|
||||
}
|
||||
else { // $totalnew == -1
|
||||
$message = formatText($aseco->getChatMessage('RANKING_NONE'),
|
||||
$name, $timing);
|
||||
}
|
||||
|
||||
// append the records if any
|
||||
if ($records != '$n') {
|
||||
$records = substr($records, 0, strlen($records)-2); // strip trailing ", "
|
||||
$message .= LF . $records;
|
||||
}
|
||||
|
||||
// show to player or all
|
||||
if ($login) {
|
||||
// strip 1 leading '>' to indicate a player message instead of system-wide
|
||||
$message = str_replace('{#server}>> ', '{#server}> ', $message);
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||
} else {
|
||||
if (($window & 4) == 4 && function_exists('send_window_message'))
|
||||
send_window_message($aseco, $message, ($mode == 3));
|
||||
else
|
||||
$aseco->client->query('ChatSendServerMessage', $aseco->formatColors($message));
|
||||
}
|
||||
} // show_trackrecs
|
||||
|
||||
function chat_newrecs($aseco, $command) {
|
||||
|
||||
// check for relay server
|
||||
if ($aseco->server->isrelay) {
|
||||
$message = formatText($aseco->getChatMessage('NOTONRELAY'));
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $command['author']->login);
|
||||
return;
|
||||
}
|
||||
|
||||
// show only newly driven records
|
||||
show_trackrecs($aseco, $command['author']->login, 0, 0);
|
||||
} // chat_newrecs
|
||||
|
||||
function chat_liverecs($aseco, $command) {
|
||||
|
||||
// check for relay server
|
||||
if ($aseco->server->isrelay) {
|
||||
$message = formatText($aseco->getChatMessage('NOTONRELAY'));
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $command['author']->login);
|
||||
return;
|
||||
}
|
||||
|
||||
// show online & show_min_recs-2 records
|
||||
show_trackrecs($aseco, $command['author']->login, 2, 0);
|
||||
} // chat_liverecs
|
||||
|
||||
|
||||
function chat_best($aseco, $command) {
|
||||
|
||||
// check for relay server
|
||||
if ($aseco->server->isrelay) {
|
||||
$message = formatText($aseco->getChatMessage('NOTONRELAY'));
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $command['author']->login);
|
||||
return;
|
||||
}
|
||||
|
||||
// display player records, best first
|
||||
disp_recs($aseco, $command, true);
|
||||
} // chat_best
|
||||
|
||||
function chat_worst($aseco, $command) {
|
||||
|
||||
// check for relay server
|
||||
if ($aseco->server->isrelay) {
|
||||
$message = formatText($aseco->getChatMessage('NOTONRELAY'));
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $command['author']->login);
|
||||
return;
|
||||
}
|
||||
|
||||
// display player records, worst first
|
||||
disp_recs($aseco, $command, false);
|
||||
} // chat_worst
|
||||
|
||||
/*
|
||||
* Universal function to get list of all records for a player.
|
||||
* Called by disp_recs (chat_best & chat_worst), chat_summary and
|
||||
* chat_stats (in chat.stats.php).
|
||||
*/
|
||||
function get_recs($pid) {
|
||||
global $aseco;
|
||||
|
||||
// get player's record for each track
|
||||
$list = array();
|
||||
$order = ($aseco->server->gameinfo->mode == Gameinfo::STNT ? 'DESC' : 'ASC');
|
||||
|
||||
$query = 'SELECT Uid,PlayerId FROM records r LEFT JOIN challenges c ON (r.ChallengeId=c.Id)
|
||||
WHERE Uid IS NOT NULL ORDER BY ChallengeId ASC,Score ' . $order . ',Date ASC';
|
||||
$result = mysql_query($query);
|
||||
|
||||
$last = '';
|
||||
while ($row = mysql_fetch_object($result)) {
|
||||
// check for new track & reset rank
|
||||
if ($last != $row->Uid) {
|
||||
$last = $row->Uid;
|
||||
$pos = 1;
|
||||
}
|
||||
if (isset($list[$row->Uid]))
|
||||
continue;
|
||||
|
||||
// store player's challenges & records
|
||||
if ($row->PlayerId == $pid) {
|
||||
$list[$row->Uid] = $pos;
|
||||
continue;
|
||||
}
|
||||
$pos++;
|
||||
}
|
||||
|
||||
mysql_free_result($result);
|
||||
// return list
|
||||
return $list;
|
||||
} // get_recs
|
||||
|
||||
function disp_recs($aseco, $command, $order) {
|
||||
global $jb_buffer;
|
||||
|
||||
$player = $command['author'];
|
||||
$target = $player;
|
||||
|
||||
// check for optional login parameter if any admin
|
||||
if ($command['params'] != '' && $aseco->allowAbility($player, 'chat_bestworst'))
|
||||
if (!$target = $aseco->getPlayerParam($player, $command['params'], true))
|
||||
return;
|
||||
|
||||
// check for records
|
||||
if ($list = get_recs($target->id)) {
|
||||
// sort for best or worst records
|
||||
$order ? asort($list) : arsort($list);
|
||||
|
||||
// get new/cached list of tracks
|
||||
$newlist = getChallengesCache($aseco); // from rasp.funcs.php
|
||||
|
||||
// create list of records
|
||||
$player->tracklist = array();
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$head = ($order ? 'Best' : 'Worst') . ' Records for ' . $target->nickname
|
||||
. '$z:' . LF . 'Id Rec Name' . LF;
|
||||
$recs = '';
|
||||
$tid = 1;
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = 1;
|
||||
foreach ($list as $uid => $pos) {
|
||||
// does the uid exist in the current server track list?
|
||||
if (array_key_exists($uid, $newlist)) {
|
||||
$row = $newlist[$uid];
|
||||
// store track in player object for jukeboxing
|
||||
$trkarr = array();
|
||||
$trkarr['name'] = $row['Name'];
|
||||
$trkarr['environment'] = $row['Environnement'];
|
||||
$trkarr['filename'] = $row['FileName'];
|
||||
$trkarr['uid'] = $row['UId'];
|
||||
$player->tracklist[] = $trkarr;
|
||||
|
||||
// format track name
|
||||
$trackname = $row['Name'];
|
||||
if (!$aseco->settings['lists_colortracks'])
|
||||
$trackname = stripColors($trackname);
|
||||
// grey out if in history
|
||||
if (in_array($row['UId'], $jb_buffer))
|
||||
$trackname = '{#grey}' . stripColors($trackname);
|
||||
else
|
||||
$trackname = '{#black}' . $trackname;
|
||||
|
||||
$recs .= '$z' . str_pad($tid, 3, '0', STR_PAD_LEFT) . '. '
|
||||
. str_pad($pos, 2, '0', STR_PAD_LEFT) . '. '
|
||||
. $trackname . LF;
|
||||
$tid++;
|
||||
if (++$lines > 9) {
|
||||
$player->msgs[] = $aseco->formatColors($head . $recs);
|
||||
$lines = 0;
|
||||
$recs = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if ($recs != '')
|
||||
$player->msgs[] = $aseco->formatColors($head . $recs);
|
||||
|
||||
// display popup message
|
||||
if (count($player->msgs) == 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'OK', '', 0);
|
||||
} elseif (count($player->msgs) > 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'Close', 'Next', 0);
|
||||
} else { // == 1
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No records found!'), $player->login);
|
||||
}
|
||||
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$envids = array('Stadium' => 11, 'Alpine' => 12, 'Bay' => 13, 'Coast' => 14, 'Island' => 15, 'Rally' => 16, 'Speed' => 17);
|
||||
$head = ($order ? 'Best' : 'Worst') . ' Records for ' . str_ireplace('$w', '', $target->nickname) . '$z:';
|
||||
$recs = array();
|
||||
if ($aseco->server->packmask != 'Stadium')
|
||||
$recs[] = array('Id', 'Rec', 'Name', 'Author', 'Env');
|
||||
else
|
||||
$recs[] = array('Id', 'Rec', 'Name', 'Author');
|
||||
$tid = 1;
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
// no extra width for $w tags due to nickname width in header
|
||||
if ($aseco->server->packmask != 'Stadium')
|
||||
$player->msgs[0] = array(1, $head, array(1.59, 0.12, 0.1, 0.8, 0.4, 0.17), array('Icons128x128_1', 'NewTrack', 0.02));
|
||||
else
|
||||
$player->msgs[0] = array(1, $head, array(1.42, 0.12, 0.1, 0.8, 0.4), array('Icons128x128_1', 'NewTrack', 0.02));
|
||||
foreach ($list as $uid => $pos) {
|
||||
// does the uid exist in the current server track list?
|
||||
if (array_key_exists($uid, $newlist)) {
|
||||
$row = $newlist[$uid];
|
||||
// store track in player object for jukeboxing
|
||||
$trkarr = array();
|
||||
$trkarr['name'] = $row['Name'];
|
||||
$trkarr['author'] = $row['Author'];
|
||||
$trkarr['environment'] = $row['Environnement'];
|
||||
$trkarr['filename'] = $row['FileName'];
|
||||
$trkarr['uid'] = $row['UId'];
|
||||
$player->tracklist[] = $trkarr;
|
||||
|
||||
// format track name
|
||||
$trackname = $row['Name'];
|
||||
if (!$aseco->settings['lists_colortracks'])
|
||||
$trackname = stripColors($trackname);
|
||||
// grey out if in history
|
||||
if (in_array($row['UId'], $jb_buffer))
|
||||
$trackname = '{#grey}' . stripColors($trackname);
|
||||
else {
|
||||
$trackname = '{#black}' . $trackname;
|
||||
// add clickable button
|
||||
if ($aseco->settings['clickable_lists'] && $tid <= 1900)
|
||||
$trackname = array($trackname, $tid+100); // action id
|
||||
}
|
||||
// format author name
|
||||
$trackauthor = $row['Author'];
|
||||
// add clickable button
|
||||
if ($aseco->settings['clickable_lists'] && $tid <= 1900)
|
||||
$trackauthor = array($trackauthor, -100-$tid); // action id
|
||||
// format env name
|
||||
$trackenv = $row['Environnement'];
|
||||
// add clickable button
|
||||
if ($aseco->settings['clickable_lists'])
|
||||
$trackenv = array($trackenv, $envids[$row['Environnement']]); // action id
|
||||
|
||||
if ($aseco->server->packmask != 'Stadium')
|
||||
$recs[] = array(str_pad($tid, 3, '0', STR_PAD_LEFT) . '.',
|
||||
str_pad($pos, 2, '0', STR_PAD_LEFT) . '.',
|
||||
$trackname, $trackauthor, $trackenv);
|
||||
else
|
||||
$recs[] = array(str_pad($tid, 3, '0', STR_PAD_LEFT) . '.',
|
||||
str_pad($pos, 2, '0', STR_PAD_LEFT) . '.',
|
||||
$trackname, $trackauthor);
|
||||
$tid++;
|
||||
if (++$lines > 14) {
|
||||
$player->msgs[] = $recs;
|
||||
$lines = 0;
|
||||
$recs = array();
|
||||
if ($aseco->server->packmask != 'Stadium')
|
||||
$recs[] = array('Id', 'Rec', 'Name', 'Author', 'Env');
|
||||
else
|
||||
$recs[] = array('Id', 'Rec', 'Name', 'Author');
|
||||
}
|
||||
}
|
||||
}
|
||||
// add if last batch exists
|
||||
if (count($recs) > 1)
|
||||
$player->msgs[] = $recs;
|
||||
|
||||
if (count($player->msgs) > 1) {
|
||||
// display ManiaLink message
|
||||
display_manialink_multi($player);
|
||||
} else {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No records found!'), $player->login);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No records found!'), $player->login);
|
||||
}
|
||||
} // disp_recs
|
||||
|
||||
function chat_summary($aseco, $command) {
|
||||
global $maxrecs;
|
||||
|
||||
$player = $command['author'];
|
||||
$target = $player;
|
||||
|
||||
// check for relay server
|
||||
if ($aseco->server->isrelay) {
|
||||
$message = formatText($aseco->getChatMessage('NOTONRELAY'));
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||
return;
|
||||
}
|
||||
|
||||
// check for optional login parameter if any admin
|
||||
if ($command['params'] != '' && $aseco->allowAbility($player, 'chat_summary'))
|
||||
if (!$target = $aseco->getPlayerParam($player, $command['params'], true))
|
||||
return;
|
||||
|
||||
// check for records
|
||||
if ($list = get_recs($target->id)) {
|
||||
// sort for best records
|
||||
asort($list);
|
||||
|
||||
// get new/cached list of tracks
|
||||
$newlist = getChallengesCache($aseco); // from rasp.funcs.php
|
||||
|
||||
// collect summary of first 3 records and count total
|
||||
$show = 3;
|
||||
$message = '';
|
||||
$total = 0;
|
||||
$cntrec = 0;
|
||||
$currec = 0;
|
||||
foreach ($list as $uid => $rec) {
|
||||
// stop upon unranked record
|
||||
if ($rec > $maxrecs) break;
|
||||
|
||||
// check if rec is for existing track
|
||||
if (array_key_exists($uid, $newlist)) {
|
||||
// count total ranked records
|
||||
$total++;
|
||||
|
||||
// check for first 3 records
|
||||
if ($show > 0) {
|
||||
// check for same record
|
||||
if ($rec == $currec) {
|
||||
$cntrec++;
|
||||
} else {
|
||||
// collect next record sum
|
||||
if ($currec > 0) {
|
||||
$message .= formatText($aseco->getChatMessage('SUM_ENTRY'),
|
||||
$cntrec, ($cntrec > 1 ? 's' : ''), $currec);
|
||||
$show--;
|
||||
}
|
||||
// count first occurance of next record
|
||||
$cntrec = 1;
|
||||
$currec = $rec;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if less than 3 records, add the last one found
|
||||
if ($show > 0 && $currec > 0) {
|
||||
$message .= formatText($aseco->getChatMessage('SUM_ENTRY'),
|
||||
$cntrec, ($cntrec > 1 ? 's' : ''), $currec);
|
||||
$show--;
|
||||
}
|
||||
|
||||
if ($message) {
|
||||
// define text version of number of top-3 records
|
||||
switch (3-$show) {
|
||||
case 1:
|
||||
$show = 'one';
|
||||
break;
|
||||
case 2:
|
||||
$show = 'two';
|
||||
break;
|
||||
case 3:
|
||||
$show = 'three';
|
||||
break;
|
||||
}
|
||||
|
||||
// show chat message
|
||||
$message = substr($message, 0, strlen($message)-2); // strip trailing ", "
|
||||
$message = formatText($aseco->getChatMessage('SUMMARY'),
|
||||
$target->nickname,
|
||||
$total, ($total > 1 ? 's' : ''),
|
||||
$show)
|
||||
. $message;
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||
} else {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No ranked records found!'), $player->login);
|
||||
}
|
||||
} else {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No ranked records found!'), $player->login);
|
||||
}
|
||||
} // chat_summary
|
||||
|
||||
// define sorting function for descending top-3's
|
||||
function top3_compare($a, $b) {
|
||||
|
||||
// compare #1 records
|
||||
if ($a[0] < $b[0])
|
||||
return 1;
|
||||
elseif ($a[0] > $b[0])
|
||||
return -1;
|
||||
|
||||
// compare #2 records
|
||||
if ($a[1] < $b[1])
|
||||
return 1;
|
||||
elseif ($a[1] > $b[1])
|
||||
return -1;
|
||||
|
||||
// compare #3 records
|
||||
if ($a[2] < $b[2])
|
||||
return 1;
|
||||
elseif ($a[2] > $b[2])
|
||||
return -1;
|
||||
|
||||
// all equal
|
||||
return 0;
|
||||
} // top3_compare
|
||||
|
||||
function chat_topsums($aseco, $command) {
|
||||
|
||||
$player = $command['author'];
|
||||
|
||||
// check for relay server
|
||||
if ($aseco->server->isrelay) {
|
||||
$message = formatText($aseco->getChatMessage('NOTONRELAY'));
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$head = 'TOP 100 of Top-3 Record Holders:';
|
||||
$top = 100;
|
||||
$bgn = '{#black}'; // nickname begin
|
||||
$end = '$z'; // ... & end colors
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$head = 'TOP 100 of Top-3 Record Holders:';
|
||||
$top = 100;
|
||||
$bgn = '{#black}'; // nickname begin
|
||||
} else {
|
||||
$head = '{#server}> TOP 4 of Top-3 Record Holders:{#highlite}';
|
||||
$top = 4;
|
||||
$bgn = '{#highlite}';
|
||||
$end = '{#highlite}';
|
||||
}
|
||||
|
||||
// get new/cached list of tracks
|
||||
$newlist = getChallengesCache($aseco); // from rasp.funcs.php
|
||||
|
||||
// get current list of track IDs
|
||||
$query = 'SELECT Id,Uid FROM challenges';
|
||||
$result = mysql_query($query);
|
||||
$tidlist = array();
|
||||
while ($row = mysql_fetch_object($result)) {
|
||||
if (array_key_exists($row->Uid, $newlist))
|
||||
$tidlist[] = $row->Id;
|
||||
}
|
||||
|
||||
// collect top-3 records
|
||||
$recs = array();
|
||||
$order = ($aseco->server->gameinfo->mode == Gameinfo::STNT ? 'DESC' : 'ASC');
|
||||
foreach ($tidlist as $tid) {
|
||||
// get top-3 ranked records on this track
|
||||
$query = 'SELECT login FROM players,records
|
||||
WHERE players.id=records.playerid AND
|
||||
challengeid=' . $tid . '
|
||||
ORDER BY score ' . $order . ',date ASC LIMIT 3';
|
||||
$result = mysql_query($query);
|
||||
|
||||
// tally top-3 record totals by login
|
||||
if ($row = mysql_fetch_array($result)) {
|
||||
if (isset($recs[$row[0]])) {
|
||||
$recs[$row[0]][0]++;
|
||||
} else {
|
||||
$recs[$row[0]] = array(1,0,0);
|
||||
}
|
||||
if ($row = mysql_fetch_array($result)) {
|
||||
if (isset($recs[$row[0]])) {
|
||||
$recs[$row[0]][1]++;
|
||||
} else {
|
||||
$recs[$row[0]] = array(0,1,0);
|
||||
}
|
||||
if ($row = mysql_fetch_array($result)) {
|
||||
if (isset($recs[$row[0]])) {
|
||||
$recs[$row[0]][2]++;
|
||||
} else {
|
||||
$recs[$row[0]] = array(0,0,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mysql_free_result($result);
|
||||
}
|
||||
|
||||
if (empty($recs)) {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No players with ranked records found!'), $player->login);
|
||||
return;
|
||||
}
|
||||
|
||||
// sort players by #1, #2 & #3 records
|
||||
uasort($recs, 'top3_compare');
|
||||
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$records = '';
|
||||
$i = 1;
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = 1;
|
||||
foreach ($recs as $login => $top3) {
|
||||
// obtain nickname for this login
|
||||
$nick = $aseco->getPlayerNick($login);
|
||||
if (!$aseco->settings['lists_colornicks'])
|
||||
$nick = stripColors($nick);
|
||||
|
||||
$records .= LF . str_pad($i, 2, '0', STR_PAD_LEFT) . '. ' . $bgn
|
||||
. str_pad($nick, 20) . $end . ' - '
|
||||
. str_pad($top3[0], 3, ' ', STR_PAD_LEFT) . ' / '
|
||||
. str_pad($top3[1], 3, ' ', STR_PAD_LEFT) . ' / '
|
||||
. str_pad($top3[2], 3, ' ', STR_PAD_LEFT);
|
||||
$i++;
|
||||
if (++$lines > 9) {
|
||||
$player->msgs[] = $aseco->formatColors($head . $records);
|
||||
$lines = 0;
|
||||
$records = '';
|
||||
}
|
||||
if ($i > $top) break;
|
||||
}
|
||||
// add if last batch exists
|
||||
if ($records != '')
|
||||
$player->msgs[] = $aseco->formatColors($head . $records);
|
||||
|
||||
// display popup message
|
||||
if (count($player->msgs) == 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'OK', '', 0);
|
||||
} else { // > 2
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'Close', 'Next', 0);
|
||||
}
|
||||
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$records = array();
|
||||
$i = 1;
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
// reserve extra width for $w tags
|
||||
$extra = ($aseco->settings['lists_colornicks'] ? 0.2 : 0);
|
||||
$player->msgs[0] = array(1, $head, array(0.85+$extra, 0.1, 0.45+$extra, 0.3), array('BgRaceScore2', 'LadderRank'));
|
||||
foreach ($recs as $login => $top3) {
|
||||
// obtain nickname for this login
|
||||
$nick = $aseco->getPlayerNick($login);
|
||||
if (!$aseco->settings['lists_colornicks'])
|
||||
$nick = stripColors($nick);
|
||||
|
||||
$records[] = array(str_pad($i, 2, '0', STR_PAD_LEFT) . '.',
|
||||
$bgn . $nick,
|
||||
str_pad($top3[0], 3, ' ', STR_PAD_LEFT) . ' / '
|
||||
. str_pad($top3[1], 3, ' ', STR_PAD_LEFT) . ' / '
|
||||
. str_pad($top3[2], 3, ' ', STR_PAD_LEFT));
|
||||
$i++;
|
||||
if (++$lines > 14) {
|
||||
$player->msgs[] = $records;
|
||||
$lines = 0;
|
||||
$records = array();
|
||||
}
|
||||
if ($i > $top) break;
|
||||
}
|
||||
// add if last batch exists
|
||||
if (!empty($records))
|
||||
$player->msgs[] = $records;
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink_multi($player);
|
||||
|
||||
} else { // TMS/TMO
|
||||
$records = $head;
|
||||
$i = 1;
|
||||
foreach ($recs as $login => $top3) {
|
||||
// obtain nickname for this login
|
||||
$nick = stripColors($aseco->getPlayerNick($login));
|
||||
|
||||
$records .= LF . $i . '. ' . $bgn
|
||||
. str_pad($nick, 15) . $end . ' - '
|
||||
. str_pad($top3[0], 3, ' ', STR_PAD_LEFT) . ' / '
|
||||
. str_pad($top3[1], 3, ' ', STR_PAD_LEFT) . ' / '
|
||||
. str_pad($top3[2], 3, ' ', STR_PAD_LEFT);
|
||||
$i++;
|
||||
if ($i > $top) break;
|
||||
}
|
||||
// show chat message
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($records), $player->login);
|
||||
}
|
||||
} // chat_topsums
|
||||
|
||||
function chat_toprecs($aseco, $command) {
|
||||
global $maxrecs;
|
||||
|
||||
$player = $command['author'];
|
||||
|
||||
// check for relay server
|
||||
if ($aseco->server->isrelay) {
|
||||
$message = formatText($aseco->getChatMessage('NOTONRELAY'));
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$head = 'TOP 100 Ranked Record Holders:';
|
||||
$top = 100;
|
||||
$bgn = '{#black}'; // nickname begin
|
||||
$end = '$z'; // ... & end colors
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$head = 'TOP 100 Ranked Record Holders:';
|
||||
$top = 100;
|
||||
$bgn = '{#black}'; // nickname begin
|
||||
} else {
|
||||
$head = '{#server}> TOP 4 Ranked Record Holders:{#highlite}';
|
||||
$top = 4;
|
||||
$bgn = '{#highlite}';
|
||||
$end = '{#highlite}';
|
||||
}
|
||||
|
||||
// get new/cached list of tracks
|
||||
$newlist = getChallengesCache($aseco); // from rasp.funcs.php
|
||||
|
||||
// get current list of track IDs
|
||||
$query = 'SELECT Id,Uid FROM challenges';
|
||||
$result = mysql_query($query);
|
||||
$tidlist = array();
|
||||
while ($row = mysql_fetch_object($result)) {
|
||||
if (array_key_exists($row->Uid, $newlist))
|
||||
$tidlist[] = $row->Id;
|
||||
}
|
||||
|
||||
// collect record totals
|
||||
$recs = array();
|
||||
$order = ($aseco->server->gameinfo->mode == Gameinfo::STNT ? 'DESC' : 'ASC');
|
||||
foreach ($tidlist as $tid) {
|
||||
// get ranked records on this track
|
||||
$query = 'SELECT login FROM players,records
|
||||
WHERE players.id=records.playerid AND
|
||||
challengeid=' . $tid . '
|
||||
ORDER BY score ' . $order . ',date ASC LIMIT ' . $maxrecs;
|
||||
$result = mysql_query($query);
|
||||
|
||||
// update record totals by login
|
||||
while ($row = mysql_fetch_array($result)) {
|
||||
if (isset($recs[$row[0]]))
|
||||
$recs[$row[0]]++;
|
||||
else
|
||||
$recs[$row[0]] = 1;
|
||||
}
|
||||
mysql_free_result($result);
|
||||
}
|
||||
|
||||
if (empty($recs)) {
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No players with ranked records found!'), $player->login);
|
||||
return;
|
||||
}
|
||||
|
||||
// sort for most records
|
||||
arsort($recs);
|
||||
|
||||
if ($aseco->server->getGame() == 'TMN') {
|
||||
$records = '';
|
||||
$i = 1;
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
$player->msgs[0] = 1;
|
||||
foreach ($recs as $login => $rec) {
|
||||
// obtain nickname for this login
|
||||
$nick = $aseco->getPlayerNick($login);
|
||||
if (!$aseco->settings['lists_colornicks'])
|
||||
$nick = stripColors($nick);
|
||||
|
||||
$records .= LF . str_pad($i, 2, '0', STR_PAD_LEFT) . '. ' . $bgn
|
||||
. str_pad($nick, 20) . $end . ' - ' . $rec;
|
||||
$i++;
|
||||
if (++$lines > 9) {
|
||||
$player->msgs[] = $aseco->formatColors($head . $records);
|
||||
$lines = 0;
|
||||
$records = '';
|
||||
}
|
||||
if ($i > $top) break;
|
||||
}
|
||||
// add if last batch exists
|
||||
if ($records != '')
|
||||
$player->msgs[] = $aseco->formatColors($head . $records);
|
||||
|
||||
// display popup message
|
||||
if (count($player->msgs) == 2) {
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'OK', '', 0);
|
||||
} else { // > 2
|
||||
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $player->msgs[1], 'Close', 'Next', 0);
|
||||
}
|
||||
|
||||
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||
$records = array();
|
||||
$i = 1;
|
||||
$lines = 0;
|
||||
$player->msgs = array();
|
||||
// reserve extra width for $w tags
|
||||
$extra = ($aseco->settings['lists_colornicks'] ? 0.2 : 0);
|
||||
$player->msgs[0] = array(1, $head, array(0.7+$extra, 0.1, 0.45+$extra, 0.15), array('BgRaceScore2', 'LadderRank'));
|
||||
foreach ($recs as $login => $rec) {
|
||||
// obtain nickname for this login
|
||||
$nick = $aseco->getPlayerNick($login);
|
||||
if (!$aseco->settings['lists_colornicks'])
|
||||
$nick = stripColors($nick);
|
||||
|
||||
$records[] = array(str_pad($i, 2, '0', STR_PAD_LEFT) . '.',
|
||||
$bgn . $nick,
|
||||
$rec);
|
||||
$i++;
|
||||
if (++$lines > 14) {
|
||||
$player->msgs[] = $records;
|
||||
$lines = 0;
|
||||
$records = array();
|
||||
}
|
||||
if ($i > $top) break;
|
||||
}
|
||||
// add if last batch exists
|
||||
if (!empty($records))
|
||||
$player->msgs[] = $records;
|
||||
|
||||
// display ManiaLink message
|
||||
display_manialink_multi($player);
|
||||
|
||||
} else { // TMS/TMO
|
||||
$records = $head;
|
||||
$i = 1;
|
||||
foreach ($recs as $login => $rec) {
|
||||
// obtain nickname for this login
|
||||
$nick = stripColors($aseco->getPlayerNick($login));
|
||||
|
||||
$records .= LF . $i . '. ' . $bgn
|
||||
. str_pad($nick, 15) . $end . ' - ' . $rec;
|
||||
$i++;
|
||||
if ($i > $top) break;
|
||||
}
|
||||
// show chat message
|
||||
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($records), $player->login);
|
||||
}
|
||||
} // chat_toprecs
|
||||
?>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue