Add Xaseco base files
This commit is contained in:
parent
716a54d4a5
commit
c63c24c949
|
@ -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,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,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
|
||||||
|
?>
|
|
@ -0,0 +1,306 @@
|
||||||
|
<?php
|
||||||
|
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chat plugin.
|
||||||
|
* Shows ranked records and their relations on the current track.
|
||||||
|
* Created by Xymph
|
||||||
|
*
|
||||||
|
* Dependencies: none
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!INHIBIT_RECCMDS) {
|
||||||
|
Aseco::addChatCommand('firstrec', 'Shows first ranked record on current track');
|
||||||
|
Aseco::addChatCommand('lastrec', 'Shows last ranked record on current track');
|
||||||
|
Aseco::addChatCommand('nextrec', 'Shows next better ranked record to beat');
|
||||||
|
Aseco::addChatCommand('diffrec', 'Shows your difference to first ranked record');
|
||||||
|
Aseco::addChatCommand('recrange', 'Shows difference first to last ranked record');
|
||||||
|
}
|
||||||
|
|
||||||
|
function chat_firstrec($aseco, $command) {
|
||||||
|
|
||||||
|
$login = $command['author']->login;
|
||||||
|
|
||||||
|
// check for relay server
|
||||||
|
if ($aseco->server->isrelay) {
|
||||||
|
$message = formatText($aseco->getChatMessage('NOTONRELAY'));
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($aseco->server->records->count() > 0) {
|
||||||
|
// get the first ranked record
|
||||||
|
$record = $aseco->server->records->getRecord(0);
|
||||||
|
|
||||||
|
// show chat message
|
||||||
|
$message = formatText($aseco->getChatMessage('FIRST_RECORD'))
|
||||||
|
. formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||||
|
1,
|
||||||
|
stripColors($record->player->nickname),
|
||||||
|
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||||
|
$record->score : formatTime($record->score)));
|
||||||
|
|
||||||
|
$message = substr($message, 0, strlen($message)-2); // strip trailing ", "
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
} else {
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No records found!'), $login);
|
||||||
|
}
|
||||||
|
} // chat_firstrec
|
||||||
|
|
||||||
|
function chat_lastrec($aseco, $command) {
|
||||||
|
|
||||||
|
$login = $command['author']->login;
|
||||||
|
|
||||||
|
// 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()) {
|
||||||
|
// get the last ranked record
|
||||||
|
$record = $aseco->server->records->getRecord($total-1);
|
||||||
|
|
||||||
|
// show chat message
|
||||||
|
$message = formatText($aseco->getChatMessage('LAST_RECORD'))
|
||||||
|
. formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||||
|
$total,
|
||||||
|
stripColors($record->player->nickname),
|
||||||
|
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||||
|
$record->score : formatTime($record->score)));
|
||||||
|
|
||||||
|
$message = substr($message, 0, strlen($message)-2); // strip trailing ", "
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
} else {
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No records found!'), $login);
|
||||||
|
}
|
||||||
|
} // chat_lastrec
|
||||||
|
|
||||||
|
function chat_nextrec($aseco, $command) {
|
||||||
|
|
||||||
|
$login = $command['author']->login;
|
||||||
|
|
||||||
|
// 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()) {
|
||||||
|
$found = false;
|
||||||
|
// find ranked record
|
||||||
|
for ($i = 0; $i < $total; $i++) {
|
||||||
|
$rec = $aseco->server->records->getRecord($i);
|
||||||
|
if ($rec->player->login == $login) {
|
||||||
|
$rank = $i;
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($found) {
|
||||||
|
// get current and next better ranked records
|
||||||
|
$nextrank = ($rank > 0 ? $rank-1 : 0);
|
||||||
|
$record = $aseco->server->records->getRecord($rank);
|
||||||
|
$next = $aseco->server->records->getRecord($nextrank);
|
||||||
|
|
||||||
|
// compute difference to next record
|
||||||
|
if ($aseco->server->gameinfo->mode != Gameinfo::STNT) {
|
||||||
|
$diff = $record->score - $next->score;
|
||||||
|
$sec = floor($diff/1000);
|
||||||
|
$hun = ($diff - ($sec * 1000)) / 10;
|
||||||
|
} else { // Stunts mode
|
||||||
|
$diff = $next->score - $record->score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// show chat message
|
||||||
|
$message1 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||||
|
$rank+1,
|
||||||
|
stripColors($record->player->nickname),
|
||||||
|
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||||
|
$record->score : formatTime($record->score)));
|
||||||
|
$message1 = substr($message1, 0, strlen($message1)-2); // strip trailing ", "
|
||||||
|
$message2 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||||
|
$nextrank+1,
|
||||||
|
stripColors($next->player->nickname),
|
||||||
|
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||||
|
$record->score : formatTime($next->score)));
|
||||||
|
$message2 = substr($message2, 0, strlen($message2)-2); // strip trailing ", "
|
||||||
|
$message = formatText($aseco->getChatMessage('DIFF_RECORD'),
|
||||||
|
$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 ranked record
|
||||||
|
$last = $aseco->server->records->getRecord($total-1);
|
||||||
|
|
||||||
|
// compute difference to next record
|
||||||
|
if ($aseco->server->gameinfo->mode != Gameinfo::STNT) {
|
||||||
|
$diff = $unranked->score - $last->score;
|
||||||
|
$sec = floor($diff/1000);
|
||||||
|
$hun = ($diff - ($sec * 1000)) / 10;
|
||||||
|
} else { // Stunts mode
|
||||||
|
$diff = $last->score - $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->player->nickname),
|
||||||
|
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||||
|
$last->score : formatTime($last->score)));
|
||||||
|
$message2 = substr($message2, 0, strlen($message2)-2); // strip trailing ", "
|
||||||
|
$message = formatText($aseco->getChatMessage('DIFF_RECORD'),
|
||||||
|
$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 record on this track yet... use {#highlite}$i/lastrec';
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No records found!'), $login);
|
||||||
|
}
|
||||||
|
} // chat_nextrec
|
||||||
|
|
||||||
|
function chat_diffrec($aseco, $command) {
|
||||||
|
|
||||||
|
$login = $command['author']->login;
|
||||||
|
|
||||||
|
// 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()) {
|
||||||
|
$found = false;
|
||||||
|
// find ranked record
|
||||||
|
for ($i = 0; $i < $total; $i++) {
|
||||||
|
$rec = $aseco->server->records->getRecord($i);
|
||||||
|
if ($rec->player->login == $login) {
|
||||||
|
$rank = $i;
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($found) {
|
||||||
|
// get current and first ranked records
|
||||||
|
$record = $aseco->server->records->getRecord($rank);
|
||||||
|
$first = $aseco->server->records->getRecord(0);
|
||||||
|
|
||||||
|
// compute difference to first record
|
||||||
|
if ($aseco->server->gameinfo->mode != Gameinfo::STNT) {
|
||||||
|
$diff = $record->score - $first->score;
|
||||||
|
$sec = floor($diff/1000);
|
||||||
|
$hun = ($diff - ($sec * 1000)) / 10;
|
||||||
|
} else { // Stunts mode
|
||||||
|
$diff = $first->score - $record->score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// show chat message
|
||||||
|
$message1 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||||
|
$rank+1,
|
||||||
|
stripColors($record->player->nickname),
|
||||||
|
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||||
|
$record->score : formatTime($record->score)));
|
||||||
|
$message1 = substr($message1, 0, strlen($message1)-2); // strip trailing ", "
|
||||||
|
$message2 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||||
|
1,
|
||||||
|
stripColors($first->player->nickname),
|
||||||
|
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||||
|
$first->score : formatTime($first->score)));
|
||||||
|
$message2 = substr($message2, 0, strlen($message2)-2); // strip trailing ", "
|
||||||
|
$message = formatText($aseco->getChatMessage('DIFF_RECORD'),
|
||||||
|
$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 record on this track yet... use {#highlite}$i/lastrec';
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No records found!'), $login);
|
||||||
|
}
|
||||||
|
} // chat_diffrec
|
||||||
|
|
||||||
|
function chat_recrange($aseco, $command) {
|
||||||
|
|
||||||
|
$login = $command['author']->login;
|
||||||
|
|
||||||
|
// 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()) {
|
||||||
|
// 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 mode
|
||||||
|
$diff = $first->score - $last->score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// show chat message
|
||||||
|
$message1 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||||
|
1,
|
||||||
|
stripColors($first->player->nickname),
|
||||||
|
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||||
|
$first->score : formatTime($first->score)));
|
||||||
|
$message1 = substr($message1, 0, strlen($message1)-2); // strip trailing ", "
|
||||||
|
$message2 = formatText($aseco->getChatMessage('RANKING_RECORD_NEW'),
|
||||||
|
$total,
|
||||||
|
stripColors($last->player->nickname),
|
||||||
|
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||||
|
$last->score : formatTime($last->score)));
|
||||||
|
$message2 = substr($message2, 0, strlen($message2)-2); // strip trailing ", "
|
||||||
|
$message = formatText($aseco->getChatMessage('DIFF_RECORD'),
|
||||||
|
$message1, $message2,
|
||||||
|
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||||
|
$diff : sprintf("%d.%02d", $sec, $hun)));
|
||||||
|
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
} else {
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No records found!'), $login);
|
||||||
|
}
|
||||||
|
} // chat_recrange
|
||||||
|
?>
|
|
@ -0,0 +1,424 @@
|
||||||
|
<?php
|
||||||
|
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chat plugin.
|
||||||
|
* Displays server/XAseco info & plugins/nations lists.
|
||||||
|
* Created by Xymph
|
||||||
|
*
|
||||||
|
* Dependencies: none
|
||||||
|
*/
|
||||||
|
|
||||||
|
Aseco::addChatCommand('server', 'Displays info about this server');
|
||||||
|
Aseco::addChatCommand('xaseco', 'Displays info about this XASECO');
|
||||||
|
Aseco::addChatCommand('plugins', 'Displays list of active plugins');
|
||||||
|
Aseco::addChatCommand('nations', 'Displays top 10 most visiting nations');
|
||||||
|
|
||||||
|
function chat_server($aseco, $command) {
|
||||||
|
global $maxrecs, $admin_contact, $feature_votes; // from rasp.settings.php
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
$login = $player->login;
|
||||||
|
|
||||||
|
// collect players/nations stats
|
||||||
|
$query = 'SELECT COUNT(Id), COUNT(DISTINCT Nation), SUM(TimePlayed) FROM players';
|
||||||
|
$res = mysql_query($query);
|
||||||
|
if (mysql_num_rows($res) > 0) {
|
||||||
|
$row = mysql_fetch_row($res);
|
||||||
|
$players = $row[0];
|
||||||
|
$nations = $row[1];
|
||||||
|
$totaltime = $row[2];
|
||||||
|
mysql_free_result($res);
|
||||||
|
$playdays = floor($totaltime / (24 * 3600));
|
||||||
|
$playtime = $totaltime - ($playdays * 24 * 3600);
|
||||||
|
} else {
|
||||||
|
mysql_free_result($res);
|
||||||
|
trigger_error('No players/nations stats found!', E_USER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get server uptime
|
||||||
|
$aseco->client->query('GetNetworkStats');
|
||||||
|
$network = $aseco->client->getResponse();
|
||||||
|
$aseco->server->uptime = $network['Uptime'];
|
||||||
|
$updays = floor($aseco->server->uptime / (24 * 3600));
|
||||||
|
$uptime = $aseco->server->uptime - ($updays * 24 * 3600);
|
||||||
|
|
||||||
|
// showing info for TMN
|
||||||
|
if ($aseco->server->getGame() == 'TMN') {
|
||||||
|
|
||||||
|
$stats = 'Welcome to: ' . $aseco->server->name . '$z' . LF . LF;
|
||||||
|
$stats .= '$gServer Date : {#black}' . date('M d, Y') . LF;
|
||||||
|
$stats .= '$gServer Time : {#black}' . date('H:i:s T') . LF;
|
||||||
|
$stats .= '$gUptime : {#black}' . $updays . ' day' . ($updays == 1 ? ' ' : 's ') . formatTimeH($uptime * 1000, false) . LF;
|
||||||
|
$stats .= '$gTrack Count : {#black}' . $aseco->server->gameinfo->numchall . LF;
|
||||||
|
$stats .= '$gGame Mode : {#black}' . $aseco->server->gameinfo->getMode() . LF;
|
||||||
|
switch ($aseco->server->gameinfo->mode) {
|
||||||
|
case 0:
|
||||||
|
$stats .= '$gPoints Limit : {#black}' . $aseco->server->gameinfo->rndslimit . LF;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
$stats .= '$gTime Limit : {#black}' . formatTime($aseco->server->gameinfo->timelimit) . LF;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$stats .= '$gPoints Limit : {#black}' . $aseco->server->gameinfo->teamlimit . LF;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
$stats .= '$gTime Limit : {#black}' . formatTime($aseco->server->gameinfo->lapslimit) . LF;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$stats .= '$gMax Players : {#black}' . $aseco->server->maxplay . LF;
|
||||||
|
$stats .= '$gMax Specs : {#black}' . $aseco->server->maxspec . LF;
|
||||||
|
$stats .= '$gRecs/Track : {#black}' . $maxrecs . LF;
|
||||||
|
if ($feature_votes) {
|
||||||
|
$stats .= '$gVoting info : {#black}/helpvote' . LF;
|
||||||
|
} else {
|
||||||
|
$stats .= '$gVote Timeout : {#black}' . formatTime($aseco->server->votetime) . LF;
|
||||||
|
$stats .= '$gVote Ratio : {#black}' . round($aseco->server->voterate, 2) . LF;
|
||||||
|
}
|
||||||
|
if ($admin_contact) {
|
||||||
|
$stats .= '$gAdmin Contact: {#black}' . $admin_contact . LF;
|
||||||
|
}
|
||||||
|
$stats .= LF . '$gVisited by $f80' . $players . ' $gPlayers from $f40' . $nations . ' $gNations' . LF;
|
||||||
|
$stats .= 'who together played: {#black}' . $playdays . ' day' . ($playdays == 1 ? ' ' : 's ') . formatTimeH($playtime * 1000, false) . ' $g!';
|
||||||
|
|
||||||
|
// display popup message
|
||||||
|
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $aseco->formatColors($stats), 'OK', '', 0);
|
||||||
|
|
||||||
|
// showing info for TMF
|
||||||
|
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||||
|
|
||||||
|
// get more server settings in one go
|
||||||
|
$comment = $aseco->client->addCall('GetServerComment', array());
|
||||||
|
$coppers = $aseco->client->addCall('GetServerCoppers', array());
|
||||||
|
$cuprpc = $aseco->client->addCall('GetCupRoundsPerChallenge', array());
|
||||||
|
if (!$aseco->client->multiquery()) {
|
||||||
|
trigger_error('[' . $aseco->client->getErrorCode() . '] GetServer (multi) - ' . $aseco->client->getErrorMessage(), E_USER_WARNING);
|
||||||
|
} else {
|
||||||
|
$response = $aseco->client->getResponse();
|
||||||
|
$comment = $response[$comment][0];
|
||||||
|
$coppers = $response[$coppers][0];
|
||||||
|
$cuprpc = $response[$cuprpc][0]['CurrentValue'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$header = 'Welcome to: ' . $aseco->server->name;
|
||||||
|
$stats = array();
|
||||||
|
$stats[] = array('Server Date', '{#black}' . date('M d, Y'));
|
||||||
|
$stats[] = array('Server Time', '{#black}' . date('H:i:s T'));
|
||||||
|
$stats[] = array('Zone', '{#black}' . $aseco->server->zone);
|
||||||
|
$field = 'Comment';
|
||||||
|
|
||||||
|
// break up long line into chunks with continuation strings
|
||||||
|
$multicmt = explode(LF, wordwrap($comment, 35, LF . '...'));
|
||||||
|
foreach ($multicmt as $line) {
|
||||||
|
$stats[] = array($field, '{#black}' . $line);
|
||||||
|
$field = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$stats[] = array('Uptime', '{#black}' . $updays . ' day' . ($updays == 1 ? ' ' : 's ') . formatTimeH($uptime * 1000, false));
|
||||||
|
if ($aseco->server->isrelay)
|
||||||
|
$stats[] = array('Relays', '{#black}' . $aseco->server->relaymaster['Login'] .
|
||||||
|
' / ' . $aseco->server->relaymaster['NickName']);
|
||||||
|
else
|
||||||
|
$stats[] = array('Track Count', '{#black}' . $aseco->server->gameinfo->numchall);
|
||||||
|
$stats[] = array('Game Mode', '{#black}' . $aseco->server->gameinfo->getMode());
|
||||||
|
switch ($aseco->server->gameinfo->mode) {
|
||||||
|
case 0:
|
||||||
|
$stats[] = array('Points Limit', '{#black}' . $aseco->server->gameinfo->rndslimit);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
$stats[] = array('Time Limit', '{#black}' . formatTime($aseco->server->gameinfo->timelimit));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$stats[] = array('Points Limit', '{#black}' . $aseco->server->gameinfo->teamlimit);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
$stats[] = array('Time Limit', '{#black}' . formatTime($aseco->server->gameinfo->lapslimit));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
$stats[] = array('Time Limit', '{#black}' . formatTime(5 * 60 * 1000)); // always 5 minutes?
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
$stats[] = array('Points Limit', '{#black}' . $aseco->server->gameinfo->cuplimit . '$g R/C: {#black}' . $cuprpc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$stats[] = array('Max Players', '{#black}' . $aseco->server->maxplay);
|
||||||
|
$stats[] = array('Max Specs', '{#black}' . $aseco->server->maxspec);
|
||||||
|
$stats[] = array('Recs/Track', '{#black}' . $maxrecs);
|
||||||
|
if ($feature_votes) {
|
||||||
|
$stats[] = array('Voting info', '{#black}/helpvote');
|
||||||
|
} else {
|
||||||
|
$stats[] = array('Vote Timeout', '{#black}' . formatTime($aseco->server->votetime));
|
||||||
|
$stats[] = array('Vote Ratio', '{#black}' . round($aseco->server->voterate, 2));
|
||||||
|
}
|
||||||
|
// check for TMUF server
|
||||||
|
if ($aseco->server->rights) {
|
||||||
|
$stats[] = array('Rights', '{#black}United' .
|
||||||
|
($aseco->allowAbility($player, 'server_coppers') ?
|
||||||
|
' $gCoppers: {#black}' . $coppers : ''));
|
||||||
|
} else { // TMNF
|
||||||
|
$stats[] = array('Rights', '{#black}Nations');
|
||||||
|
}
|
||||||
|
$stats[] = array('Ladder Limits', '{#black}' . $aseco->server->laddermin .
|
||||||
|
'$g - {#black}' . $aseco->server->laddermax);
|
||||||
|
if ($admin_contact) {
|
||||||
|
$stats[] = array('Admin Contact', '{#black}' . $admin_contact);
|
||||||
|
}
|
||||||
|
$stats[] = array();
|
||||||
|
$stats[] = array('Visited by $f80' . $players . ' $gPlayers from $f40' . $nations . ' $gNations');
|
||||||
|
$stats[] = array('who together played: {#black}' . $playdays . ' day' . ($playdays == 1 ? ' ' : 's ') . formatTimeH($playtime * 1000, false) . ' $g!');
|
||||||
|
|
||||||
|
// display ManiaLink message
|
||||||
|
display_manialink($login, $header, array('Icons64x64_1', 'DisplaySettings', 0.01), $stats, array(1.0, 0.3, 0.7), 'OK');
|
||||||
|
|
||||||
|
} else { // TMS/TMO
|
||||||
|
$stats = '{#server}>> Server Stats' . LF;
|
||||||
|
$stats .= 'Showing info of ' . $aseco->server->name . LF;
|
||||||
|
// no info actually shown
|
||||||
|
|
||||||
|
// show chat message
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($stats), $login);
|
||||||
|
}
|
||||||
|
} // chat_server
|
||||||
|
|
||||||
|
function chat_xaseco($aseco, $command) {
|
||||||
|
global $admin_contact; // from rasp.settings.php
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
$login = $player->login;
|
||||||
|
|
||||||
|
$uptime = time() - $aseco->uptime;
|
||||||
|
$updays = floor($uptime / (24 * 3600));
|
||||||
|
$uptime = $uptime - ($updays * 24 * 3600);
|
||||||
|
|
||||||
|
// showing info for TMN
|
||||||
|
if ($aseco->server->getGame() == 'TMN') {
|
||||||
|
|
||||||
|
$info = 'XASECO info: ' . $aseco->server->name . '$z' . LF . LF;
|
||||||
|
$info .= '$gVersion : {#black}' . XASECO_VERSION . LF;
|
||||||
|
$info .= '$gUptime : {#black}' . $updays . ' day' . ($updays == 1 ? ' ' : 's ') . formatTimeH($uptime * 1000, false) . LF;
|
||||||
|
$info .= '$gWebsites : {#black}' . XASECO_ORG . LF;
|
||||||
|
$info .= '$g {#black}' . XASECO_TMN . LF;
|
||||||
|
$info .= '$g {#black}' . XASECO_TMF . LF;
|
||||||
|
$info .= '$g {#black}' . XASECO_TM2 . LF;
|
||||||
|
$info .= '$gCredits : {#black}Main author: Xymph (since v0.8)' . LF;
|
||||||
|
$info .= '$g {#black}Original authors: $nFlo, Assembler Maniac, Jfreu & others$m' . LF;
|
||||||
|
if (isset($aseco->masteradmin_list['TMLOGIN'])) {
|
||||||
|
// count non-LAN logins
|
||||||
|
$count = 0;
|
||||||
|
foreach ($aseco->masteradmin_list['TMLOGIN'] as $lgn) {
|
||||||
|
if ($lgn != '' && !isLANLogin($lgn)) {
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($count > 0) {
|
||||||
|
$field = 'Masteradmin';
|
||||||
|
if ($count > 1)
|
||||||
|
$field .= 's';
|
||||||
|
else
|
||||||
|
$field .= ' ';
|
||||||
|
$field .= ' : ';
|
||||||
|
foreach ($aseco->masteradmin_list['TMLOGIN'] as $lgn) {
|
||||||
|
// skip any LAN logins
|
||||||
|
if ($lgn != '' && !isLANLogin($lgn)) {
|
||||||
|
$info .= '$g' . $field . '{#black}' . $aseco->getPlayerNick($lgn) . '$z' . LF;
|
||||||
|
$field = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($admin_contact) {
|
||||||
|
$info .= '$gAdmin Contact: {#black}' . $admin_contact . LF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// display popup message
|
||||||
|
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $aseco->formatColors($info), 'OK', '', 0);
|
||||||
|
|
||||||
|
// showing info for TMF
|
||||||
|
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||||
|
|
||||||
|
// prepare Welcome message
|
||||||
|
$welcome = formatText($aseco->getChatMessage('WELCOME'),
|
||||||
|
stripColors($player->nickname),
|
||||||
|
$aseco->server->name, XASECO_VERSION);
|
||||||
|
|
||||||
|
$header = 'XASECO info: ' . $aseco->server->name;
|
||||||
|
$info = array();
|
||||||
|
$info[] = array('Version', '{#black}' . XASECO_VERSION);
|
||||||
|
$field = 'Welcome';
|
||||||
|
$welcome = preg_split('/{br}/', $aseco->formatColors($welcome));
|
||||||
|
foreach ($welcome as $line) {
|
||||||
|
$info[] = array($field, '{#black}' . $line);
|
||||||
|
$field = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$info[] = array('Uptime', '{#black}' . $updays . ' day' . ($updays == 1 ? ' ' : 's ') . formatTimeH($uptime * 1000, false));
|
||||||
|
$info[] = array('Websites', '{#black}$l[' . XASECO_ORG . ']' . XASECO_ORG . '$l');
|
||||||
|
$info[] = array('', '{#black}$l[' . XASECO_TMN . ']' . XASECO_TMN . '$l');
|
||||||
|
$info[] = array('', '{#black}$l[' . XASECO_TMF . ']' . XASECO_TMF . '$l');
|
||||||
|
$info[] = array('', '{#black}$l[' . XASECO_TM2 . ']' . XASECO_TM2 . '$l');
|
||||||
|
$info[] = array('Credits', '{#black}Main author: Xymph (since v0.8)');
|
||||||
|
$info[] = array('', '{#black}Original authors: Flo, Assembler Maniac, Jfreu & others');
|
||||||
|
if (isset($aseco->masteradmin_list['TMLOGIN'])) {
|
||||||
|
// count non-LAN logins
|
||||||
|
$count = 0;
|
||||||
|
foreach ($aseco->masteradmin_list['TMLOGIN'] as $lgn) {
|
||||||
|
if ($lgn != '' && !isLANLogin($lgn)) {
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($count > 0) {
|
||||||
|
$field = 'Masteradmin';
|
||||||
|
if ($count > 1)
|
||||||
|
$field .= 's';
|
||||||
|
foreach ($aseco->masteradmin_list['TMLOGIN'] as $lgn) {
|
||||||
|
// skip any LAN logins
|
||||||
|
if ($lgn != '' && !isLANLogin($lgn)) {
|
||||||
|
$info[] = array($field, '{#black}' . $aseco->getPlayerNick($lgn) . '$z');
|
||||||
|
$field = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($admin_contact) {
|
||||||
|
$info[] = array('Admin Contact', '{#black}' . $admin_contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
// display ManiaLink message
|
||||||
|
display_manialink($login, $header, array('BgRaceScore2', 'Warmup'), $info, array(1.0, 0.3, 0.7), 'OK');
|
||||||
|
|
||||||
|
} else { // TMS/TMO
|
||||||
|
$info = '{#server}>> XASECO Info' . LF;
|
||||||
|
$info .= 'Showing info of ' . $aseco->server->name . LF;
|
||||||
|
// no info actually shown
|
||||||
|
|
||||||
|
// show chat message
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($info), $login);
|
||||||
|
}
|
||||||
|
} // chat_xaseco
|
||||||
|
|
||||||
|
function chat_plugins($aseco, $command) {
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
|
||||||
|
// display plugins list for TMN
|
||||||
|
if ($aseco->server->getGame() == 'TMN') {
|
||||||
|
$head = $aseco->formatColors('Currently active plugins:{#black}') . LF;
|
||||||
|
$list = '';
|
||||||
|
$lines = 0;
|
||||||
|
$player->msgs = array();
|
||||||
|
$player->msgs[0] = 1;
|
||||||
|
// create list of plugins
|
||||||
|
foreach ($aseco->plugins as $plugin) {
|
||||||
|
$list .= $plugin . LF;
|
||||||
|
if (++$lines > 14) {
|
||||||
|
$player->msgs[] = $head . $list;
|
||||||
|
$lines = 0;
|
||||||
|
$list = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add if last batch exists
|
||||||
|
if ($list != '')
|
||||||
|
$player->msgs[] = $head . $list;
|
||||||
|
|
||||||
|
// 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 plugins list for TMF
|
||||||
|
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||||
|
$head = 'Currently active plugins:';
|
||||||
|
$list = array();
|
||||||
|
$lines = 0;
|
||||||
|
$player->msgs = array();
|
||||||
|
$player->msgs[0] = array(1, $head, array(0.7), array('Icons128x128_1', 'Browse', 0.02));
|
||||||
|
// create list of plugins
|
||||||
|
foreach ($aseco->plugins as $plugin) {
|
||||||
|
$list[] = array('{#black}' . $plugin);
|
||||||
|
if (++$lines > 14) {
|
||||||
|
$player->msgs[] = $list;
|
||||||
|
$lines = 0;
|
||||||
|
$list = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add if last batch exists
|
||||||
|
if (!empty($list))
|
||||||
|
$player->msgs[] = $list;
|
||||||
|
|
||||||
|
// display ManiaLink message
|
||||||
|
display_manialink_multi($player);
|
||||||
|
} // TMO/TMS
|
||||||
|
} // chat_plugins
|
||||||
|
|
||||||
|
function chat_nations($aseco, $command) {
|
||||||
|
|
||||||
|
if ($aseco->server->getGame() == 'TMN')
|
||||||
|
$top = 10;
|
||||||
|
elseif ($aseco->server->getGame() == 'TMF')
|
||||||
|
$top = 10;
|
||||||
|
else // TMS/TMO
|
||||||
|
$top = 4;
|
||||||
|
|
||||||
|
$query = 'SELECT Nation, COUNT(Nation) AS count FROM players GROUP BY Nation ORDER BY count DESC LIMIT ' . $top;
|
||||||
|
$res = mysql_query($query);
|
||||||
|
|
||||||
|
// collect and sort nations
|
||||||
|
if (mysql_num_rows($res) > 0) {
|
||||||
|
$nations = array();
|
||||||
|
while ($row = mysql_fetch_row($res)) {
|
||||||
|
$nations[$row[0]] = $row[1];
|
||||||
|
}
|
||||||
|
mysql_free_result($res);
|
||||||
|
} else {
|
||||||
|
trigger_error('No players/nations found!', E_USER_WARNING);
|
||||||
|
mysql_free_result($res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
arsort($nations);
|
||||||
|
|
||||||
|
if ($aseco->server->getGame() == 'TMN') {
|
||||||
|
$nats = 'TOP 10 Most Visiting Nations:';
|
||||||
|
$bgn = '{#black}'; // nation begin
|
||||||
|
$end = '$g'; // ... & end colors
|
||||||
|
|
||||||
|
// compile sorted nations
|
||||||
|
$i = 1;
|
||||||
|
foreach ($nations as $nat => $tot) {
|
||||||
|
$nats .= LF . $i++ . '. ' . $bgn . $nat . $end . ' - ' . $tot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// display popup message
|
||||||
|
$aseco->client->query('SendDisplayServerMessageToLogin', $command['author']->login, $aseco->formatColors($nats), 'OK', '', 0);
|
||||||
|
|
||||||
|
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||||
|
$header = 'TOP 10 Most Visiting Nations:';
|
||||||
|
$nats = array();
|
||||||
|
$bgn = '{#black}'; // nation begin
|
||||||
|
|
||||||
|
// compile sorted nations
|
||||||
|
$i = 1;
|
||||||
|
foreach ($nations as $nat => $tot) {
|
||||||
|
$nats[] = array($i++ . '.', $bgn . $nat, $tot);
|
||||||
|
}
|
||||||
|
|
||||||
|
// display ManiaLink message
|
||||||
|
display_manialink($command['author']->login, $header, array('Icons128x128_1', 'Credits'), $nats, array(0.8, 0.1, 0.4, 0.3), 'OK');
|
||||||
|
|
||||||
|
} else { // TMS/TMO
|
||||||
|
$nats = '{#server}> TOP 4 Most Visiting Nations:{#highlite}';
|
||||||
|
$bgn = '{#highlite}';
|
||||||
|
$end = '{#highlite}';
|
||||||
|
|
||||||
|
// compile sorted nations
|
||||||
|
$i = 1;
|
||||||
|
foreach ($nations as $nat => $tot) {
|
||||||
|
$nats .= LF . $i++ . '. ' . $bgn . $nat . $end . ' - ' . $tot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// show chat message
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($nats), $command['author']->login);
|
||||||
|
}
|
||||||
|
} // chat_nations
|
||||||
|
?>
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chat plugin.
|
||||||
|
* Shows (file)names of current track's song & mod.
|
||||||
|
* Created by Xymph
|
||||||
|
*
|
||||||
|
* Dependencies: none
|
||||||
|
*/
|
||||||
|
|
||||||
|
Aseco::addChatCommand('song', 'Shows filename of current track\'s song');
|
||||||
|
Aseco::addChatCommand('mod', 'Shows (file)name of current track\'s mod');
|
||||||
|
|
||||||
|
function chat_song($aseco, $command) {
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
|
||||||
|
// check for track's song
|
||||||
|
if ($aseco->server->challenge->gbx->songFile) {
|
||||||
|
$message = formatText($aseco->getChatMessage('SONG'),
|
||||||
|
stripColors($aseco->server->challenge->name),
|
||||||
|
$aseco->server->challenge->gbx->songFile);
|
||||||
|
// use only first parameter
|
||||||
|
$command['params'] = explode(' ', $command['params'], 2);
|
||||||
|
if ((strtolower($command['params'][0]) == 'url' ||
|
||||||
|
strtolower($command['params'][0]) == 'loc') &&
|
||||||
|
$aseco->server->challenge->gbx->songUrl) {
|
||||||
|
$message .= LF . '{#highlite}$l[' . $aseco->server->challenge->gbx->songUrl . ']' . $aseco->server->challenge->gbx->songUrl . '$l';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message = '{#server}> {#error}No track song found!';
|
||||||
|
if ($aseco->server->getGame() == 'TMF' && function_exists('chat_music'))
|
||||||
|
$message .= ' Try {#highlite}$i /music current {#error}instead.';
|
||||||
|
}
|
||||||
|
// show chat message
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||||
|
} // chat_song
|
||||||
|
|
||||||
|
function chat_mod($aseco, $command) {
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
|
||||||
|
// check for track's mod
|
||||||
|
if ($aseco->server->challenge->gbx->modName) {
|
||||||
|
$message = formatText($aseco->getChatMessage('MOD'),
|
||||||
|
stripColors($aseco->server->challenge->name),
|
||||||
|
$aseco->server->challenge->gbx->modName,
|
||||||
|
$aseco->server->challenge->gbx->modFile);
|
||||||
|
// use only first parameter
|
||||||
|
$command['params'] = explode(' ', $command['params'], 2);
|
||||||
|
if ((strtolower($command['params'][0]) == 'url' ||
|
||||||
|
strtolower($command['params'][0]) == 'loc') &&
|
||||||
|
$aseco->server->challenge->gbx->modUrl) {
|
||||||
|
$message .= LF . '{#highlite}$l[' . $aseco->server->challenge->gbx->modUrl . ']' . $aseco->server->challenge->gbx->modUrl . '$l';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message = '{#server}> {#error}No track mod found!';
|
||||||
|
}
|
||||||
|
// show chat message
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||||
|
} // chat_mod
|
||||||
|
?>
|
|
@ -0,0 +1,357 @@
|
||||||
|
<?php
|
||||||
|
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chat plugin.
|
||||||
|
* Displays player statistics & personal settings.
|
||||||
|
* Updated by Xymph
|
||||||
|
*
|
||||||
|
* Dependencies: requires chat.records2.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once('includes/tmndatafetcher.inc.php'); // provides access to TMN world stats
|
||||||
|
|
||||||
|
Aseco::addChatCommand('stats', 'Displays statistics of current player');
|
||||||
|
Aseco::addChatCommand('statsall', 'Displays world statistics of a player');
|
||||||
|
Aseco::addChatCommand('settings', 'Displays your personal settings');
|
||||||
|
|
||||||
|
// calls function get_recs() from chat.records2.php
|
||||||
|
function chat_stats($aseco, $command) {
|
||||||
|
global $rasp, $feature_ranks, $maxrecs;
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
$target = $player;
|
||||||
|
|
||||||
|
// check for optional player parameter
|
||||||
|
if ($command['params'] != '')
|
||||||
|
if (!$target = $aseco->getPlayerParam($player, $command['params'], true))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// showing stats for TMN
|
||||||
|
if ($aseco->server->getGame() == 'TMN') {
|
||||||
|
|
||||||
|
// get current player info
|
||||||
|
$aseco->client->resetError();
|
||||||
|
$aseco->client->query('GetPlayerInfo', $target->login);
|
||||||
|
$info = $aseco->client->getResponse();
|
||||||
|
if ($aseco->client->isError()) {
|
||||||
|
$rank = 0;
|
||||||
|
$score = 0;
|
||||||
|
} else {
|
||||||
|
$rank = $info['LadderStats']['Ranking'];
|
||||||
|
$score = $info['LadderStats']['Score'];
|
||||||
|
}
|
||||||
|
// format ladder rank with narrow spaces between the thousands
|
||||||
|
$rank = str_replace(' ', '$n $m', number_format($rank, 0, ' ', ' '));
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
$records = 0;
|
||||||
|
if ($list = get_recs($target->id)) { // from chat.records2.php
|
||||||
|
// sort for best records
|
||||||
|
asort($list);
|
||||||
|
// count total ranked records
|
||||||
|
foreach ($list as $name => $rec) {
|
||||||
|
// stop upon unranked record
|
||||||
|
if ($rec > $maxrecs) break;
|
||||||
|
// count ranked record
|
||||||
|
$records++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$stats = 'Stats for: ' . $target->nickname . '$z / {#login}' . $target->login . LF . LF;
|
||||||
|
$stats .= '$gServer Date : {#black}' . date('M d, Y') . LF;
|
||||||
|
$stats .= '$gServer Time : {#black}' . date('H:i:s T') . LF;
|
||||||
|
$stats .= '$gTime Played : {#black}' . formatTimeH($target->getTimePlayed() * 1000, false) . LF;
|
||||||
|
$stats .= '$gLast Online : {#black}' . preg_replace('/^\d\d\d\d/', '\$n$0\$m', preg_replace('/:\d\d$/', '', $laston[0])) . LF;
|
||||||
|
if ($feature_ranks) {
|
||||||
|
$stats .= '$gServer Rank : {#black}' . $rasp->getRank($target->login) . LF;
|
||||||
|
}
|
||||||
|
$stats .= '$gRecords : {#black}' . $records . LF;
|
||||||
|
$stats .= '$gRaces Won : {#black}' . ($target->getWins() > $target->wins ? $target->getWins() : $target->wins) . LF;
|
||||||
|
$stats .= '$gLadder Rank : {#black}' . $rank . LF;
|
||||||
|
$stats .= '$gLadder Score: {#black}' . round($score, 1) . LF;
|
||||||
|
$stats .= '$gNation : {#black}' . $target->nation . LF;
|
||||||
|
$stats .= '$gClan : {#black}' . ($target->teamname ? $target->teamname . '$z' : '<none>') . LF;
|
||||||
|
if ($aseco->allowAbility($player, 'chat_statsip')) {
|
||||||
|
$stats .= '$gIP : {#black}' . $target->ipport;
|
||||||
|
}
|
||||||
|
|
||||||
|
// display popup message
|
||||||
|
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $aseco->formatColors($stats), 'OK', '', 0);
|
||||||
|
|
||||||
|
// showing stats for TMF
|
||||||
|
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||||
|
|
||||||
|
// get current player info
|
||||||
|
$aseco->client->resetError();
|
||||||
|
$aseco->client->query('GetDetailedPlayerInfo', $target->login);
|
||||||
|
$info = $aseco->client->getResponse();
|
||||||
|
if ($aseco->client->isError()) {
|
||||||
|
$rank = 0;
|
||||||
|
$score = 0;
|
||||||
|
$lastm = 0;
|
||||||
|
$wins = 0;
|
||||||
|
$draws = 0;
|
||||||
|
$losses = 0;
|
||||||
|
$zone = '';
|
||||||
|
$inscrdays = 0;
|
||||||
|
$inscrhours = 0;
|
||||||
|
} else {
|
||||||
|
$rank = $info['LadderStats']['PlayerRankings'][0]['Ranking'];
|
||||||
|
$score = $info['LadderStats']['PlayerRankings'][0]['Score'];
|
||||||
|
$lastm = $info['LadderStats']['LastMatchScore'];
|
||||||
|
$wins = $info['LadderStats']['NbrMatchWins'];
|
||||||
|
$draws = $info['LadderStats']['NbrMatchDraws'];
|
||||||
|
$losses = $info['LadderStats']['NbrMatchLosses'];
|
||||||
|
|
||||||
|
// get zone info
|
||||||
|
$zone = substr($info['Path'], 6); // strip 'World|'
|
||||||
|
$inscr = $info['HoursSinceZoneInscription'];
|
||||||
|
$inscrdays = floor($inscr / 24);
|
||||||
|
$inscrhours = $inscr - ($inscrdays * 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
// format numbers with narrow spaces between the thousands
|
||||||
|
$frank = str_replace(' ', '$n $m', number_format($rank, 0, ' ', ' '));
|
||||||
|
$fwins = str_replace(' ', '$n $m', number_format($wins, 0, ' ', ' '));
|
||||||
|
$fdraws = str_replace(' ', '$n $m', number_format($draws, 0, ' ', ' '));
|
||||||
|
$flosses = str_replace(' ', '$n $m', number_format($losses, 0, ' ', ' '));
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
$records = 0;
|
||||||
|
if ($list = get_recs($target->id)) { // from chat.records2.php
|
||||||
|
// sort for best records
|
||||||
|
asort($list);
|
||||||
|
// count total ranked records
|
||||||
|
foreach ($list as $name => $rec) {
|
||||||
|
// stop upon unranked record
|
||||||
|
if ($rec > $maxrecs) break;
|
||||||
|
// count ranked record
|
||||||
|
$records++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$header = 'Stats for: ' . $target->nickname . '$z / {#login}' . $target->login;
|
||||||
|
$stats = array();
|
||||||
|
$stats[] = array('Server Date', '{#black}' . date('M d, Y'));
|
||||||
|
$stats[] = array('Server Time', '{#black}' . date('H:i:s T'));
|
||||||
|
$value = '{#black}' . formatTimeH($target->getTimePlayed() * 1000, false);
|
||||||
|
// add clickable button
|
||||||
|
if ($aseco->settings['clickable_lists'])
|
||||||
|
$value = array($value, -5); // action id
|
||||||
|
$stats[] = array('Time Played', $value);
|
||||||
|
$stats[] = array('Last Online', '{#black}' . preg_replace('/:\d\d$/', '', $laston[0]));
|
||||||
|
if ($feature_ranks) {
|
||||||
|
$value = '{#black}' . $rasp->getRank($target->login);
|
||||||
|
// add clickable button
|
||||||
|
if ($aseco->settings['clickable_lists'])
|
||||||
|
$value = array($value, -6); // action id
|
||||||
|
$stats[] = array('Server Rank', $value);
|
||||||
|
}
|
||||||
|
$value = '{#black}' . $records;
|
||||||
|
// add clickable button
|
||||||
|
if ($aseco->settings['clickable_lists'])
|
||||||
|
$value = array($value, 5); // action id
|
||||||
|
$stats[] = array('Records', $value);
|
||||||
|
$value = '{#black}' . ($target->getWins() > $target->wins ? $target->getWins() : $target->wins);
|
||||||
|
// add clickable button
|
||||||
|
if ($aseco->settings['clickable_lists'])
|
||||||
|
$value = array($value, 6); // action id
|
||||||
|
$stats[] = array('Races Won', $value);
|
||||||
|
$stats[] = array('Ladder Rank', '{#black}' . $frank);
|
||||||
|
$stats[] = array('Ladder Score', '{#black}' . round($score, 1));
|
||||||
|
$stats[] = array('Last Match', '{#black}' . round($lastm, 1));
|
||||||
|
$stats[] = array('Wins', '{#black}' . $fwins);
|
||||||
|
$stats[] = array('Draws', '{#black}' . $fdraws . ($losses != 0 ?
|
||||||
|
' $gW/L: {#black}' . round($wins / $losses, 3) : ''));
|
||||||
|
$stats[] = array('Losses', '{#black}' . $flosses);
|
||||||
|
$stats[] = array('Zone', '{#black}' . $zone);
|
||||||
|
$stats[] = array('Inscribed', '{#black}' . $inscrdays . ' day' . ($inscrdays == 1 ? ' ' : 's ') . $inscrhours . ' hours');
|
||||||
|
$stats[] = array('Rights', '{#black}' . ($target->rights ? 'United' : 'Nations'));
|
||||||
|
if ($aseco->server->rights) {
|
||||||
|
$stats[] = array('Donations', '{#black}' . ($target->rights ? ldb_getDonations($aseco, $target->login) : 'N/A'));
|
||||||
|
}
|
||||||
|
$stats[] = array('Clan', '{#black}' . ($target->teamname ? $target->teamname . '$z' : '<none>'));
|
||||||
|
$stats[] = array('Client', '{#black}' . $target->client);
|
||||||
|
if ($aseco->allowAbility($player, 'chat_statsip')) {
|
||||||
|
$stats[] = array('IP', '{#black}' . $target->ipport);
|
||||||
|
}
|
||||||
|
|
||||||
|
// display ManiaLink message
|
||||||
|
display_manialink($player->login, $header, array('Icons128x128_1', 'Statistics', 0.03), $stats, array(1.0, 0.3, 0.7), 'OK');
|
||||||
|
|
||||||
|
} else { // TMS/TMO
|
||||||
|
$stats = '{#server}> XASECO Stats' . LF;
|
||||||
|
$stats .= 'Showing stats of ' . $target->nickname . LF;
|
||||||
|
$stats .= 'Time Played: ' . formatTimeH($target->getTimePlayed() * 1000, false) . LF;
|
||||||
|
$stats .= 'Races Won: ' . $target->getWins();
|
||||||
|
|
||||||
|
// show chat message
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($stats), $player->login);
|
||||||
|
}
|
||||||
|
} // chat_stats
|
||||||
|
|
||||||
|
function chat_statsall($aseco, $command) {
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
$target = $player;
|
||||||
|
|
||||||
|
// showing stats for TMN only
|
||||||
|
if ($aseco->server->getGame() == 'TMN') {
|
||||||
|
// check for optional player parameter
|
||||||
|
if ($command['params'] != '') {
|
||||||
|
$login = $command['params'];
|
||||||
|
if (is_numeric($login)) {
|
||||||
|
if (!$target = $aseco->getPlayerParam($player, $login, true)) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
$login = $target->login;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$login = $player->login;
|
||||||
|
}
|
||||||
|
|
||||||
|
// obtain external stats
|
||||||
|
$data = new TMNDataFetcher($login, true);
|
||||||
|
if (!$data->nickname) {
|
||||||
|
$message = '{#server}> {#highlite}' . $login . '{#error} is not a valid player!';
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// format ranks & stats with narrow spaces between the thousands
|
||||||
|
$wrank = str_replace(' ', '$n $m', number_format($data->worldrank, 0, ' ', ' '));
|
||||||
|
$nrank = str_replace(' ', '$n $m', number_format($data->nationrank, 0, ' ', ' '));
|
||||||
|
$ntotal = str_replace(' ', '$n $m', number_format($data->nationplayers, 0, ' ', ' '));
|
||||||
|
$ptotal = str_replace(' ', '$n $m', number_format($data->totalplayers, 0, ' ', ' '));
|
||||||
|
$wins = str_replace(' ', '$n $m', number_format($data->wins, 0, ' ', ' '));
|
||||||
|
$draws = str_replace(' ', '$n $m', number_format($data->draws, 0, ' ', ' '));
|
||||||
|
$losses = str_replace(' ', '$n $m', number_format($data->losses, 0, ' ', ' '));
|
||||||
|
$trank = str_replace(' ', '$n $m', number_format($data->teamrank, 0, ' ', ' '));
|
||||||
|
$ttotal = str_replace(' ', '$n $m', number_format($data->totalteams, 0, ' ', ' '));
|
||||||
|
|
||||||
|
$stats = 'Stats for: {#black}' . $data->nickname . '$z / {#login}' . $data->login . LF . LF;
|
||||||
|
$stats .= '$gLadder Rank : {#black}' . $wrank . '$g / {#black}' . $ptotal . LF;
|
||||||
|
$stats .= '$gLadder Score : {#black}' . round($data->points, 1) . LF;
|
||||||
|
$stats .= '$gLast Match : {#black}' . round($data->lastmatch, 1) . LF;
|
||||||
|
$stats .= '$gNation : {#black}' . $data->nation . LF;
|
||||||
|
$stats .= '$gNation Rank : {#black}' . $nrank . '$g / {#black}' . $ntotal . LF;
|
||||||
|
$stats .= '$gWins : {#black}' . $wins . LF;
|
||||||
|
$stats .= '$gDraws : {#black}' . $draws;
|
||||||
|
if ($data->losses != 0) {
|
||||||
|
$stats .= ' $gW/L: {#black}' . round($data->wins / $data->losses, 3);
|
||||||
|
}
|
||||||
|
$stats .= LF;
|
||||||
|
$stats .= '$gLosses : {#black}' . $losses . LF;
|
||||||
|
$stats .= '$gStars / Days : {#black}' . $data->stars . '$g / {#black}' . $data->stardays . LF;
|
||||||
|
$stats .= '$gTeam : {#black}' . ($data->teamname ? $data->teamname . '$z' : '<none>') . LF;
|
||||||
|
if ($data->teamname) {
|
||||||
|
$stats .= '$gTeam Rank : {#black}' . $trank . '$g / {#black}' . $ttotal . LF;
|
||||||
|
}
|
||||||
|
$stats .= '$gOnline : {#black}' . ($data->online ? $data->serverlogin . '$g / {#black}' . $data->servernation : '<no>') . LF;
|
||||||
|
$stats .= '$gNations Score: {#black}' . $data->nationpoints . LF;
|
||||||
|
$stats .= '$gNations Rank : {#black}' . $data->nationpos . '$g / {#black}' . $data->totalnations;
|
||||||
|
|
||||||
|
// display popup message
|
||||||
|
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $aseco->formatColors($stats), 'OK', '', 0);
|
||||||
|
} else {
|
||||||
|
$message = '{#server}> {#error}Command unavailable, use {#highlite}$i /stats {#error}instead.';
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||||
|
}
|
||||||
|
} // chat_statsall
|
||||||
|
|
||||||
|
function chat_settings($aseco, $command) {
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
$target = $player;
|
||||||
|
|
||||||
|
// check for optional login parameter if any admin
|
||||||
|
if ($command['params'] != '' && $aseco->allowAbility($player, 'chat_settings'))
|
||||||
|
if (!$target = $aseco->getPlayerParam($player, $command['params'], true))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get CPs settings
|
||||||
|
if (function_exists('chat_cps'))
|
||||||
|
$cps = ldb_getCPs($aseco, $target->login);
|
||||||
|
else
|
||||||
|
$cps = false;
|
||||||
|
|
||||||
|
// showing settings for TMN
|
||||||
|
if ($aseco->server->getGame() == 'TMN') {
|
||||||
|
if ($cps) {
|
||||||
|
$settings = 'Settings for: ' . $target->nickname . '$z / {#login}' . $target->login . LF . LF;
|
||||||
|
$settings .= '$gLocal CPS : {#black}' . $cps['cps'] . LF;
|
||||||
|
$settings .= '$gDedimania CPS: {#black}' . $cps['dedicps'] . LF;
|
||||||
|
|
||||||
|
// display popup message
|
||||||
|
$aseco->client->query('SendDisplayServerMessageToLogin', $player->login, $aseco->formatColors($settings), 'OK', '', 0);
|
||||||
|
} else {
|
||||||
|
$message = '{#server}> {#error}No personal settings available';
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||||
|
}
|
||||||
|
|
||||||
|
// showing settings for TMF
|
||||||
|
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||||
|
// get style setting
|
||||||
|
if (function_exists('style_default'))
|
||||||
|
$style = ldb_getStyle($aseco, $target->login);
|
||||||
|
else
|
||||||
|
$style = false;
|
||||||
|
|
||||||
|
// get panel settings
|
||||||
|
if (function_exists('panels_default'))
|
||||||
|
$panels = ldb_getPanels($aseco, $target->login);
|
||||||
|
else
|
||||||
|
$panels = false;
|
||||||
|
|
||||||
|
if ($cps || $style || $panels) {
|
||||||
|
$header = 'Settings for: ' . $target->nickname . '$z / {#login}' . $target->login;
|
||||||
|
$settings = array();
|
||||||
|
|
||||||
|
// collect available settings
|
||||||
|
if ($cps) {
|
||||||
|
$settings[] = array('Local CPS', '{#black}' . $cps['cps']);
|
||||||
|
$settings[] = array('Dedimania CPS', '{#black}' . $cps['dedicps']);
|
||||||
|
if ($style || $panels)
|
||||||
|
$settings[] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($style) {
|
||||||
|
$settings[] = array('Window Style', '{#black}' . $style);
|
||||||
|
if ($panels)
|
||||||
|
$settings[] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($panels) {
|
||||||
|
if ($aseco->isAnyAdmin($target))
|
||||||
|
$settings[] = array('Admin Panel', '{#black}' . substr($panels['admin'], 5));
|
||||||
|
$settings[] = array('Donate Panel', '{#black}' . substr($panels['donate'], 6));
|
||||||
|
$settings[] = array('Records Panel', '{#black}' . substr($panels['records'], 7));
|
||||||
|
$settings[] = array('Vote Panel', '{#black}' . substr($panels['vote'], 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
// display ManiaLink message
|
||||||
|
display_manialink($player->login, $header, array('Icons128x128_1', 'Inputs', 0.03), $settings, array(1.0, 0.3, 0.7), 'OK');
|
||||||
|
} else {
|
||||||
|
$message = '{#server}> {#error}No personal settings available';
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||||
|
}
|
||||||
|
} else { // TMO/TMS
|
||||||
|
$message = '{#server}> {#error}No personal settings available';
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $player->login);
|
||||||
|
}
|
||||||
|
} // chat_settings
|
||||||
|
?>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chat plugin.
|
||||||
|
* Shows player wins.
|
||||||
|
* Created by Xymph
|
||||||
|
*
|
||||||
|
* Dependencies: none
|
||||||
|
*/
|
||||||
|
|
||||||
|
Aseco::addChatCommand('wins', 'Shows wins for current player');
|
||||||
|
|
||||||
|
function chat_wins($aseco, $command) {
|
||||||
|
|
||||||
|
$wins = $command['author']->getWins();
|
||||||
|
// use plural unless 1, and add ! for 2 or more
|
||||||
|
$message = formatText($aseco->getChatMessage('WINS'), $wins,
|
||||||
|
($wins == 1 ? '.' : ($wins > 1 ? 's!' : 's.')));
|
||||||
|
// show chat message
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $command['author']->login);
|
||||||
|
} // chat_wins
|
||||||
|
?>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,178 @@
|
||||||
|
<?php
|
||||||
|
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jfreu's lite plugin.
|
||||||
|
* Provides only the player join/leave messages and the INFO messages.
|
||||||
|
* Add this to plugins.xml instead of jfreu.plugin.php if you don't
|
||||||
|
* need the rest of the Jfreu features. If you don't want the INFO
|
||||||
|
* messages, set $infomessages = 0 in jfreu.config.php.
|
||||||
|
* Created by Xymph
|
||||||
|
*
|
||||||
|
* Dependencies: none
|
||||||
|
*/
|
||||||
|
|
||||||
|
Aseco::registerEvent('onStartup', 'init_jfreu');
|
||||||
|
Aseco::registerEvent('onEndRace', 'info_message');
|
||||||
|
Aseco::registerEvent('onPlayerConnect', 'player_connect');
|
||||||
|
Aseco::registerEvent('onPlayerDisconnect', 'player_disconnect');
|
||||||
|
|
||||||
|
Aseco::addChatCommand('message', 'Shows random informational message');
|
||||||
|
|
||||||
|
class Jfreu
|
||||||
|
{
|
||||||
|
//** Jfreu's plugin version **//
|
||||||
|
var $version;
|
||||||
|
|
||||||
|
//** colors **// <-- use aseco colors ?
|
||||||
|
var $white;
|
||||||
|
var $yellow;
|
||||||
|
var $red;
|
||||||
|
var $blue;
|
||||||
|
var $green;
|
||||||
|
var $admin;
|
||||||
|
|
||||||
|
//** random info message **//
|
||||||
|
var $messages;
|
||||||
|
var $nbmessages;
|
||||||
|
var $infomessages;
|
||||||
|
var $message_start;
|
||||||
|
|
||||||
|
//** player join/leave messages **//
|
||||||
|
var $player_join;
|
||||||
|
var $player_joins;
|
||||||
|
var $player_left;
|
||||||
|
} // class Jfreu
|
||||||
|
|
||||||
|
// called @ onStartup
|
||||||
|
function init_jfreu($aseco, $command)
|
||||||
|
{
|
||||||
|
include_once('includes/jfreu.config.php');
|
||||||
|
$version = '0.14';
|
||||||
|
$aseco->server->jfreu = new Jfreu();
|
||||||
|
$aseco->server->jfreu->version = $version;
|
||||||
|
$aseco->server->jfreu->message_start = $message_start;
|
||||||
|
|
||||||
|
$aseco->server->jfreu->player_join = $player_join;
|
||||||
|
$aseco->server->jfreu->player_joins = $player_joins;
|
||||||
|
$aseco->server->jfreu->player_left = $player_left;
|
||||||
|
|
||||||
|
//** random information messages **//
|
||||||
|
$aseco->server->jfreu->infomessages = $infomessages;
|
||||||
|
$i = 1;
|
||||||
|
while (isset(${'message'.$i}) && $i < 1000) {
|
||||||
|
$aseco->server->jfreu->messages[$i] = ${'message'.$i};
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
if ($i != 1000) {
|
||||||
|
$aseco->server->jfreu->nbmessages = $i - 1;
|
||||||
|
} else {
|
||||||
|
$aseco->server->jfreu->nbmessages = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//** colors **//
|
||||||
|
$whi = $aseco->server->jfreu->white = $aseco->formatColors('$z$s{#highlite}');
|
||||||
|
$yel = $aseco->server->jfreu->yellow = $aseco->formatColors('$z$s{#server}');
|
||||||
|
$red = $aseco->server->jfreu->red = $aseco->formatColors('$z$s{#error}');
|
||||||
|
$blu = $aseco->server->jfreu->blue = $aseco->formatColors('$z$s{#message}');
|
||||||
|
$gre = $aseco->server->jfreu->green = $aseco->formatColors('$z$s{#record}');
|
||||||
|
$adm = $aseco->server->jfreu->admin = $aseco->formatColors('$z$s{#logina}');
|
||||||
|
|
||||||
|
//** Loaded message **//
|
||||||
|
$message = $yel.'>> '.$whi.'Jfreu'.$blu.'\'s lite plugin '.$gre.$version.$blu.': '.$whi.'Loaded'.$blu.'.';
|
||||||
|
$aseco->client->query('ChatSendServerMessage', $message);
|
||||||
|
} // init_jfreu
|
||||||
|
|
||||||
|
// called @ onEndRace
|
||||||
|
function info_message($aseco, $data)
|
||||||
|
{
|
||||||
|
// if no info messages, bail out
|
||||||
|
if ($aseco->server->jfreu->infomessages == 0) return;
|
||||||
|
|
||||||
|
// get random message
|
||||||
|
$i = rand(1, $aseco->server->jfreu->nbmessages);
|
||||||
|
$message = $aseco->formatColors($aseco->server->jfreu->message_start . $aseco->server->jfreu->messages[$i]);
|
||||||
|
// hyperlink release page on TMF
|
||||||
|
if ($aseco->server->getGame() == 'TMF') {
|
||||||
|
$message = preg_replace('|' . XASECO_TMN . '|', '$l[$0]$0$l', $message);
|
||||||
|
$message = preg_replace('|' . XASECO_ORG . '|', '$l[$0]$0$l', $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the message & test for scoreboard or /message command
|
||||||
|
if ($aseco->server->getGame() == 'TMF' && $aseco->server->jfreu->infomessages == 2 &&
|
||||||
|
function_exists('send_window_message'))
|
||||||
|
send_window_message($aseco, $message, ($data !== false));
|
||||||
|
else
|
||||||
|
$aseco->client->query('ChatSendServerMessage', $message);
|
||||||
|
} // info_message
|
||||||
|
|
||||||
|
function chat_message($aseco, $command)
|
||||||
|
{
|
||||||
|
info_message($aseco, false);
|
||||||
|
} // chat_message
|
||||||
|
|
||||||
|
// called @ onPlayerConnect
|
||||||
|
function player_connect($aseco, $player)
|
||||||
|
{
|
||||||
|
global $rasp, $feature_ranks;
|
||||||
|
|
||||||
|
$whi = $aseco->server->jfreu->white;
|
||||||
|
$yel = $aseco->server->jfreu->yellow;
|
||||||
|
$red = $aseco->server->jfreu->red;
|
||||||
|
$blu = $aseco->server->jfreu->blue;
|
||||||
|
$gre = $aseco->server->jfreu->green;
|
||||||
|
$adm = $aseco->server->jfreu->admin;
|
||||||
|
|
||||||
|
// if starting up, bail out immediately
|
||||||
|
if ($aseco->startup_phase) return;
|
||||||
|
|
||||||
|
// define admin/player title
|
||||||
|
$title = $aseco->isMasterAdmin($player) ? $adm.$aseco->titles['MASTERADMIN'][0] :
|
||||||
|
($aseco->isAdmin($player) ? $adm.$aseco->titles['ADMIN'][0] :
|
||||||
|
($aseco->isOperator($player) ? $adm.$aseco->titles['OPERATOR'][0] :
|
||||||
|
$blu.'New Player'));
|
||||||
|
// format ladder rank with narrow spaces between the thousands
|
||||||
|
$rank = str_replace(' ', '$n $m', number_format($player->ladderrank, 0, ' ', ' '));
|
||||||
|
// abbreviate long nations
|
||||||
|
$nation = $player->nation;
|
||||||
|
if (strlen($nation) > 14)
|
||||||
|
$nation = mapCountry($nation);
|
||||||
|
if ($feature_ranks) {
|
||||||
|
$message = formatText($aseco->server->jfreu->player_joins,
|
||||||
|
$title, clean_nick($player->nickname),
|
||||||
|
$nation, $rank, $rasp->getRank($player->login));
|
||||||
|
} else {
|
||||||
|
$message = formatText($aseco->server->jfreu->player_join,
|
||||||
|
$title, clean_nick($player->nickname),
|
||||||
|
$nation, $rank);
|
||||||
|
}
|
||||||
|
$aseco->client->query('ChatSendServerMessage', $aseco->formatColors($message));
|
||||||
|
} // player_connect
|
||||||
|
|
||||||
|
// called @ onPlayerDisconnect
|
||||||
|
function player_disconnect($aseco, $player)
|
||||||
|
{
|
||||||
|
$message = formatText($aseco->server->jfreu->player_left,
|
||||||
|
clean_nick($player->nickname),
|
||||||
|
formatTimeH($player->getTimeOnline() * 1000, false));
|
||||||
|
$aseco->client->query('ChatSendServerMessage', $aseco->formatColors($message));
|
||||||
|
} // player_disconnect
|
||||||
|
|
||||||
|
function clean_nick($nick)
|
||||||
|
{
|
||||||
|
global $aseco;
|
||||||
|
|
||||||
|
$whi = $aseco->server->jfreu->white;
|
||||||
|
$yel = $aseco->server->jfreu->yellow;
|
||||||
|
$red = $aseco->server->jfreu->red;
|
||||||
|
$blu = $aseco->server->jfreu->blue;
|
||||||
|
$gre = $aseco->server->jfreu->green;
|
||||||
|
$adm = $aseco->server->jfreu->admin;
|
||||||
|
|
||||||
|
$propre = stripColors($nick);
|
||||||
|
if ($propre == '') {
|
||||||
|
return $red.'ERROR';
|
||||||
|
}
|
||||||
|
return $propre;
|
||||||
|
} // clean_nick
|
||||||
|
?>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<lists>
|
||||||
|
<ban_list>
|
||||||
|
<!-- format:
|
||||||
|
<login></login> <time></time>
|
||||||
|
-->
|
||||||
|
</ban_list>
|
||||||
|
</lists>
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<config>
|
||||||
|
<server>
|
||||||
|
<servername>YOUR SERVER NAME</servername>
|
||||||
|
<servertop> $449TOP</servertop>
|
||||||
|
<autochangename>false</autochangename>
|
||||||
|
<infomessages>1</infomessages>
|
||||||
|
<badwords>false</badwords>
|
||||||
|
<badwordsban>false</badwordsban>
|
||||||
|
<badwordsnum>3</badwordsnum>
|
||||||
|
<badwordstime>10</badwordstime>
|
||||||
|
<unspecvote>true</unspecvote>
|
||||||
|
<novote>false</novote>
|
||||||
|
</server>
|
||||||
|
|
||||||
|
<limits>
|
||||||
|
<ranklimit>false</ranklimit>
|
||||||
|
<limit>500000</limit>
|
||||||
|
<hardlimit>1000000</hardlimit>
|
||||||
|
<autorank>false</autorank>
|
||||||
|
<offset>999</offset>
|
||||||
|
<autolimit>500000</autolimit>
|
||||||
|
<autorankminplayers>10</autorankminplayers>
|
||||||
|
<autorankvip>false</autorankvip>
|
||||||
|
<maxplayers>20</maxplayers>
|
||||||
|
<kickhirank>false</kickhirank>
|
||||||
|
<pf>0</pf>
|
||||||
|
</limits>
|
||||||
|
</config>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<lists>
|
||||||
|
<vip_list>
|
||||||
|
</vip_list>
|
||||||
|
|
||||||
|
<vip_team_list>
|
||||||
|
</vip_team_list>
|
||||||
|
</lists>
|
|
@ -0,0 +1,175 @@
|
||||||
|
<?php
|
||||||
|
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* (X)ASECO plugin to kick idle players
|
||||||
|
*
|
||||||
|
* (C) 2007 by Mistral
|
||||||
|
* Updated by Xymph
|
||||||
|
*
|
||||||
|
* Dependencies: none
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
Aseco::registerEvent('onNewChallenge', 'kickIdleNewChallenge');
|
||||||
|
Aseco::registerEvent('onPlayerConnect', 'kickIdleInit');
|
||||||
|
Aseco::registerEvent('onChat', 'kickIdleChat');
|
||||||
|
Aseco::registerEvent('onCheckpoint', 'kickIdleCheckpoint');
|
||||||
|
Aseco::registerEvent('onPlayerFinish', 'kickIdleFinish');
|
||||||
|
Aseco::registerEvent('onEndRace', 'kickIdlePlayers');
|
||||||
|
|
||||||
|
global $kickPlayAfter, $kickSpecAfter, $kickSpecToo, $specPlayFirst, $resetOnChat,
|
||||||
|
$resetOnCheckpoint, $resetOnFinish, $idlekickStart, $idlekick_log, $idlekick_debug;
|
||||||
|
|
||||||
|
$kickPlayAfter = 2; // Player idle this number of challenges and get kicked or specced
|
||||||
|
$kickSpecAfter = 4; // Spectator idle this number of challenges and get kicked
|
||||||
|
$kickSpecToo = true; // Kick spectators too
|
||||||
|
$specPlayFirst = false; // Set idle player to spectator first instead of kick (TMF only)
|
||||||
|
$resetOnChat = true; // Reset idle counter on chat use
|
||||||
|
$resetOnCheckpoint = true; // Reset idle counter when passing a checkpoint
|
||||||
|
$resetOnFinish = false; // Reset idle counter when reaching the finish
|
||||||
|
// don't use OnFinish in rounds or team mode, because every player will "finish"
|
||||||
|
|
||||||
|
// don't touch:
|
||||||
|
$idlekickStart = true;
|
||||||
|
$idlekick_log = false;
|
||||||
|
$idlekick_debug = false;
|
||||||
|
|
||||||
|
// called @ onChat
|
||||||
|
function kickIdleChat($aseco, $chat) {
|
||||||
|
global $resetOnChat, $idlekick_debug;
|
||||||
|
|
||||||
|
// if server message, bail out immediately
|
||||||
|
if ($chat[0] == $aseco->server->id) return;
|
||||||
|
|
||||||
|
// if no check on chat use, bail out too
|
||||||
|
if (!$resetOnChat) return;
|
||||||
|
|
||||||
|
$player = $aseco->server->players->getPlayer($chat[1]);
|
||||||
|
$player->mistral['idleCount'] = 0;
|
||||||
|
if ($idlekick_debug)
|
||||||
|
$aseco->console('Idlekick: {1} reset on chat', $player->login);
|
||||||
|
} // kickIdleChat
|
||||||
|
|
||||||
|
// called @ onCheckpoint
|
||||||
|
function kickIdleCheckpoint($aseco, $checkpt) {
|
||||||
|
global $resetOnCheckpoint, $idlekick_debug;
|
||||||
|
|
||||||
|
// if no check on checkpoints, bail out
|
||||||
|
if (!$resetOnCheckpoint) return;
|
||||||
|
|
||||||
|
$player = $aseco->server->players->getPlayer($checkpt[1]);
|
||||||
|
$player->mistral['idleCount'] = 0;
|
||||||
|
if ($idlekick_debug)
|
||||||
|
$aseco->console('Idlekick: {1} reset on checkpoint', $player->login);
|
||||||
|
} // kickIdleCheckpoint
|
||||||
|
|
||||||
|
// called @ onPlayerFinish
|
||||||
|
function kickIdleFinish($aseco, $finish_item) {
|
||||||
|
global $resetOnFinish, $idlekick_debug;
|
||||||
|
|
||||||
|
// if no check on finishes, bail out
|
||||||
|
if (!$resetOnFinish) return;
|
||||||
|
|
||||||
|
$player = $finish_item->player;
|
||||||
|
$player->mistral['idleCount'] = 0;
|
||||||
|
if ($idlekick_debug)
|
||||||
|
$aseco->console('Idlekick: {1} reset on finish', $player->login);
|
||||||
|
} // kickIdleFinish
|
||||||
|
|
||||||
|
// called @ onNewChallenge
|
||||||
|
function kickIdleNewChallenge($aseco, $challenge) {
|
||||||
|
global $kickSpecToo, $idlekickStart, $idlekick_debug, $idlekick_log;
|
||||||
|
|
||||||
|
if ($idlekickStart) {
|
||||||
|
$idlekickStart = false;
|
||||||
|
if ($idlekick_debug)
|
||||||
|
$aseco->console('Idlekick: idlekickStart set to false');
|
||||||
|
foreach ($aseco->server->players->player_list as $player)
|
||||||
|
kickIdleInit($aseco, $player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($aseco->server->players->player_list as $player) {
|
||||||
|
// get player status
|
||||||
|
$spec = $aseco->isSpectator($player);
|
||||||
|
|
||||||
|
// check for admin immunity
|
||||||
|
if ($spec ? $aseco->allowAbility($player, 'noidlekick_spec')
|
||||||
|
: $aseco->allowAbility($player, 'noidlekick_play'))
|
||||||
|
continue; // go check next player
|
||||||
|
|
||||||
|
// check for spectator kicking
|
||||||
|
if ($kickSpecToo || !$spec)
|
||||||
|
$player->mistral['idleCount']++;
|
||||||
|
if ($idlekick_log)
|
||||||
|
$aseco->console('Idlekick: {1} set to {2}', $player->login, $player->mistral['idleCount']);
|
||||||
|
}
|
||||||
|
} // kickIdleNewChallenge
|
||||||
|
|
||||||
|
// called @ onPlayerConnect
|
||||||
|
function kickIdleInit($aseco, $player) {
|
||||||
|
global $idlekick_debug;
|
||||||
|
|
||||||
|
$player->mistral['idleCount'] = 0;
|
||||||
|
if ($idlekick_debug)
|
||||||
|
$aseco->console('Idlekick: {1} initialised with 0', $player->login);
|
||||||
|
} // kickIdleInit
|
||||||
|
|
||||||
|
// called @ onEndRace
|
||||||
|
function kickIdlePlayers($aseco, $data) {
|
||||||
|
global $kickPlayAfter, $kickSpecAfter, $specPlayFirst, $idlekick_debug;
|
||||||
|
|
||||||
|
foreach ($aseco->server->players->player_list as $player) {
|
||||||
|
$spec = $aseco->isSpectator($player);
|
||||||
|
// check for spectator or player challenge counts
|
||||||
|
if ($player->mistral['idleCount'] == ($spec ? $kickSpecAfter
|
||||||
|
: $kickPlayAfter)) {
|
||||||
|
$dokick = false;
|
||||||
|
if ($spec) {
|
||||||
|
$dokick = true;
|
||||||
|
// log console message
|
||||||
|
$aseco->console('IdleKick spectator: {1} after {2} challenge(s) without action', $player->login, $kickSpecAfter);
|
||||||
|
$message = formatText($aseco->getChatMessage('IDLEKICK_SPEC'),
|
||||||
|
$player->nickname,
|
||||||
|
$kickSpecAfter, ($kickSpecAfter == 1 ? '' : 's'));
|
||||||
|
} else {
|
||||||
|
if ($aseco->server->getGame() == 'TMF' && $specPlayFirst) {
|
||||||
|
// log console message
|
||||||
|
$aseco->console('IdleSpec player: {1} after {2} challenge(s) without action', $player->login, $kickPlayAfter);
|
||||||
|
$message = formatText($aseco->getChatMessage('IDLESPEC_PLAY'),
|
||||||
|
$player->nickname,
|
||||||
|
$kickPlayAfter, ($kickPlayAfter == 1 ? '' : 's'));
|
||||||
|
|
||||||
|
// force player into spectator
|
||||||
|
$rtn = $aseco->client->query('ForceSpectator', $player->login, 1);
|
||||||
|
if (!$rtn) {
|
||||||
|
trigger_error('[' . $aseco->client->getErrorCode() . '] ForceSpectator - ' . $aseco->client->getErrorMessage(), E_USER_WARNING);
|
||||||
|
} else {
|
||||||
|
// allow spectator to switch back to player
|
||||||
|
$rtn = $aseco->client->query('ForceSpectator', $player->login, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// force free camera mode on spectator
|
||||||
|
$aseco->client->addCall('ForceSpectatorTarget', array($player->login, '', 2));
|
||||||
|
} else {
|
||||||
|
$dokick = true;
|
||||||
|
// log console message
|
||||||
|
$aseco->console('IdleKick player: {1} after {2} challenge(s) without action', $player->login, $kickPlayAfter);
|
||||||
|
$message = formatText($aseco->getChatMessage('IDLEKICK_PLAY'),
|
||||||
|
$player->nickname,
|
||||||
|
$kickPlayAfter, ($kickPlayAfter == 1 ? '' : 's'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// show chat message
|
||||||
|
$aseco->client->query('ChatSendServerMessage', $aseco->formatColors($message));
|
||||||
|
// kick idle player
|
||||||
|
if ($dokick)
|
||||||
|
$aseco->client->query('Kick', $player->login);
|
||||||
|
}
|
||||||
|
elseif ($idlekick_debug)
|
||||||
|
$aseco->console('Idlekick: {1} current value is {2}', $player->login, $player->mistral['idleCount']);
|
||||||
|
}
|
||||||
|
} // kickIdlePlayers
|
||||||
|
?>
|
|
@ -0,0 +1,448 @@
|
||||||
|
<?php
|
||||||
|
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access Control plugin.
|
||||||
|
* Controls player access by nation (TMN) or zone (TMF).
|
||||||
|
* Inspired by Apache's mod_access:
|
||||||
|
* http://httpd.apache.org/docs/2.0/mod/mod_access.html
|
||||||
|
* Created by Xymph
|
||||||
|
*
|
||||||
|
* Dependencies: none
|
||||||
|
*/
|
||||||
|
|
||||||
|
Aseco::registerEvent('onStartup', 'access_initcontrol');
|
||||||
|
Aseco::registerEvent('onPlayerConnect2', 'access_playerconnect'); // use post event after all join processing
|
||||||
|
|
||||||
|
global $access_control;
|
||||||
|
// ['order'] - boolean: allow,deny = true; deny,allow = false
|
||||||
|
// ['allowall'] - boolean: Allow from all = true; otherwise false
|
||||||
|
// ['allow'] - array of nations/zones to allow
|
||||||
|
// ['denyall'] - boolean: Deny from all = true; otherwise false
|
||||||
|
// ['deny'] - array of nations/zones to deny
|
||||||
|
|
||||||
|
// called @ onStartup
|
||||||
|
function access_initcontrol($aseco, $reload = false) {
|
||||||
|
global $access_control;
|
||||||
|
|
||||||
|
// initialize access control
|
||||||
|
$access_control = array();
|
||||||
|
$access_control['order'] = false;
|
||||||
|
$access_control['allowall'] = false;
|
||||||
|
$access_control['allow'] = array();
|
||||||
|
$access_control['denyall'] = false;
|
||||||
|
$access_control['deny'] = array();
|
||||||
|
$access_control['messages'] = array();
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
// log console message
|
||||||
|
if (!$reload)
|
||||||
|
$aseco->console('Load player access control [access.xml]');
|
||||||
|
|
||||||
|
// read & parse config file
|
||||||
|
if (!$settings = $aseco->xml_parser->parseXml('access.xml'))
|
||||||
|
$error = 'Could not read/parse access control config file access.xml !';
|
||||||
|
|
||||||
|
// check/store Order section
|
||||||
|
if (!$error) {
|
||||||
|
if (isset($settings['ACCESS']['ORDER'][0])) {
|
||||||
|
// strip all spaces
|
||||||
|
$order = str_replace(' ', '', strtolower($settings['ACCESS']['ORDER'][0]));
|
||||||
|
if ($order == 'allow,deny')
|
||||||
|
$access_control['order'] = true;
|
||||||
|
elseif ($order == 'deny,allow')
|
||||||
|
$access_control['order'] = false;
|
||||||
|
else {
|
||||||
|
$error = 'Access control config invalid \'order\' section: "' . $settings['ACCESS']['ORDER'][0] . '"';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$error = 'Access control config missing section: order';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check/store Allow section
|
||||||
|
if (!$error) {
|
||||||
|
if (isset($settings['ACCESS']['ALLOW'][0])) {
|
||||||
|
// check/store From entry(ies)
|
||||||
|
if (isset($settings['ACCESS']['ALLOW'][0]['FROM'])) {
|
||||||
|
foreach ($settings['ACCESS']['ALLOW'][0]['FROM'] as $from) {
|
||||||
|
if ($from == 'all') {
|
||||||
|
if (count($settings['ACCESS']['ALLOW'][0]['FROM']) > 1) {
|
||||||
|
$error = 'Access control config \'allow\' section contains more besides "all" value';
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
$access_control['allowall'] = true;
|
||||||
|
}
|
||||||
|
} else { // != 'all'
|
||||||
|
if (in_array($from, $access_control['allow'])) {
|
||||||
|
$error = 'Access control config \'allow\' section contains duplicate value: ' . $from;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if ($from != '') // ignore empty entries
|
||||||
|
$access_control['allow'][] = $from;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$error = 'Access control config \'allow\' section must contain at least one \'from\' entry';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$error = 'Access control config missing section: allow';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check/store Deny section
|
||||||
|
if (!$error) {
|
||||||
|
if (isset($settings['ACCESS']['DENY'][0])) {
|
||||||
|
// check/store From entry(ies)
|
||||||
|
if (isset($settings['ACCESS']['DENY'][0]['FROM'])) {
|
||||||
|
foreach ($settings['ACCESS']['DENY'][0]['FROM'] as $from) {
|
||||||
|
if ($from == 'all') {
|
||||||
|
if (count($settings['ACCESS']['DENY'][0]['FROM']) > 1) {
|
||||||
|
$error = 'Access control config \'deny\' section contains more besides "all" value';
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
$access_control['denyall'] = true;
|
||||||
|
}
|
||||||
|
} else { // != 'all'
|
||||||
|
if (in_array($from, $access_control['deny'])) {
|
||||||
|
$error = 'Access control config \'deny\' section contains duplicate value: ' . $from;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if ($from != '') // ignore empty entries
|
||||||
|
$access_control['deny'][] = $from;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$error = 'Access control config \'deny\' section must contain at least one \'from\' entry';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$error = 'Access control config missing section: deny';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// final consistency check
|
||||||
|
if (!$error && $access_control['allowall'] && $access_control['denyall'])
|
||||||
|
$error = 'Access control config \'allow\' & \'deny\' sections cannot both use "all" value';
|
||||||
|
|
||||||
|
// load messages
|
||||||
|
if (!$error) {
|
||||||
|
if (isset($settings['ACCESS']['MESSAGES'][0])) {
|
||||||
|
if (isset($settings['ACCESS']['MESSAGES'][0]['DENIED'][0]))
|
||||||
|
$access_control['messages']['denied'] = $settings['ACCESS']['MESSAGES'][0]['DENIED'][0];
|
||||||
|
else
|
||||||
|
$error = 'Access control config \'messages\' section missing value: denied';
|
||||||
|
if (isset($settings['ACCESS']['MESSAGES'][0]['DIALOG'][0]))
|
||||||
|
$access_control['messages']['dialog'] = $settings['ACCESS']['MESSAGES'][0]['DIALOG'][0];
|
||||||
|
else
|
||||||
|
$error = 'Access control config \'messages\' section missing value: dialog';
|
||||||
|
if (isset($settings['ACCESS']['MESSAGES'][0]['RELOAD'][0]))
|
||||||
|
$access_control['messages']['reload'] = $settings['ACCESS']['MESSAGES'][0]['RELOAD'][0];
|
||||||
|
else
|
||||||
|
$error = 'Access control config \'messages\' section missing value: reload';
|
||||||
|
if (isset($settings['ACCESS']['MESSAGES'][0]['XMLERR'][0]))
|
||||||
|
$access_control['messages']['xmlerr'] = $settings['ACCESS']['MESSAGES'][0]['XMLERR'][0];
|
||||||
|
else
|
||||||
|
$error = 'Access control config \'messages\' section missing value: xmlerr';
|
||||||
|
if (isset($settings['ACCESS']['MESSAGES'][0]['MISSING'][0]))
|
||||||
|
$access_control['messages']['missing'] = $settings['ACCESS']['MESSAGES'][0]['MISSING'][0];
|
||||||
|
else
|
||||||
|
$error = 'Access control config \'messages\' section missing value: missing';
|
||||||
|
} else {
|
||||||
|
$error = 'Access control config missing section: messages';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$error) {
|
||||||
|
// sort access lists
|
||||||
|
sort($access_control['allow']);
|
||||||
|
sort($access_control['deny']);
|
||||||
|
|
||||||
|
// log console message
|
||||||
|
if ($reload)
|
||||||
|
$aseco->console('Player access control reloaded from access.xml');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// log error message
|
||||||
|
trigger_error($error, E_USER_WARNING);
|
||||||
|
$access_control = array();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} // access_initcontrol
|
||||||
|
|
||||||
|
function in_zones($access, $zones) {
|
||||||
|
|
||||||
|
// check all zones for matching (leading part of) player's zone
|
||||||
|
foreach ($zones as $zone)
|
||||||
|
if (strpos($access, $zone) === 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} // in_zones
|
||||||
|
|
||||||
|
// called @ onPlayerConnect2
|
||||||
|
function access_playerconnect($aseco, $player) {
|
||||||
|
global $access_control;
|
||||||
|
|
||||||
|
// if no access control, bail out immediately
|
||||||
|
if (!$access_control) return;
|
||||||
|
|
||||||
|
// get nation/zone to check for access
|
||||||
|
if ($aseco->server->getGame() == 'TMF') {
|
||||||
|
$access = $player->zone;
|
||||||
|
} elseif ($aseco->server->getGame() == 'TMN') {
|
||||||
|
$access = $player->nation;
|
||||||
|
} else { // TMS/TMO
|
||||||
|
return; // no access control
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for empty nation/zone
|
||||||
|
if ($access == '') {
|
||||||
|
if ($access_control['order']) { // Allow,Deny
|
||||||
|
; // default denied
|
||||||
|
} else { // Deny,Allow
|
||||||
|
return; // default allowed
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($aseco->server->getGame() == 'TMF') {
|
||||||
|
if ($access_control['order']) { // Allow,Deny
|
||||||
|
// first check Allow list
|
||||||
|
if ($access_control['allowall'] || in_zones($access, $access_control['allow'])) {
|
||||||
|
// then check Deny list
|
||||||
|
if ($access_control['denyall'] || in_zones($access, $access_control['deny']))
|
||||||
|
; // deny this nation
|
||||||
|
else
|
||||||
|
return; // allow this nation
|
||||||
|
}
|
||||||
|
else
|
||||||
|
; // deny this nation
|
||||||
|
} else { // Deny,Allow
|
||||||
|
// first check Deny list
|
||||||
|
if ($access_control['denyall'] || in_zones($access, $access_control['deny'])) {
|
||||||
|
// then check Allow list
|
||||||
|
if ($access_control['allowall'] || in_zones($access, $access_control['allow']))
|
||||||
|
return; // allow this nation
|
||||||
|
else
|
||||||
|
; // deny this nation
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return; // allow this nation
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // TMN
|
||||||
|
if ($access_control['order']) { // Allow,Deny
|
||||||
|
// first check Allow list
|
||||||
|
if ($access_control['allowall'] || in_array($access, $access_control['allow'])) {
|
||||||
|
// then check Deny list
|
||||||
|
if ($access_control['denyall'] || in_array($access, $access_control['deny']))
|
||||||
|
; // deny this nation
|
||||||
|
else
|
||||||
|
return; // allow this nation
|
||||||
|
}
|
||||||
|
else
|
||||||
|
; // deny this nation
|
||||||
|
} else { // Deny,Allow
|
||||||
|
// first check Deny list
|
||||||
|
if ($access_control['denyall'] || in_array($access, $access_control['deny'])) {
|
||||||
|
// then check Allow list
|
||||||
|
if ($access_control['allowall'] || in_array($access, $access_control['allow']))
|
||||||
|
return; // allow this nation
|
||||||
|
else
|
||||||
|
; // deny this nation
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return; // allow this nation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// log & kick player
|
||||||
|
$aseco->console('Player \'{1}\' denied access from "{2}" - kicking...', $player->login, $access);
|
||||||
|
|
||||||
|
$message = formatText($access_control['messages']['denied'],
|
||||||
|
stripColors($player->nickname),
|
||||||
|
($aseco->server->getGame() == 'TMF' ? 'zone' : 'nation'),
|
||||||
|
$access);
|
||||||
|
$aseco->client->query('ChatSendServerMessage', $aseco->formatColors($message));
|
||||||
|
if ($aseco->server->getGame() == 'TMF') {
|
||||||
|
$message = formatText($access_control['messages']['dialog'],
|
||||||
|
$access);
|
||||||
|
$aseco->client->addCall('Kick', array($player->login, $aseco->formatColors($message)));
|
||||||
|
} else {
|
||||||
|
$aseco->client->addCall('Kick', array($player->login));
|
||||||
|
}
|
||||||
|
} // access_playerconnect
|
||||||
|
|
||||||
|
|
||||||
|
function admin_access($aseco, $command) {
|
||||||
|
global $access_control;
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
$login = $player->login;
|
||||||
|
|
||||||
|
if ($command['params'] == 'help') {
|
||||||
|
if ($aseco->server->getGame() == 'TMF') {
|
||||||
|
$header = '{#black}/admin access$g handles player access control:';
|
||||||
|
$help = array();
|
||||||
|
$help[] = array('...', '{#black}help',
|
||||||
|
'Displays this help information');
|
||||||
|
$help[] = array('...', '{#black}list',
|
||||||
|
'Displays current access control settings');
|
||||||
|
$help[] = array('...', '{#black}reload',
|
||||||
|
'Reloads updated access control settings');
|
||||||
|
|
||||||
|
// display ManiaLink message
|
||||||
|
display_manialink($login, $header, array('Icons64x64_1', 'TrackInfo', -0.01), $help, array(0.8, 0.05, 0.15, 0.6), 'OK');
|
||||||
|
} elseif ($aseco->server->getGame() == 'TMN') {
|
||||||
|
$help = '{#black}/admin access$g handles player access control:' . LF;
|
||||||
|
$help .= ' - {#black}help$g, displays this help information' . LF;
|
||||||
|
$help .= ' - {#black}list$g, lists current settings' . LF;
|
||||||
|
$help .= ' - {#black}reload$g, reloads updated settings' . LF;
|
||||||
|
|
||||||
|
// display popup message
|
||||||
|
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $aseco->formatColors($help), 'OK', '', 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elseif ($command['params'] == 'list') {
|
||||||
|
$player->msgs = array();
|
||||||
|
|
||||||
|
if ($aseco->server->getGame() == 'TMF') {
|
||||||
|
$head = 'Current player access control settings:';
|
||||||
|
$info = array();
|
||||||
|
// initialize with Order entry
|
||||||
|
$info[] = array('Order:', '{#black}' . ($access_control['order'] ? 'Allow,Deny' : 'Deny,Allow'));
|
||||||
|
$info[] = array();
|
||||||
|
|
||||||
|
$lines = 2;
|
||||||
|
$player->msgs[0] = array(1, $head, array(1.0, 0.2, 0.8), array('Icons128x128_1', 'ManiaZones'));
|
||||||
|
|
||||||
|
// collect Allow entries
|
||||||
|
$info[] = array('Allow:', '');
|
||||||
|
$lines++;
|
||||||
|
if ($access_control['allowall']) {
|
||||||
|
$info[] = array('', '{#black}all');
|
||||||
|
$lines++;
|
||||||
|
} else {
|
||||||
|
foreach ($access_control['allow'] as $from) {
|
||||||
|
$info[] = array('', '{#black}' . $from);
|
||||||
|
if (++$lines > 14) {
|
||||||
|
$player->msgs[] = $info;
|
||||||
|
$lines = 0;
|
||||||
|
$info = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert spacer
|
||||||
|
$info[] = array();
|
||||||
|
if (++$lines > 14) {
|
||||||
|
$player->msgs[] = $info;
|
||||||
|
$lines = 0;
|
||||||
|
$info = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect Deny entries
|
||||||
|
$info[] = array('Deny:', '');
|
||||||
|
$lines++;
|
||||||
|
if ($access_control['denyall']) {
|
||||||
|
$info[] = array('', '{#black}all');
|
||||||
|
$lines++;
|
||||||
|
} else {
|
||||||
|
foreach ($access_control['deny'] as $from) {
|
||||||
|
$info[] = array('', '{#black}' . $from);
|
||||||
|
if (++$lines > 14) {
|
||||||
|
$player->msgs[] = $info;
|
||||||
|
$lines = 0;
|
||||||
|
$info = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add if last batch exists
|
||||||
|
if (count($info) > 1)
|
||||||
|
$player->msgs[] = $info;
|
||||||
|
|
||||||
|
// display ManiaLink message
|
||||||
|
display_manialink_multi($player);
|
||||||
|
|
||||||
|
} elseif ($aseco->server->getGame() == 'TMN') {
|
||||||
|
$head = 'Current player access control settings:' . LF;
|
||||||
|
// initialize with Order entry
|
||||||
|
$info = 'Order: {#black}' . ($access_control['order'] ? 'Allow,Deny' : 'Deny,Allow') . LF . LF;
|
||||||
|
$lines = 2;
|
||||||
|
$player->msgs[0] = 1;
|
||||||
|
|
||||||
|
// collect Allow entries
|
||||||
|
$info .= '$gAllow:' . LF;
|
||||||
|
$lines++;
|
||||||
|
if ($access_control['allowall']) {
|
||||||
|
$info .= ' {#black}all' . LF;
|
||||||
|
$lines++;
|
||||||
|
} else {
|
||||||
|
foreach ($access_control['allow'] as $from) {
|
||||||
|
$info .= ' {#black}' . $from . LF;
|
||||||
|
if (++$lines > 9) {
|
||||||
|
$player->msgs[] = $aseco->formatColors($head . $info);
|
||||||
|
$lines = 0;
|
||||||
|
$info = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert spacer
|
||||||
|
$info .= LF;
|
||||||
|
if (++$lines > 9) {
|
||||||
|
$player->msgs[] = $aseco->formatColors($head . $info);
|
||||||
|
$lines = 0;
|
||||||
|
$info = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect Deny entries
|
||||||
|
$info .= '$gDeny:' . LF;
|
||||||
|
$lines++;
|
||||||
|
if ($access_control['denyall']) {
|
||||||
|
$info .= ' {#black}all' . LF;
|
||||||
|
$lines++;
|
||||||
|
} else {
|
||||||
|
foreach ($access_control['deny'] as $from) {
|
||||||
|
$info .= ' {#black}' . $from . LF;
|
||||||
|
if (++$lines > 9) {
|
||||||
|
$player->msgs[] = $aseco->formatColors($head . $info);
|
||||||
|
$lines = 0;
|
||||||
|
$info = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add if last batch exists
|
||||||
|
if ($info != '')
|
||||||
|
$player->msgs[] = $aseco->formatColors($head . $info);
|
||||||
|
|
||||||
|
// display popup message
|
||||||
|
if (count($player->msgs) == 2) {
|
||||||
|
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $player->msgs[1], 'OK', '', 0);
|
||||||
|
} elseif (count($player->msgs) > 2) {
|
||||||
|
$aseco->client->query('SendDisplayServerMessageToLogin', $login, $player->msgs[1], 'Close', 'Next', 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elseif ($command['params'] == 'reload') {
|
||||||
|
// reload/check access control
|
||||||
|
if (access_initcontrol($aseco, true)) {
|
||||||
|
$message = $access_control['messages']['reload'];
|
||||||
|
} else {
|
||||||
|
$access_control = array();
|
||||||
|
$message = $access_control['messages']['xmlerr'];
|
||||||
|
}
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$message = $access_control['messages']['missing'];
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
}
|
||||||
|
} // admin_access
|
||||||
|
?>
|
|
@ -0,0 +1,157 @@
|
||||||
|
<?php
|
||||||
|
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto TimeLimit plugin.
|
||||||
|
* Changes Timelimit for TimeAttack dynamically depending on the next
|
||||||
|
* track's author time.
|
||||||
|
*
|
||||||
|
* Original by ck|cyrus
|
||||||
|
* Rewrite by Xymph
|
||||||
|
*
|
||||||
|
* Dependencies: none (but must be after plugin.rasp_jukebox.php in plugins.xml)
|
||||||
|
*/
|
||||||
|
|
||||||
|
Aseco::registerEvent('onSync', 'load_atlconfig');
|
||||||
|
Aseco::registerEvent('onEndRace', 'autotimelimit');
|
||||||
|
|
||||||
|
global $atl_config, $atl_active, $atl_restart;
|
||||||
|
|
||||||
|
// load ATL configuration
|
||||||
|
function load_atlconfig($aseco) {
|
||||||
|
global $atl_config, $atl_active, $atl_restart;
|
||||||
|
|
||||||
|
// initialize flags
|
||||||
|
$atl_active = false;
|
||||||
|
$atl_restart = false;
|
||||||
|
|
||||||
|
// load config file
|
||||||
|
$config_file = 'autotime.xml';
|
||||||
|
if (file_exists($config_file)) {
|
||||||
|
$aseco->console('Load auto timelimit config [' . $config_file . ']');
|
||||||
|
if ($xml = $aseco->xml_parser->parseXml($config_file)) {
|
||||||
|
$atl_config = $xml['AUTOTIME'];
|
||||||
|
$atl_active = true;
|
||||||
|
} else {
|
||||||
|
trigger_error('[ATL] Could not read/parse config file ' . $config_file . ' !', E_USER_WARNING);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
trigger_error('[ATL] Could not find config file ' . $config_file . ' !', E_USER_WARNING);
|
||||||
|
}
|
||||||
|
} // load_atlconfig
|
||||||
|
|
||||||
|
// called @ onEndRace
|
||||||
|
function autotimelimit($aseco, $data) {
|
||||||
|
global $atl_config, $atl_active, $atl_restart;
|
||||||
|
|
||||||
|
// if not active, bail out immediately
|
||||||
|
if (!$atl_active) return;
|
||||||
|
// if restarting, bail out immediately
|
||||||
|
if ($atl_restart) {
|
||||||
|
$atl_restart = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get next game settings
|
||||||
|
$aseco->client->query('GetNextGameInfo');
|
||||||
|
$nextgame = $aseco->client->getResponse();
|
||||||
|
|
||||||
|
// check for TimeAttack on next track
|
||||||
|
if ($nextgame['GameMode'] == Gameinfo::TA) {
|
||||||
|
// check if auto timelimit enabled
|
||||||
|
if ($atl_config['MULTIPLICATOR'][0] > 0) {
|
||||||
|
// check if at least one active player on the server
|
||||||
|
if (active_player($aseco)) {
|
||||||
|
// get next track details
|
||||||
|
$challenge = get_trackinfo($aseco, 1);
|
||||||
|
$newtime = intval($challenge->authortime);
|
||||||
|
} else {
|
||||||
|
// server already switched so get current track name
|
||||||
|
$challenge = get_trackinfo($aseco, 0);
|
||||||
|
$newtime = 0; // force default
|
||||||
|
$newtime = intval($challenge->authortime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute new timelimit
|
||||||
|
if ($newtime <= 0) {
|
||||||
|
$newtime = $atl_config['DEFAULTTIME'][0] * 60 * 1000;
|
||||||
|
$tag = 'default';
|
||||||
|
} else {
|
||||||
|
$newtime *= $atl_config['MULTIPLICATOR'][0];
|
||||||
|
$newtime -= ($newtime % 1000); // round down to seconds
|
||||||
|
$tag = 'new';
|
||||||
|
}
|
||||||
|
// check for min/max times
|
||||||
|
if ($newtime < $atl_config['MINTIME'][0] * 60 * 1000) {
|
||||||
|
$newtime = $atl_config['MINTIME'][0] * 60 * 1000;
|
||||||
|
$tag = 'min';
|
||||||
|
} elseif ($newtime > $atl_config['MAXTIME'][0] * 60 * 1000) {
|
||||||
|
$newtime = $atl_config['MAXTIME'][0] * 60 * 1000;
|
||||||
|
$tag = 'max';
|
||||||
|
}
|
||||||
|
|
||||||
|
// set and log timelimit (strip .00 sec)
|
||||||
|
$aseco->client->addcall('SetTimeAttackLimit', array($newtime));
|
||||||
|
$aseco->console('set {1} timelimit for [{2}]: {3} (Author time: {4})',
|
||||||
|
$tag, stripColors($challenge->name, false),
|
||||||
|
substr(formatTime($newtime), 0, -3),
|
||||||
|
formatTime($challenge->authortime));
|
||||||
|
|
||||||
|
// display timelimit (strip .00 sec)
|
||||||
|
$message = formatText($atl_config['MESSAGE'][0], $tag,
|
||||||
|
stripColors($challenge->name),
|
||||||
|
substr(formatTime($newtime), 0, -3),
|
||||||
|
formatTime($challenge->authortime));
|
||||||
|
if ($atl_config['DISPLAY'][0] == 2 && function_exists('send_window_message'))
|
||||||
|
send_window_message($aseco, $message, true);
|
||||||
|
elseif ($atl_config['DISPLAY'][0] > 0)
|
||||||
|
$aseco->client->query('ChatSendServerMessage', $aseco->formatColors($message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // autotimelimit
|
||||||
|
|
||||||
|
// get info on current/next track
|
||||||
|
function get_trackinfo($aseco, $offset) {
|
||||||
|
|
||||||
|
// get current/next track using /nextmap algorithm
|
||||||
|
if ($aseco->server->getGame() != 'TMF') {
|
||||||
|
$aseco->client->query('GetCurrentChallengeIndex');
|
||||||
|
$trkid = $aseco->client->getResponse();
|
||||||
|
$trkid += $offset;
|
||||||
|
$aseco->client->resetError();
|
||||||
|
$rtn = $aseco->client->query('GetChallengeList', 1, $trkid);
|
||||||
|
$track = $aseco->client->getResponse();
|
||||||
|
if ($aseco->client->isError()) {
|
||||||
|
// get first track
|
||||||
|
$rtn = $aseco->client->query('GetChallengeList', 1, 0);
|
||||||
|
$track = $aseco->client->getResponse();
|
||||||
|
}
|
||||||
|
} else { // TMF
|
||||||
|
if ($offset == 1)
|
||||||
|
$aseco->client->query('GetNextChallengeIndex');
|
||||||
|
else
|
||||||
|
$aseco->client->query('GetCurrentChallengeIndex');
|
||||||
|
$trkid = $aseco->client->getResponse();
|
||||||
|
$rtn = $aseco->client->query('GetChallengeList', 1, $trkid);
|
||||||
|
$track = $aseco->client->getResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get track info
|
||||||
|
$rtn = $aseco->client->query('GetChallengeInfo', $track[0]['FileName']);
|
||||||
|
$trackinfo = $aseco->client->getResponse();
|
||||||
|
return new Challenge($trackinfo);
|
||||||
|
} // get_trackinfo
|
||||||
|
|
||||||
|
// check for at least one active player
|
||||||
|
function active_player($aseco) {
|
||||||
|
|
||||||
|
$total = 0;
|
||||||
|
// check all connected players
|
||||||
|
foreach ($aseco->server->players->player_list as $player) {
|
||||||
|
// get current player status
|
||||||
|
if (!$aseco->isSpectator($player))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} // active_player
|
||||||
|
?>
|
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chatlog plugin.
|
||||||
|
* Keeps log of player chat, and displays the chat log.
|
||||||
|
* Created by Xymph
|
||||||
|
*
|
||||||
|
* Dependencies: none
|
||||||
|
*/
|
||||||
|
|
||||||
|
Aseco::registerEvent('onChat', 'log_chat');
|
||||||
|
Aseco::addChatCommand('chatlog', 'Displays log of recent chat messages');
|
||||||
|
|
||||||
|
global $chatbuf; // chat history buffer
|
||||||
|
global $chatlen; // length of chat history
|
||||||
|
global $linelen; // max length of chat line
|
||||||
|
|
||||||
|
$chatbuf = array();
|
||||||
|
$chatlen = 30;
|
||||||
|
$linelen = 40;
|
||||||
|
|
||||||
|
// called @ onChat
|
||||||
|
function log_chat($aseco, $chat) {
|
||||||
|
global $chatbuf, $chatlen;
|
||||||
|
|
||||||
|
// check for non-empty player chat line, not a chat command
|
||||||
|
if ($chat[0] != $aseco->server->id && $chat[2] != '' && $chat[2]{0} != '/') {
|
||||||
|
// drop oldest chat line if buffer full
|
||||||
|
if (count($chatbuf) >= $chatlen) {
|
||||||
|
array_shift($chatbuf);
|
||||||
|
}
|
||||||
|
// append timestamp, player nickname (but strip wide font) & chat line to history
|
||||||
|
if ($player = $aseco->server->players->getPlayer($chat[1]))
|
||||||
|
$chatbuf[] = array(date('H:i:s'), str_ireplace('$w', '', $player->nickname), $chat[2]);
|
||||||
|
}
|
||||||
|
} // log_chat
|
||||||
|
|
||||||
|
function chat_chatlog($aseco, $command) {
|
||||||
|
global $chatbuf, $linelen;
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
$login = $player->login;
|
||||||
|
|
||||||
|
if (!empty($chatbuf)) {
|
||||||
|
if ($aseco->server->getGame() == 'TMN') {
|
||||||
|
$head = 'Recent chat history:' . LF;
|
||||||
|
$msg = '';
|
||||||
|
$lines = 0;
|
||||||
|
$player->msgs = array();
|
||||||
|
$player->msgs[0] = 1;
|
||||||
|
foreach ($chatbuf as $item) {
|
||||||
|
// break up long lines into chunks with continuation strings
|
||||||
|
$multi = explode(LF, wordwrap(stripColors($item[2]), $linelen, LF . '...'));
|
||||||
|
foreach ($multi as $line) {
|
||||||
|
$line = substr($line, 0, $linelen+3); // chop off excessively long words
|
||||||
|
$msg .= '$z' . ($aseco->settings['chatpmlog_times'] ? '$n<{#server}' . $item[0] . '$z$n>$m ' : '') .
|
||||||
|
'[{#black}' . $item[1] . '$z] ' . $line . 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
} elseif ($aseco->server->getGame() == 'TMF') {
|
||||||
|
$head = 'Recent chat history:';
|
||||||
|
$msg = array();
|
||||||
|
$lines = 0;
|
||||||
|
$player->msgs = array();
|
||||||
|
$player->msgs[0] = array(1, $head, array(1.2), array('Icons64x64_1', 'Outbox'));
|
||||||
|
foreach ($chatbuf as $item) {
|
||||||
|
// break up long lines into chunks with continuation strings
|
||||||
|
$multi = explode(LF, wordwrap(stripColors($item[2]), $linelen+30, LF . '...'));
|
||||||
|
foreach ($multi as $line) {
|
||||||
|
$line = substr($line, 0, $linelen+33); // chop off excessively long words
|
||||||
|
$msg[] = array('$z' . ($aseco->settings['chatpmlog_times'] ? '<{#server}' . $item[0] . '$z> ' : '') .
|
||||||
|
'[{#black}' . $item[1] . '$z] ' . $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);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No chat history found!'), $login);
|
||||||
|
}
|
||||||
|
} // chat_chatlog
|
||||||
|
?>
|
|
@ -0,0 +1,809 @@
|
||||||
|
<?php
|
||||||
|
/* vim: set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checkpoints plugin.
|
||||||
|
* Provides checkpoints/finish tracking, and displays checkpoint passages
|
||||||
|
* via automatic pop-ups (useful only in Rounds/Team/Cup modes).
|
||||||
|
* On TMF, manages the CP panel during playing, retiring & spectating,
|
||||||
|
* as well as the Cup mode's warm-up phase. Disabled in Stunts mode.
|
||||||
|
* Created by Xymph
|
||||||
|
*
|
||||||
|
* Dependencies: used by plugin.dedimania.php & plugin.localdatabase.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
Aseco::registerEvent('onPlayerConnect', 'addplayer_cp');
|
||||||
|
Aseco::registerEvent('onPlayerDisconnect', 'removeplayer_cp');
|
||||||
|
Aseco::registerEvent('onNewChallenge', 'reset_checkp');
|
||||||
|
Aseco::registerEvent('onBeginRound', 'clear_curr_cp');
|
||||||
|
Aseco::registerEvent('onEndRace', 'disable_checkp');
|
||||||
|
Aseco::registerEvent('onRestartChallenge', 'restart_checkp');
|
||||||
|
Aseco::registerEvent('onCheckpoint', 'store_checkp');
|
||||||
|
Aseco::registerEvent('onPlayerFinish1', 'store_finish'); // use pre event before local/Dedimania record processsing
|
||||||
|
Aseco::registerEvent('onPlayerInfoChanged', 'spec_togglecp');
|
||||||
|
|
||||||
|
Aseco::addChatCommand('cps', 'Sets local record checkpoints tracking');
|
||||||
|
Aseco::addChatCommand('cpsspec', 'Shows checkpoints of spectated player');
|
||||||
|
Aseco::addChatCommand('cptms', 'Displays all local records\' checkpoint times');
|
||||||
|
Aseco::addChatCommand('sectms', 'Displays all local records\' sector times');
|
||||||
|
|
||||||
|
global $checkpoints, $checkpoint_tests;
|
||||||
|
$checkpoints = array();
|
||||||
|
$checkpoint_tests = false; // after reload no tests until end race
|
||||||
|
|
||||||
|
class Checkpoints {
|
||||||
|
var $loclrec;
|
||||||
|
var $dedirec;
|
||||||
|
var $best_time;
|
||||||
|
var $best_fin;
|
||||||
|
var $best_cps;
|
||||||
|
var $curr_fin;
|
||||||
|
var $curr_cps;
|
||||||
|
var $speccers;
|
||||||
|
|
||||||
|
// init empty checkpoints
|
||||||
|
function Checkpoints() {
|
||||||
|
$this->loclrec = -1; // -1 = off, 0 = own/last rec, 1-max = rec #1-max
|
||||||
|
$this->dedirec = -1; // -1 = off, 0 = own/last rec, 1-30 = rec #1-30
|
||||||
|
$this->best_time = 0;
|
||||||
|
$this->best_fin = PHP_INT_MAX;
|
||||||
|
$this->curr_fin = PHP_INT_MAX;
|
||||||
|
$this->best_cps = array();
|
||||||
|
$this->curr_cps = array();
|
||||||
|
$this->speccers = array();
|
||||||
|
}
|
||||||
|
} // class Checkpoints
|
||||||
|
|
||||||
|
function chat_cps($aseco, $command) {
|
||||||
|
global $checkpoints;
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
$login = $player->login;
|
||||||
|
|
||||||
|
// check for relay server
|
||||||
|
if ($aseco->server->isrelay) {
|
||||||
|
$message = formatText($aseco->getChatMessage('NOTONRELAY'));
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($aseco->settings['display_checkpoints']) {
|
||||||
|
// set local checkpoints tracking
|
||||||
|
$param = $command['params'];
|
||||||
|
if (strtolower($param) == 'off') {
|
||||||
|
$checkpoints[$login]->loclrec = -1;
|
||||||
|
$checkpoints[$login]->dedirec = -1;
|
||||||
|
$message = '{#server}> Local checkpoints tracking: {#highlite}OFF';
|
||||||
|
}
|
||||||
|
elseif ($param == '') {
|
||||||
|
$checkpoints[$login]->loclrec = 0;
|
||||||
|
$checkpoints[$login]->dedirec = -1;
|
||||||
|
$message = '{#server}> Local checkpoints tracking: {#highlite}ON {#server}(your own or the last record)';
|
||||||
|
}
|
||||||
|
elseif (is_numeric($param) && $param > 0 && $param <= $aseco->server->records->max) {
|
||||||
|
$checkpoints[$login]->loclrec = intval($param);
|
||||||
|
$checkpoints[$login]->dedirec = -1;
|
||||||
|
$message = '{#server}> Local checkpoints tracking record: {#highlite}' . $checkpoints[$login]->loclrec;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$message = '{#server}> {#error}No such Local record {#highlite}$i ' . $param;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle TMF checkpoints panel
|
||||||
|
if ($aseco->server->getGame() == 'TMF') {
|
||||||
|
if ($checkpoints[$login]->loclrec == -1) {
|
||||||
|
// disable CP panel
|
||||||
|
if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers))
|
||||||
|
cpspanel_off($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers));
|
||||||
|
else
|
||||||
|
cpspanel_off($aseco, $login);
|
||||||
|
} else {
|
||||||
|
// enable CP panel unless spectator, Stunts mode, or warm-up
|
||||||
|
if (!$player->isspectator && $aseco->server->gameinfo->mode != Gameinfo::STNT && !$aseco->warmup_phase) {
|
||||||
|
if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers))
|
||||||
|
display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), 0, '$00f -.--');
|
||||||
|
else
|
||||||
|
display_cpspanel($aseco, $login, 0, '$00f -.--');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message = '{#server}> {#error}Checkpoints tracking permanently disabled by server';
|
||||||
|
}
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
} // chat_cps
|
||||||
|
|
||||||
|
function chat_cpsspec($aseco, $command) {
|
||||||
|
global $checkpoints;
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
$login = $player->login;
|
||||||
|
|
||||||
|
// check for relay server
|
||||||
|
if ($aseco->server->isrelay) {
|
||||||
|
$message = formatText($aseco->getChatMessage('NOTONRELAY'));
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($aseco->server->getGame() == 'TMF') {
|
||||||
|
if ($aseco->settings['enable_cpsspec']) {
|
||||||
|
// toggle cpsspec setting
|
||||||
|
if ($player->speclogin != '') {
|
||||||
|
// if subscribed, unsubscribe first
|
||||||
|
if ($player->speclogin != ',' && isset($checkpoints[$player->speclogin])) {
|
||||||
|
if (($i = array_search($login, $checkpoints[$player->speclogin]->speccers)) !== false)
|
||||||
|
unset($checkpoints[$player->speclogin]->speccers[$i]);
|
||||||
|
}
|
||||||
|
$player->speclogin = '';
|
||||||
|
cpspanel_off($aseco, $login);
|
||||||
|
} else {
|
||||||
|
// if spectator, subscribe
|
||||||
|
$aseco->client->query('GetPlayerInfo', $login, 1);
|
||||||
|
$info = $aseco->client->getResponse();
|
||||||
|
$targetid = floor($info['SpectatorStatus'] / 10000);
|
||||||
|
// check for player or free camera
|
||||||
|
if ($info['SpectatorStatus'] == 0 || $targetid == 255) {
|
||||||
|
$player->speclogin = ','; // no target
|
||||||
|
} else {
|
||||||
|
// find login for target
|
||||||
|
foreach ($aseco->server->players->player_list as $pl) {
|
||||||
|
if ($pl->pid == $targetid) {
|
||||||
|
$player->speclogin = $pl->login;
|
||||||
|
// subscribe to this player
|
||||||
|
if (!in_array($login, $checkpoints[$player->speclogin]->speccers))
|
||||||
|
$checkpoints[$player->speclogin]->speccers[] = $login;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// show chat message
|
||||||
|
$message = '{#server}> Spectated player checkpoints tracking ';
|
||||||
|
if ($player->speclogin != '')
|
||||||
|
$message .= 'enabled';
|
||||||
|
else
|
||||||
|
$message .= 'disabled';
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
} else {
|
||||||
|
$message = $aseco->getChatMessage('NO_CPSSPEC');
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message = $aseco->getChatMessage('FOREVER_ONLY');
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login);
|
||||||
|
}
|
||||||
|
} // chat_cpsspec
|
||||||
|
|
||||||
|
|
||||||
|
function chat_cptms($aseco, $command) {
|
||||||
|
chat_sectms($aseco, $command, false);
|
||||||
|
} // chat_cptms
|
||||||
|
|
||||||
|
function chat_sectms($aseco, $command, $diff = true) {
|
||||||
|
|
||||||
|
$player = $command['author'];
|
||||||
|
$login = $player->login;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find sector count from first record with CP times
|
||||||
|
$cpscnt = '?';
|
||||||
|
for ($i = 0; $i < $total; $i++) {
|
||||||
|
$cur_record = $aseco->server->records->getRecord($i);
|
||||||
|
if (!empty($cur_record->checks)) {
|
||||||
|
$cpscnt = count($cur_record->checks);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// display popup window for TMN
|
||||||
|
if ($aseco->server->getGame() == 'TMN') {
|
||||||
|
$head = 'Current TOP ' . $aseco->server->records->max . ' Local ' . ($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 = $aseco->server->records->getRecord($i);
|
||||||
|
$msg .= str_pad($i+1, 2, '0', STR_PAD_LEFT) . '. '
|
||||||
|
. ($cur_record->new ? '{#black}' : '')
|
||||||
|
. formatTime($cur_record->score);
|
||||||
|
// 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 ' . $aseco->server->records->max . ' Local ' . ($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 = $aseco->server->records->getRecord($i);
|
||||||
|
$line = array();
|
||||||
|
$line[] = str_pad($i+1, 2, '0', STR_PAD_LEFT) . '.';
|
||||||
|
$line[] = ($cur_record->new ? '{#black}' : '') .
|
||||||
|
($aseco->server->gameinfo->mode == Gameinfo::STNT ?
|
||||||
|
$cur_record->score : formatTime($cur_record->score));
|
||||||
|
// 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 sector times available');
|
||||||
|
$aseco->client->query('ChatSendServerMessageToLogin', $msg, $login);
|
||||||
|
}
|
||||||
|
} // chat_sectms
|
||||||
|
|
||||||
|
|
||||||
|
// called @ onPlayerConnect
|
||||||
|
function addplayer_cp($aseco, $player) {
|
||||||
|
global $checkpoints;
|
||||||
|
|
||||||
|
$login = $player->login;
|
||||||
|
|
||||||
|
$checkpoints[$login] = new Checkpoints();
|
||||||
|
// set first lap reference in Laps mode
|
||||||
|
if ($aseco->server->gameinfo->mode == Gameinfo::LAPS)
|
||||||
|
$checkpoints[$login]->curr_fin = 0;
|
||||||
|
if ($aseco->settings['display_checkpoints']) {
|
||||||
|
// set personal or default CPs
|
||||||
|
if ($cps = ldb_getCPs($aseco, $login)) {
|
||||||
|
$checkpoints[$login]->loclrec = $cps['cps'];
|
||||||
|
$checkpoints[$login]->dedirec = $cps['dedicps'];
|
||||||
|
} else {
|
||||||
|
if ($aseco->settings['auto_enable_cps'])
|
||||||
|
$checkpoints[$login]->loclrec = 0;
|
||||||
|
if ($aseco->settings['auto_enable_dedicps'])
|
||||||
|
$checkpoints[$login]->dedirec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // addplayer_cp
|
||||||
|
|
||||||
|
// called @ onPlayerDisconnect
|
||||||
|
function removeplayer_cp($aseco, $player) {
|
||||||
|
global $checkpoints;
|
||||||
|
|
||||||
|
$login = $player->login;
|
||||||
|
|
||||||
|
ldb_setCPs($aseco, $login,
|
||||||
|
$checkpoints[$login]->loclrec, $checkpoints[$login]->dedirec);
|
||||||
|
|
||||||
|
// free up memory
|
||||||
|
unset($checkpoints[$login]);
|
||||||
|
} // removeplayer_cp
|
||||||
|
|
||||||
|
// called @ onNewChallenge
|
||||||
|
function reset_checkp($aseco, $challenge) {
|
||||||
|
global $checkpoints, $laps_cpcount;
|
||||||
|
|
||||||
|
// clear all checkpoints
|
||||||
|
foreach ($checkpoints as $login => $cp) {
|
||||||
|
$checkpoints[$login]->best_cps = array();
|
||||||
|
$checkpoints[$login]->curr_cps = array();
|
||||||
|
$checkpoints[$login]->best_fin = PHP_INT_MAX;
|
||||||
|
if ($aseco->server->gameinfo->mode == Gameinfo::LAPS)
|
||||||
|
$checkpoints[$login]->curr_fin = 0;
|
||||||
|
else
|
||||||
|
$checkpoints[$login]->curr_fin = PHP_INT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set local checkpoint references
|
||||||
|
if ($aseco->settings['display_checkpoints']) {
|
||||||
|
foreach ($checkpoints as $login => $cp) {
|
||||||
|
$lrec = $checkpoints[$login]->loclrec - 1;
|
||||||
|
|
||||||
|
// check for specific record
|
||||||
|
if ($lrec+1 > 0) {
|
||||||
|
// if specific record unavailable, use last one
|
||||||
|
if ($lrec > $aseco->server->records->count() - 1)
|
||||||
|
$lrec = $aseco->server->records->count() - 1;
|
||||||
|
$curr = $aseco->server->records->getRecord($lrec);
|
||||||
|
// check for valid checkpoints
|
||||||
|
if (!empty($curr->checks) && $curr->score == end($curr->checks)) {
|
||||||
|
$checkpoints[$login]->best_fin = $curr->score;
|
||||||
|
$checkpoints[$login]->best_cps = $curr->checks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ($lrec+1 == 0) {
|
||||||
|
// search for own/last record
|
||||||
|
$lrec = 0;
|
||||||
|
while ($lrec < $aseco->server->records->count()) {
|
||||||
|
$curr = $aseco->server->records->getRecord($lrec++);
|
||||||
|
if ($curr->player->login == $login)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// check for valid checkpoints
|
||||||
|
if (!empty($curr->checks) && $curr->score == end($curr->checks)) {
|
||||||
|
$checkpoints[$login]->best_fin = $curr->score;
|
||||||
|
$checkpoints[$login]->best_cps = $curr->checks;
|
||||||
|
}
|
||||||
|
} // else -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CP count only for Laps mode
|
||||||
|
if ($aseco->server->getGame() == 'TMF')
|
||||||
|
$laps_cpcount = $challenge->nbchecks;
|
||||||
|
else
|
||||||
|
$laps_cpcount = 0;
|
||||||
|
} // reset_checkp
|
||||||
|
|
||||||
|
// called @ onBeginRound
|
||||||
|
function clear_curr_cp($aseco) {
|
||||||
|
global $checkpoints;
|
||||||
|
|
||||||
|
// if Stunts mode or warm-up, bail out immediately
|
||||||
|
if ($aseco->server->gameinfo->mode == Gameinfo::STNT || $aseco->warmup_phase) return;
|
||||||
|
|
||||||
|
// clear current checkpoints
|
||||||
|
foreach ($checkpoints as $login => $cp) {
|
||||||
|
$checkpoints[$login]->curr_cps = array();
|
||||||
|
// set first lap reference in Laps mode, otherwise max time
|
||||||
|
if ($aseco->server->gameinfo->mode == Gameinfo::LAPS)
|
||||||
|
$checkpoints[$login]->curr_fin = 0;
|
||||||
|
else
|
||||||
|
$checkpoints[$login]->curr_fin = PHP_INT_MAX;
|
||||||
|
|
||||||
|
// reset CP panel unless spectator
|
||||||
|
if ($aseco->server->getGame() == 'TMF' && $checkpoints[$login]->loclrec != -1) {
|
||||||
|
$player = $aseco->server->players->getPlayer($login);
|
||||||
|
if (!$player->isspectator) {
|
||||||
|
if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers))
|
||||||
|
display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), 0, '$00f -.--');
|
||||||
|
else
|
||||||
|
display_cpspanel($aseco, $login, 0, '$00f -.--');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // clear_curr_cp
|
||||||
|
|
||||||
|
// called @ onEndRace
|
||||||
|
function disable_checkp($aseco, $data) {
|
||||||
|
global $checkpoint_tests;
|
||||||
|
|
||||||
|
// disable CP panels at end of track
|
||||||
|
if ($aseco->server->getGame() == 'TMF') {
|
||||||
|
allcpspanels_off($aseco);
|
||||||
|
}
|
||||||
|
|
||||||
|
$checkpoint_tests = true; // now commence cheat tests
|
||||||
|
} // disable_checkp
|
||||||
|
|
||||||
|
// called @ onRestartChallenge
|
||||||
|
function restart_checkp($aseco, $data) {
|
||||||
|
global $checkpoints, $checkpoint_tests;
|
||||||
|
|
||||||
|
// clear current checkpoints
|
||||||
|
foreach ($checkpoints as $login => $cp) {
|
||||||
|
$checkpoints[$login]->curr_cps = array();
|
||||||
|
// set first lap reference in Laps mode, otherwise max time
|
||||||
|
if ($aseco->server->gameinfo->mode == Gameinfo::LAPS)
|
||||||
|
$checkpoints[$login]->curr_fin = 0;
|
||||||
|
else
|
||||||
|
$checkpoints[$login]->curr_fin = PHP_INT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
$checkpoint_tests = true; // now commence cheat tests
|
||||||
|
} // restart_checkp
|
||||||
|
|
||||||
|
// called @ onCheckpoint
|
||||||
|
// TMN: [0]=PlayerUid, [1]=Login, [2]=Time, [3]=Score, [4]=CheckpointIndex
|
||||||
|
// TMF: [0]=PlayerUid, [1]=Login, [2]=TimeOrScore, [3]=CurLap, [4]=CheckpointIndex
|
||||||
|
function store_checkp($aseco, $checkpt) {
|
||||||
|
global $rasp, $checkpoints, $laps_cpcount, $checkpoint_tests,
|
||||||
|
$feature_stats; // from rasp.settings.php
|
||||||
|
|
||||||
|
// if Stunts mode, bail out immediately
|
||||||
|
// no checkpoints during warm-up, so no need to check that
|
||||||
|
if ($aseco->server->gameinfo->mode == Gameinfo::STNT) return;
|
||||||
|
|
||||||
|
// if undefined login, bail out too
|
||||||
|
$login = $checkpt[1];
|
||||||
|
if (!isset($checkpoints[$login])) return;
|
||||||
|
|
||||||
|
// check for Laps mode
|
||||||
|
if ($aseco->server->gameinfo->mode != Gameinfo::LAPS) {
|
||||||
|
|
||||||
|
// reset for next run in TimeAttack mode
|
||||||
|
if ($aseco->server->gameinfo->mode == Gameinfo::TA && $checkpt[4] == 0)
|
||||||
|
$checkpoints[$login]->curr_cps = array();
|
||||||
|
|
||||||
|
// check for cheated checkpoints:
|
||||||
|
// non-positive time, wrong index, or time less than preceding one
|
||||||
|
if ($checkpt[2] <= 0 || $checkpt[4] != count($checkpoints[$login]->curr_cps) ||
|
||||||
|
($checkpt[4] > 0 && $checkpt[2] < end($checkpoints[$login]->curr_cps))) {
|
||||||
|
if ($checkpoint_tests) {
|
||||||
|
$aseco->processCheater($login, $checkpoints[$login]->curr_cps, $checkpt, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// store current checkpoint
|
||||||
|
$checkpoints[$login]->curr_cps[$checkpt[4]] = $checkpt[2];
|
||||||
|
|
||||||
|
// check if displaying for this player, and for best checkpoints
|
||||||
|
if ($checkpoints[$login]->loclrec != -1 &&
|
||||||
|
isset($checkpoints[$login]->best_cps[$checkpt[4]])) {
|
||||||
|
|
||||||
|
// check whether not last one (Finish) on TMN
|
||||||
|
$check = $checkpt[4] + 1;
|
||||||
|
if ($aseco->server->getGame() == 'TMF' ||
|
||||||
|
$check < count($checkpoints[$login]->best_cps)) {
|
||||||
|
|
||||||
|
$diff = $checkpoints[$login]->curr_cps[$checkpt[4]] -
|
||||||
|
$checkpoints[$login]->best_cps[$checkpt[4]];
|
||||||
|
// check for improvement
|
||||||
|
if ($diff < 0) {
|
||||||
|
$diff = abs($diff);
|
||||||
|
$sign = '$00f-'; // blue
|
||||||
|
} elseif ($diff == 0) {
|
||||||
|
$sign = '$00f'; // blue
|
||||||
|
} else { // $diff > 0
|
||||||
|
$sign = '$f00+'; // red
|
||||||
|
}
|
||||||
|
$sec = floor($diff/1000);
|
||||||
|
$hun = ($diff - ($sec * 1000)) / 10;
|
||||||
|
|
||||||
|
if ($aseco->server->getGame() == 'TMN') {
|
||||||
|
$cpmsg = '$nCP' . $check . ': $m$000' . formatTime($checkpt[2])
|
||||||
|
. ' $w' . $sign . sprintf('%d.%02d', $sec, $hun);
|
||||||
|
// display temporary popup message
|
||||||
|
$aseco->client->query('SendDisplayServerMessageToLogin', $login,
|
||||||
|
$cpmsg, '', '', 2000); // timeout 2 secs
|
||||||
|
} else { // TMF
|
||||||
|
// check for Finish checkpoint
|
||||||
|
if ($check == count($checkpoints[$login]->best_cps))
|
||||||
|
$check = 'F';
|
||||||
|
// update CP panel
|
||||||
|
if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers))
|
||||||
|
display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), $check,
|
||||||
|
$sign . sprintf('%d.%02d', $sec, $hun));
|
||||||
|
else
|
||||||
|
display_cpspanel($aseco, $login, $check,
|
||||||
|
$sign . sprintf('%d.%02d', $sec, $hun));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // Laps
|
||||||
|
|
||||||
|
// no support on TMN because PlayerCheckpoint event doesn't supply CurLap
|
||||||
|
if ($aseco->server->getGame() != 'TMF') return;
|
||||||
|
|
||||||
|
// check for cheated checkpoints:
|
||||||
|
// non-positive time, negative index
|
||||||
|
if ($checkpt[2] <= 0 || $checkpt[4] < 0) {
|
||||||
|
if ($checkpoint_tests) {
|
||||||
|
$aseco->processCheater($login, $checkpoints[$login]->curr_cps, $checkpt, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// in TMN get checkpoints count/lap from first player to complete first lap
|
||||||
|
if ($laps_cpcount == 0 && $checkpt[3] == 1)
|
||||||
|
$laps_cpcount = $checkpt[4] + 1;
|
||||||
|
|
||||||
|
// get relative CP in this lap
|
||||||
|
if ($laps_cpcount > 0)
|
||||||
|
$relcheck = $checkpt[4] % $laps_cpcount;
|
||||||
|
else // first lap
|
||||||
|
$relcheck = $checkpt[4];
|
||||||
|
|
||||||
|
// check for cheated checkpoints:
|
||||||
|
// wrong index, time not more than reference, relative time less than preceding one
|
||||||
|
if ($relcheck != count($checkpoints[$login]->curr_cps) ||
|
||||||
|
$checkpt[2] < $checkpoints[$login]->curr_fin ||
|
||||||
|
($relcheck > 0 && $checkpt[2] - $checkpoints[$login]->curr_fin < end($checkpoints[$login]->curr_cps))) {
|
||||||
|
if ($checkpoint_tests) {
|
||||||
|
$aseco->processCheater($login, $checkpoints[$login]->curr_cps, $checkpt, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// store current checkpoint for current lap, relative to reference
|
||||||
|
$checkpoints[$login]->curr_cps[$relcheck] = $checkpt[2] - $checkpoints[$login]->curr_fin;
|
||||||
|
|
||||||
|
// check for a completed lap
|
||||||
|
if ($checkpt[3] * $laps_cpcount != $checkpt[4] + 1) {
|
||||||
|
|
||||||
|
// check if displaying for this player, and for best checkpoints
|
||||||
|
if ($checkpoints[$login]->loclrec != -1 &&
|
||||||
|
isset($checkpoints[$login]->best_cps[$relcheck])) {
|
||||||
|
|
||||||
|
// check for improvement
|
||||||
|
$diff = $checkpoints[$login]->curr_cps[$relcheck] - $checkpoints[$login]->best_cps[$relcheck];
|
||||||
|
if ($diff < 0) {
|
||||||
|
$diff = abs($diff);
|
||||||
|
$sign = '$00f-'; // blue
|
||||||
|
} elseif ($diff == 0) {
|
||||||
|
$sign = '$00f'; // blue
|
||||||
|
} else { // $diff > 0
|
||||||
|
$sign = '$f00+'; // red
|
||||||
|
}
|
||||||
|
$sec = floor($diff/1000);
|
||||||
|
$hun = ($diff - ($sec * 1000)) / 10;
|
||||||
|
|
||||||
|
// update CP panel
|
||||||
|
if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers))
|
||||||
|
display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), $relcheck + 1,
|
||||||
|
$sign . sprintf('%d.%02d', $sec, $hun));
|
||||||
|
else
|
||||||
|
display_cpspanel($aseco, $login, $relcheck + 1,
|
||||||
|
$sign . sprintf('%d.%02d', $sec, $hun));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // completed lap
|
||||||
|
|
||||||
|
// store current lap finish as reference for next lap
|
||||||
|
$checkpoints[$login]->curr_fin = $checkpt[2];
|
||||||
|
|
||||||
|
// build a record object with the current lap information
|
||||||
|
$finish_item = new Record();
|
||||||
|
$finish_item->player = $aseco->server->players->getPlayer($login);
|
||||||
|
$finish_item->score = $checkpoints[$login]->curr_cps[$relcheck];
|
||||||
|
$finish_item->date = strftime('%Y-%m-%d %H:%M:%S');
|
||||||
|
$finish_item->challenge = clone $aseco->server->challenge;
|
||||||
|
unset($finish_item->challenge->gbx); // reduce memory usage
|
||||||
|
unset($finish_item->challenge->tmx);
|
||||||
|
|
||||||
|
// store current lap
|
||||||
|
if ($feature_stats) {
|
||||||
|
$rasp->insertTime($finish_item, implode(',', $checkpoints[$login]->curr_cps));
|
||||||
|
}
|
||||||
|
|
||||||
|
// process for local and Dedimania records
|
||||||
|
$finish_item->new = true; // set lap 'Finish' flag
|
||||||
|
ldb_playerFinish($aseco, $finish_item);
|
||||||
|
$finish_item->new = true; // ditto
|
||||||
|
if (function_exists('dedimania_playerfinish'))
|
||||||
|
dedimania_playerfinish($aseco, $finish_item);
|
||||||
|
|
||||||
|
// check for new best lap
|
||||||
|
$diff = $checkpoints[$login]->curr_cps[$relcheck] - $checkpoints[$login]->best_fin;
|
||||||
|
if ($diff < 0) {
|
||||||
|
// store new best lap
|
||||||
|
$checkpoints[$login]->best_fin = $checkpoints[$login]->curr_cps[$relcheck];
|
||||||
|
$checkpoints[$login]->best_cps = $checkpoints[$login]->curr_cps;
|
||||||
|
// store timestamp for sorting in case of equal bests
|
||||||
|
$checkpoints[$login]->best_time = microtime(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if displaying for this player, and not first lap
|
||||||
|
if ($checkpoints[$login]->loclrec != -1 && $checkpt[4] + 1 >= $laps_cpcount) {
|
||||||
|
// check for improvement
|
||||||
|
if ($diff < 0) {
|
||||||
|
$diff = abs($diff);
|
||||||
|
$sign = '$00f-'; // blue
|
||||||
|
} elseif ($diff == 0) {
|
||||||
|
$sign = '$00f'; // blue
|
||||||
|
} else { // $diff > 0
|
||||||
|
$sign = '$f00+'; // red
|
||||||
|
}
|
||||||
|
$sec = floor($diff/1000);
|
||||||
|
$hun = ($diff - ($sec * 1000)) / 10;
|
||||||
|
|
||||||
|
// indicate Lap Finish checkpoint
|
||||||
|
$relcheck = 'L';
|
||||||
|
// update CP panel
|
||||||
|
if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers))
|
||||||
|
display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), $relcheck,
|
||||||
|
$sign . sprintf('%d.%02d', $sec, $hun));
|
||||||
|
else
|
||||||
|
display_cpspanel($aseco, $login, $relcheck,
|
||||||
|
$sign . sprintf('%d.%02d', $sec, $hun));
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset for next lap
|
||||||
|
$checkpoints[$login]->curr_cps = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // store_checkp
|
||||||
|
|
||||||
|
// called @ onPlayerFinish1
|
||||||
|
function store_finish($aseco, $finish_item) {
|
||||||
|
global $checkpoints, $checkpoint_tests;
|
||||||
|
|
||||||
|
// if Laps or Stunts mode, bail out immediately
|
||||||
|
// no finishes during warm-up, so no need to check that
|
||||||
|
if ($aseco->server->gameinfo->mode == Gameinfo::LAPS ||
|
||||||
|
$aseco->server->gameinfo->mode == Gameinfo::STNT) return;
|
||||||
|
|
||||||
|
$login = $finish_item->player->login;
|
||||||
|
// in case of CP order problem
|
||||||
|
sort($checkpoints[$login]->curr_cps);
|
||||||
|
|
||||||
|
// check for actual finish
|
||||||
|
if ($finish_item->score > 0) {
|
||||||
|
// compute number of checkpoints (incl. multilaps except in TA mode)
|
||||||
|
$reqchecks = $finish_item->challenge->nbchecks;
|
||||||
|
if ($aseco->server->getGame() == 'TMF' && $aseco->server->gameinfo->mode != Gameinfo::TA &&
|
||||||
|
$finish_item->challenge->laprace) {
|
||||||
|
if ($finish_item->challenge->forcedlaps != 0)
|
||||||
|
$reqchecks *= $finish_item->challenge->forcedlaps;
|
||||||
|
else
|
||||||
|
$reqchecks *= $finish_item->challenge->nblaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for required number of checkpoints on TMF
|
||||||
|
if ($aseco->server->getGame() == 'TMF' && $reqchecks != count($checkpoints[$login]->curr_cps)) {
|
||||||
|
if ($checkpoint_tests) {
|
||||||
|
trigger_error('CPs for ' . $login . ' required: ' . $reqchecks . ' present: ' . count($checkpoints[$login]->curr_cps) .
|
||||||
|
' - ' . implode(',', $checkpoints[$login]->curr_cps), E_USER_WARNING);
|
||||||
|
}
|
||||||
|
// reset to prevent local/Dedimania records
|
||||||
|
$finish_item->score = 0;
|
||||||
|
// check for finish equal last checkpoint
|
||||||
|
} elseif ($finish_item->score == end($checkpoints[$login]->curr_cps)) {
|
||||||
|
$checkpoints[$login]->curr_fin = $finish_item->score;
|
||||||
|
|
||||||
|
// check for improvement
|
||||||
|
if ($checkpoints[$login]->curr_fin < $checkpoints[$login]->best_fin) {
|
||||||
|
$checkpoints[$login]->best_fin = $checkpoints[$login]->curr_fin;
|
||||||
|
$checkpoints[$login]->best_cps = $checkpoints[$login]->curr_cps;
|
||||||
|
// store timestamp for sorting in case of equal bests
|
||||||
|
$checkpoints[$login]->best_time = microtime(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($checkpoint_tests) {
|
||||||
|
$aseco->processCheater($login, $checkpoints[$login]->curr_cps, false, $finish_item->score);
|
||||||
|
// reset to prevent local/Dedimania records
|
||||||
|
$finish_item->score = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check for player retire in TimeAttack mode
|
||||||
|
elseif ($aseco->server->getGame() == 'TMF' && $aseco->server->gameinfo->mode == Gameinfo::TA &&
|
||||||
|
$finish_item->score == 0 && $checkpoints[$login]->loclrec != -1) {
|
||||||
|
// reset CP panel
|
||||||
|
if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers))
|
||||||
|
display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), 0, '$00f -.--');
|
||||||
|
else
|
||||||
|
display_cpspanel($aseco, $login, 0, '$00f -.--');
|
||||||
|
}
|
||||||
|
} // store_finish
|
||||||
|
|
||||||
|
// called @ onPlayerInfoChanged
|
||||||
|
function spec_togglecp($aseco, $playerinfo) {
|
||||||
|
global $checkpoints;
|
||||||
|
|
||||||
|
// if Stunts mode or warm-up, bail out immediately
|
||||||
|
if ($aseco->server->gameinfo->mode == Gameinfo::STNT || $aseco->warmup_phase) return;
|
||||||
|
|
||||||
|
$login = $playerinfo['Login'];
|
||||||
|
$player = $aseco->server->players->getPlayer($login);
|
||||||
|
// if no real spectator status change, bail out immediately
|
||||||
|
if ($player->prevstatus == $player->isspectator) return;
|
||||||
|
|
||||||
|
// check if CPS active
|
||||||
|
if (isset($checkpoints[$login]) && $checkpoints[$login]->loclrec != -1) {
|
||||||
|
// check spectator status
|
||||||
|
if ($playerinfo['SpectatorStatus'] != 0) {
|
||||||
|
// disable CP panel
|
||||||
|
if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers))
|
||||||
|
cpspanel_off($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers));
|
||||||
|
else
|
||||||
|
cpspanel_off($aseco, $login);
|
||||||
|
} else {
|
||||||
|
// enable CP panel
|
||||||
|
if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers))
|
||||||
|
display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), 0, '$00f -.--');
|
||||||
|
else
|
||||||
|
display_cpspanel($aseco, $login, 0, '$00f -.--');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for spectated player update
|
||||||
|
if ($aseco->settings['enable_cpsspec']) {
|
||||||
|
// check if /cpsspec enabled
|
||||||
|
if ($player->speclogin != '') {
|
||||||
|
$targetid = floor($playerinfo['SpectatorStatus'] / 10000);
|
||||||
|
|
||||||
|
// check for player status or free camera
|
||||||
|
if ($playerinfo['SpectatorStatus'] == 0 || $targetid == 255) {
|
||||||
|
// if subscribed, unsubscribe first
|
||||||
|
if ($player->speclogin != ',' && isset($checkpoints[$player->speclogin])) {
|
||||||
|
if (($i = array_search($login, $checkpoints[$player->speclogin]->speccers)) !== false)
|
||||||
|
unset($checkpoints[$player->speclogin]->speccers[$i]);
|
||||||
|
}
|
||||||
|
$player->speclogin = ','; // no target
|
||||||
|
} else {
|
||||||
|
// ignore stray self-spectating PlayerInfoChanged events
|
||||||
|
if ($player->pid != $targetid) {
|
||||||
|
// find login for target
|
||||||
|
foreach ($aseco->server->players->player_list as $pl) {
|
||||||
|
if ($pl->pid == $targetid) {
|
||||||
|
$player->speclogin = $pl->login;
|
||||||
|
// subscribe to this player
|
||||||
|
if (!in_array($login, $checkpoints[$player->speclogin]->speccers))
|
||||||
|
$checkpoints[$player->speclogin]->speccers[] = $login;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // spec_togglecp
|
||||||
|
?>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue