// TribesNext Project // http://www.tribesnext.com/ // Copyright 2011-2012 // Tribes 2 Community System // Robot Browser Client // This scripts implements a network data interface to the TribseNext community system browser robot data // interface. The "robot" data interface provides the data in a way that is easy to parse with the meager // and mediocre string processing and parsing features present in the Tribes 2 game. If you are reading this // script and desire to make some sort of third party client for web access or other purposes, you will have // a much easier time if you use the JSON API to access the same data. // Currently available methods (as of RC3) are as follow: // - Retrieval of a "Community Enhanced Certificate" indicating current name/tag/membership. // - Search for clans by name. // - Search for players by name. // - View a clan profile. // - View a player profile. // - View a clan history. // - View a player history. // - Change recruiting status of a clan. // - Change the profile info of a clan. // - Change a clan's tag. // - Change a clan's website. // - Change a clan name. // - Change which in-game picture is displayed on the clan profile page. // - Invite a player to a clan. // - View outstanding invites to a clan. // - Change the rank/title of either one's self, or of others in a clan. // - Authorize disbanding a clan. // - Kick another player from a clan. // - Change the player name of an account. // - Change which clan tag an account will display. // - Change a player's profile website. // - Change a player's profile info. // - Accept an invitation to join a clan. // - Reject an invitation to join a clan. // - Leave a clan. // - Create a clan. $TribesNext::Community::Browser::Active = 0; function CommunityBrowserInterface::onConnected(%this) { echo("Browser-Sending: " @ %this.data); %this.primed = 0; %this.send(%this.data); } function CommunityBrowserInterface::onDisconnect(%this) { if (!%this.primed) { // nothing sent from the server // this means there is probably a firewall interfering with the communication // with a rare chance that the browser system is unavailable (in which case we will post an announcement) // alert the user the first time if (!$TribesNext::Community::Browser::Firewalled) { $TribesNext::Community::Browser::Firewalled = 1; schedule(500, 0, MessageBoxOK, "NETWORK", "Unable to communicate with the browser server via HTTP. Reconfigure your firewall to allow access."); } } $TribesNext::Community::Browser::Active = 0; tn_community_Browser_executeNextRequest(); } function CommunityBrowserInterface::onLine(%this, %line) { if (trim(%line) $= "") { %this.primed = 1; return; } if (!%this.primed) return; warn("Browser: " @ %line); if (getSubStr(%line, 0, 4) $= "ERR:") { // A really exceptional error happened in the browser system schedule(500, 0, MessageBoxOK, "SYSTEM ERROR", trim(getSubStr(%line, 4, strlen(%line)))); } %message = getField(%line, 0); switch$ (%message) { // display errors to the user -- most of these should never actually happen // unless the user is being intentionally naughty or is operating on stale data case "ERR": if (getField(%line, 1) $= "BROWSER") { schedule(500, 0, MessageBoxOK, "ERROR", getFields(%line, 2)); } // DCE and CEC returns are certificates that are handed to game servers to get tags // and handle name changes -- they replace the authInfo field, instead of having the // server generate a skeleton version of the authInfo from the GUID and name. // in the absense of a DCE/CEC pair, the player will still be able to play with the // "raw" account, using the original account name and no tag case "DCE": %dceCert = collapseEscape(getField(%line, 1)); %index = getField(%dceCert, 1); $T2CSRI::ClientDCESupport::DCECert[%index] = %dceCert; case "CEC": $T2CSRI::CommunityCertificate = collapseEscape(getField(%line, 1)); // schedule a refresh %expire = getField($T2CSRI::CommunityCertificate, 2); rubyEval("tsEval '$temp=\"' + (" @ %expire @ " - Time.now().to_i).to_s + '\";'"); %expire = $temp - 60; if (%expire > 0) { if (isEventPending($TribesNext::Browser::CertRefreshSch)) cancel($TribesNext::Browser::CertRefreshSch); $TribesNext::Browser::CertRefreshSch = schedule(1000 * %expire, 0, tn_community_Browser_request_cert); } else { schedule(500, 0, MessageBoxOK, "ERROR", "Received expired certificate from community server. Is your computer's clock set correctly?"); } // data access methods // results for searching for a clan by name case "CSEARCH": %query = getField(%line, 1); if ($Browser::CQuery !$= %query) { // new query -- wipe old results deleteVariables("$Browser::CResults*"); $Browser::CQuery = %query; $Browser::CCount = ""; } %idx = getField(%line, 2) + 0; %answer = getFields(%line, 3); $Browser::CResults[%idx] = %answer; if (%idx >= $Browser::CCount) $Browser::CCount = %idx; // results for querying a clan (all necessary to display in UI) case "CLAN": %id = getField(%line, 2); %var = getField(%line, 1); %clan = tn_community_browser_getClanProfile(%id); if (%var $= "NAME") { // wipe the players so membership doesn't look screwed up if it shrinks tn_community_browser_wipePlayers(%clan); %clan.name = getField(%line, 3); %clan.lastRefresh = getSimTime(); } else if (%var $= "TAG") { %clan.tag = getField(%line, 3) TAB getField(%line, 4); } else if (%var $= "RECR") { %clan.recruiting = getField(%line, 3); } else if (%var $= "SITE") { %clan.site = getField(%line, 3); } else if (%var $= "DATE") { // convert epoch to human readable %clan.date = tn_community_mailui_epochToDate(getField(%line, 3)); } else if (%var $= "PICT") { %clan.picture = getField(%line, 3); } else if (%var $= "ACTIVE") { %clan.active = getField(%line, 3); } else if (%var $= "INFO") { %clan.info = collapseEscape(getField(%line, 3)); } else if (%var $= "MEMB") { %idx = getField(%line, 3) + 0; %clan.player[%idx] = getFields(%line, 4); if (%idx >= %clan.pcount) %clan.pcount = %idx; } // results for querying a clan history case "CHIST": %id = getField(%line, 1); %idx = getField(%line, 2) + 0; %clan = tn_community_browser_getClanProfile(%id); %event = getFields(%line, 3); if (%event !$= %clan.history[%idx]) { // underlying event has changed, clear the display cache // this may occur if one of the underlying players has changed // active clan, or name %clan.historyCache[%idx] = ""; } %clan.history[%idx] = %event; if (%idx >= %clan.hcount) %clan.hcount = %idx; // results for searching for a player by name case "SEARCH": %query = getField(%line, 1); if ($Browser::PQuery !$= %query) { // new query -- wipe old results deleteVariables("$Browser::PResults*"); $Browser::PQuery = %query; $Browser::PCount = ""; } %idx = getField(%line, 2) + 0; %answer = tn_community_util_extractPlayer(%line, 3); $Browser::PResults[%idx] = %answer; if ($Browser::PCount $= "" || %idx >= $Browser::PCount) $Browser::PCount = %idx; // results for querying a player (all necessary to display in UI) case "PLAYER": %guid = getField(%line, 2); %var = getField(%line, 1); %player = tn_community_browser_getPlayerProfile(%guid); if (%var $= "NAME") { tn_community_browser_wipeMemberships(%player); %player.name = getField(%line, 3); %player.lastRefresh = getSimTime(); } else if (%var $= "TAG") { %player.tag = getField(%line, 3) TAB getField(%line, 4); } else if (%var $= "DATE") { // convert epoch to human readable %player.date = tn_community_mailui_epochToDate(getField(%line, 3)); } else if (%var $= "SITE") { %player.site = getField(%line, 3); } else if (%var $= "INFO") { %player.info = collapseEscape(getField(%line, 3)); } else if (%var $= "ONLINE") { %player.online = getField(%line, 3); } else if (%var $= "CLAN") { %idx = getField(%line, 3) + 0; %player.membership[%idx] = getFields(%line, 4); if (%idx >= %player.mcount) %player.mcount = %idx; } // results for querying a player history case "PHIST": %guid = getField(%line, 1); %idx = getField(%line, 2) + 0; %player = tn_community_browser_getPlayerProfile(%guid); %event = getFields(%line, 3); if (%event !$= %player.history[%idx]) { // underlying event has changed, clear the display cache // this may occur if one of the underlying players has changed // active clan, or name %player.historyCache[%idx] = ""; } %player.history[%idx] = %event; if (%idx >= %player.hcount) %player.hcount = %idx; // clan management // clan recruit flag changes case "CLAN_RECRUITING": // for these clan management methods, we just queue a redownload of the profile page %id = getField(%line, 2); tn_community_browser_getClanProfile(%id).lastRefresh = 0; tn_community_browser_clan_view(%id); // clan info page changes case "CLAN_INFO": // for these clan management methods, we just queue a redownload of the profile page %id = getField(%line, 2); tn_community_browser_getClanProfile(%id).lastRefresh = 0; tn_community_browser_clan_view(%id); // clan tag changes case "CLAN_RETAGGED": // for these clan management methods, we just queue a redownload of the profile page %id = getField(%line, 1); tn_community_browser_getClanProfile(%id).lastRefresh = 0; tn_community_browser_clan_view(%id); // clan website changes case "CLAN_WEBSITE": // for these clan management methods, we just queue a redownload of the profile page %id = getField(%line, 1); tn_community_browser_getClanProfile(%id).lastRefresh = 0; tn_community_browser_clan_view(%id); // clan renamed case "CLAN_RENAMED": // for these clan management methods, we just queue a redownload of the profile page %id = getField(%line, 1); tn_community_browser_getClanProfile(%id).lastRefresh = 0; tn_community_browser_clan_view(%id); // clan team picture changed case "CLAN_TEAMPIC": // for these clan management methods, we just queue a redownload of the profile page %id = getField(%line, 2); tn_community_browser_getClanProfile(%id).lastRefresh = 0; tn_community_browser_clan_view(%id); // clan invitation sent case "INVITED": %id = getField(%line, 2); %guid = getField(%line, 1); %clan = tn_community_browser_getClanProfile(%id); %player = tn_community_browser_getPlayerProfile(%guid); if (%clan.name !$= "" && %player.name !$= "") { // have both clan and player name %out = "Sent \"" @ %player.name @ "\" an invitation to join \"" @ %clan.name @ "\"."; } else if (%clan.name $= "" && %player.name !$= "") { // just have player name %out = "Sent invitation to \"" @ %player.name @ "\"."; } else if (%clan.name !$= "" && %player.name $= "") { // just have clan name %out = "Sent invitation to join \"" @ %clan.name @ "\"."; } else { // have neither clan or player name %out = "Invitation sent."; } schedule(500, 0, MessageBoxOK, "INVITATION", %out); // results for querying the pending invites on a clan case "INVITEE": %id = getField(%line, 1); %idx = getField(%line, 2) + 0; %clan = tn_community_browser_getClanProfile(%id); %clan.invitee[%idx] = getFields(%line, 3); if (%idx > %clan.icount) %clan.icount = %idx; // changing a clan rank/title of one's self case "CLAN_RANK_SET": // for these clan management methods, we just queue a redownload of the profile page %id = getField(%line, 1); tn_community_browser_getClanProfile(%id).lastRefresh = 0; tn_community_browser_clan_view(%id); // changing a clan rank/title of another clan member case "CLAN_RANK_OTHER": // for these clan management methods, we just queue a redownload of the profile page %id = getField(%line, 1); tn_community_browser_getClanProfile(%id).lastRefresh = 0; tn_community_browser_clan_view(%id); // retracting a disband authorization case "DISBAND_RETRACTED": %id = getField(%line, 1); %clan = tn_community_browser_getClanProfile(%id); if (%clan.name !$= "") { %out = "You have retracted your disband authorization for \"" @ %clan.name @ "\"."; } else { %out = "You have retracted your disband authorization for the clan."; } schedule(500, 0, MessageBoxOK, "AUTHORIZATION", %out); // clan disband authorized, but still need disband consensus case "AUTHORIZED_DISBAND": %id = getField(%line, 1); %clan = tn_community_browser_getClanProfile(%id); if (%clan.name !$= "") { %out = "You have authorized disbanding \"" @ %clan.name @ "\"."; } else { %out = "You have authorized disbanding the clan."; } schedule(500, 0, MessageBoxOK, "AUTHORIZATION", %out); // clan disband authorized and disband completed case "DISBANDED_CLAN": %id = getField(%line, 1); %clan = tn_community_browser_getClanProfile(%id); if (%clan.name !$= "") { %out = "You have disbanded clan \"" @ %clan.name @ "\"."; } else { %out = "You have disbanded the clan."; } schedule(500, 0, MessageBoxOK, "DISBANDED", %out); tn_community_browser_clan_view(%id); // kicked another person from clan case "CLAN_KICKED": // for these clan management methods, we just queue a redownload of the profile page %id = getField(%line, 1); tn_community_browser_getClanProfile(%id).lastRefresh = 0; tn_community_browser_clan_view(%id); // user profile management // user successfully renamed the visible name of their account case "RENAMED": // update our own profile and certificate tn_community_browser_user_view(getField($LoginCertificate, 1)); tn_community_browser_request_cert(); // user switched their active clan tag (or turned it off) case "ACTIVE_CLAN": // update our own profile and certificate tn_community_browser_user_view(getField($LoginCertificate, 1)); tn_community_browser_request_cert(); // user switched their profile website link case "PLAYER_WEBSITE": // update our own profile tn_community_browser_user_view(getField($LoginCertificate, 1)); // user switched their profile info case "PLAYER_INFO_UPDATED": // update our own profile tn_community_browser_user_view(getField($LoginCertificate, 1)); // player accepted an invitation to join a clan case "CLAN_JOINED": // update our copy of the clan profile %id = getField(%line, 1); tn_community_browser_getClanProfile(%id).lastRefresh = 0; tn_community_browser_clan_view(%id); // also update our own profile and certificate tn_community_browser_user_view(getField($LoginCertificate, 1)); tn_community_browser_request_cert(); // player has rejected an invitation to join a clan case "INVITATION_DECLINED": %id = getField(%line, 1); %clan = tn_community_browser_getClanProfile(%id); if (%clan.name !$= "") { %out = "You have rejected an invitation to join \"" @ %clan.name @ "\"."; } else { %out = "You have rejected this clan invitation."; } schedule(500, 0, MessageBoxOK, "INVITATION", %out); // player has left a clan case "CLAN_LEFT": // update our copy of the clan profile %id = getField(%line, 1); tn_community_browser_getClanProfile(%id).lastRefresh = 0; tn_community_browser_clan_view(%id); // also update our own profile and certificate tn_community_browser_user_view(getField($LoginCertificate, 1)); tn_community_browser_request_cert(); // player has created a clan case "CLAN_CREATED": // update our copy of the clan profile %id = getField(%line, 1); tn_community_browser_getClanProfile(%id).lastRefresh = 0; tn_community_browser_clan_view(%id); // also update our own profile and certificate tn_community_browser_user_view(getField($LoginCertificate, 1)); tn_community_browser_request_cert(); // UI hook: pop the creation dialog Canvas.popDialog(CreateTribeDlg); // for the newly created clan, create a new tab switch us to it LaunchTabView.viewTab("BROWSER", TribeAndWarriorBrowserGui, 0); TWBTabView.view(%fld[1], "", "Tribe"); } } // primary data store structures for the browser // BrowserPlayer: // guid (primary key) // name // tag = tag \t append // date (epoch) // site // info // online (boolean) // mcount // membership[x] = clanid \t clanname \t rank \t title \t tag \t append // hcount // history[x] = (player history entry) -> entry 0 is oldest // BrowserClan: // id (primary key) // name // tag = (tag \t append) // recruiting (boolean) // site // date (epoch) // picture // active (boolean) // info // pcount // player[x] = (name \t tag \t append \t guid) \t rank \t escape(title) \t online? // hcount // history[x] = (clan history entry) -> entry 0 is oldest // icount // invitee[x] = expiration \t (sender player) \t (recipient player) function tn_community_browser_wipeMemberships(%this) { %count = %this.mcount; for (%i = 0; %i < %count; %i++) { %this.membership[%i] = ""; } %this.mcount = ""; %count = %this.icount; for (%i = 0; %i < %count; %i++) { %this.invitee[%i] = ""; } %this.icount = ""; } function tn_community_browser_wipePlayers(%this) { %count = %this.pcount; for (%i = 0; %i < %count; %i++) { %this.player[%i] = ""; } %this.pcount = ""; } function tn_community_browser_getPlayerProfile(%guid) { if (isObject($Browser::PlayerProfileTable[%guid])) return $Browser::PlayerProfileTable[%guid]; %profile = new SimObject() { classname = BrowserPlayer; guid = %guid; }; $Browser::PlayerProfileTable[%guid] = %profile; $BrowserPlayerSet.add(%profile); return %profile; } function tn_community_browser_getClanProfile(%id) { if (isObject($Browser::ClanProfileTable[%id])) return $Browser::ClanProfileTable[%id]; %profile = new SimObject() { classname = BrowserClan; id = %id; }; $Browser::ClanProfileTable[%id] = %profile; $BrowserClanSet.add(%profile); return %profile; } function tn_community_browser_initQueue() { // initialize a message vector to handle queuing requests to the remote system if (isObject($BrowserRequestQueue)) $BrowserRequestQueue.delete(); $BrowserRequestQueue = new MessageVector(); // initialize the browser player and clan object caches if (isObject($BrowserPlayerSet)) { while ($BrowserPlayerSet.getCount() > 0) $BrowserPlayerSet.getObject(0).delete(); $BrowserPlayerSet.delete(); } if (isObject($BrowserClanSet)) { while ($BrowserClanSet.getCount() > 0) $BrowserClanSet.getObject(0).delete(); $BrowserClanSet.delete(); } $BrowserPlayerSet = new SimSet(); $BrowserClanSet = new SimSet(); } tn_community_browser_initQueue(); function tn_community_browser_processRequest(%request, %payload) { if (%request !$= "") { %request = "?guid=" @ getField($LoginCertificate, 1) @ "&uuid=" @ $TribesNext::Community::UUID @ "&" @ %request; } if (%payload $= "") { %data = "GET " @ $TribesNext::Community::BaseURL @ $TribesNext::Community::BrowserScript @ %request; %data = %data @ " HTTP/1.1\r\nHost: " @ $TribesNext::Community::Host @ "\r\nUser-Agent: Tribes 2\r\nConnection: close\r\n\r\n"; } else { %data = "POST " @ $TribesNext::Community::BaseURL @ $TribesNext::Community::BrowserScript @ " HTTP/1.1\r\n"; %data = %data @ "Host: " @ $TribesNext::Community::Host @ "\r\nUser-Agent: Tribes 2\r\nConnection: close\r\n"; %data = %data @ %payload; } $BrowserRequestQueue.pushBackLine(%data); if (!$TribesNext::Community::Browser::Active) tn_community_browser_executeNextRequest(); } function tn_community_browser_executeNextRequest() { if ($BrowserRequestQueue.getNumLines() <= 0) return; %data = $BrowserRequestQueue.getLineText(0); $BrowserRequestQueue.popFrontLine(); $TribesNext::Community::Browser::Active = 1; if (isObject(CommunityBrowserInterface)) { CommunityBrowserInterface.disconnect(); } else { new TCPObject(CommunityBrowserInterface); } CommunityBrowserInterface.data = %data; CommunityBrowserInterface.connect($TribesNext::Community::Host @ ":" @ $TribesNext::Community::Port); } // URL escape a string function tn_community_browser_urlescape(%string) { // this function transforms all characters into %xx form, regardless of whether // it is necessary to actually encode them %out = ""; %len = strlen(%string); for (%i = 0; %i < %len; %i++) { %c = getSubStr(%string, %i, 1); %hex = DecToHex(strCmp(%c, "")); while (strlen(%hex) < 2) %hex = "0" @ %hex; %out = %out @ "%" @ %hex; } return %out; } // implementation of API requests function tn_community_browser_request_cert() { error("Browser: Downloading enhanced certificate from community server."); tn_community_browser_processRequest("method=cert"); } // * * * clan data accessor API methods (these do not require authentication) // search for clans by name, returns a list of full-names and clan ID numbers function tn_community_browser_clan_search(%name) { $Browser::CCount = ""; %name = tn_community_browser_urlescape(%name); tn_community_browser_processRequest("method=csearch&a0=" @ %name); } // views clan information for a given clan (e.g. memberships, info, website, recruiting, etc.) function tn_community_browser_clan_view(%id) { tn_community_browser_processRequest("method=cview&a0=" @ %id); } // views clan history (e.g. renamings, retaggings, invitations, kickings, ranking) function tn_community_browser_clan_history(%id) { tn_community_browser_processRequest("method=chist&a0=" @ %id); } // * * * clan management API methods (these require authentication, membership, and sufficient rank) // set the recruiting yes/no flag on the clan (alteration rank) function tn_community_browser_clan_recruiting(%id, %set) { tn_community_browser_processRequest("method=crecr&a0=" @ %id @ "&a1=" @ %set); } // set the clan info field string (alteration rank) function tn_community_browser_clan_info(%id, %info) { %guid = getField($LoginCertificate, 1); %uuid = $TribesNext::Community::UUID; %boundary = "-------------------------"; %rand = getRandom(10000, 99999) @ getRandom(10000, 99999) @ getRandom(10, 9999); %formelem = "Content-Disposition: form-data; name=\""; %payload = "--" @ %boundary @ %rand @ "\r\n"; // GUID element %payload = %payload @ %formelem @ "guid\"\r\n\r\n" @ %guid @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // UUID %payload = %payload @ %formelem @ "uuid\"\r\n\r\n" @ %uuid @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // method %payload = %payload @ %formelem @ "method\"\r\n\r\ncinfo\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // id %payload = %payload @ %formelem @ "a0\"\r\n\r\n" @ %id @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // info %payload = %payload @ %formelem @ "a1\"\r\n\r\n" @ %info @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; %header = "Content-Type: multipart/form-data; boundary=" @ %boundary @ %rand @ "\r\n"; %header = %header @ "Content-Length: " @ strlen(%payload) @ "\r\n\r\n"; tn_community_browser_processRequest("", %header @ %payload); } // set the clan tag, and whether it is prepended or appended to player names (alteration rank) function tn_community_browser_clan_retag(%id, %tag, %append) { %tag = tn_community_browser_urlescape(%tag); tn_community_browser_processRequest("method=ctag&a0=" @ %id @ "&a1=" @ %tag @ "&a2=" @ %append); } // set the clan website string (alteration rank) function tn_community_browser_clan_website(%id, %website) { %website = tn_community_browser_urlescape(%website); tn_community_browser_processRequest("method=csite&a0=" @ %id @ "&a1=" @ %website); } // set the clan name string (alteration rank) function tn_community_browser_clan_rename(%id, %name) { %name = tn_community_browser_urlescape(%name); tn_community_browser_processRequest("method=cname&a0=" @ %id @ "&a1=" @ %name); } // set the filename of the displayed clan picture in the in-game browser (alteration rank) function tn_community_browser_clan_picture(%id, %picture) { %picture = tn_community_browser_urlescape(%picture); tn_community_browser_processRequest("method=cpict&a0=" @ %id @ "&a1=" @ %picture); } // invite another player (by GUID) to this clan (recruitment rank) function tn_community_browser_clan_sendInvite(%id, %invitee) { tn_community_browser_processRequest("method=cinvite&a0=" @ %id @ "&a1=" @ %invitee); } // cancel another player's (by GUID) invitation to this clan (recruitment rank, for self invites -- admin for any invite) function tn_community_browser_clan_retractInvite(%id, %invitee) { tn_community_browser_processRequest("method=cretract&a0=" @ %id @ "&a1=" @ %invitee); } // set a list of outstanding invitations for a clan (recruitment rank) function tn_community_browser_clan_viewInvites(%id) { tn_community_browser_processRequest("method=cinvview&a0=" @ %id); } // change the rank/title of a user in the clan // if invoked on self, this works so long as the member is not of probation rank // if invoked on others, this requires alteration rank -- it can raise others to the user's rank // but, it cannot be used to reduce the rank of someone at the same (or greater) level function tn_community_browser_clan_changeRank(%id, %target, %rank, %title) { %title = tn_community_browser_urlescape(%title); tn_community_browser_processRequest("method=crank&a0=" @ %id @ "&a1=" @ %target @ "&a2=" @ %rank @ "&a3=" @ %title); } // sets authorization status for a clan disband // must be administrative rank, and must be consensus of at least 50% to complete the disband // authorization can be de-set if an administrative rank user changes their mind // if 50% of administrative rank users authorize disband, the disband will happen instantly // when serving this request function tn_community_browser_clan_disband(%id, %set) { tn_community_browser_processRequest("method=cdisb&a0=" @ %id @ "&a1=" @ %set); } // kick a user from the clan // requires alteration rank, but cannot kick users at same (or greater) level function tn_community_browser_clan_kick(%id, %target) { tn_community_browser_processRequest("method=ckick&a0=" @ %id @ "&a1=" @ %target); } // * * * user data accessor API methods (do not require authentication) // search for players by name -- returns full matching names and GUIDs function tn_community_browser_user_search(%name) { %name = tn_community_browser_urlescape(%name); $Browser::PCount = ""; tn_community_browser_processRequest("method=usearch&a0=" @ %name); } // view info for a user -- profile, clan memberships, registration date, etc. function tn_community_browser_user_view(%guid) { tn_community_browser_processRequest("method=uview&a0=" @ %guid); } // view history for a user -- clan creations/joins/leavings/kicks/kicked/disband/renamings function tn_community_browser_user_history(%guid) { tn_community_browser_processRequest("method=uhist&a0=" @ %guid); } // * * * user profile management API methods (require authentication as the player him/herself) // request a name-change, this will be fulfilled it if is unused for raw accounts, unused // in a prior rename browser-side, and deemed acceptable to the existing naming policy function tn_community_browser_user_rename(%name) { %name = tn_community_browser_urlescape(%name); tn_community_browser_processRequest("method=uname&a0=" @ %name); } // sets the active displayed clan to the given ID. By setting -1, it is possible to retain // clan memberships, but not show a tag (this was not possible in the Dynamix browser) function tn_community_browser_user_activeClan(%id) { tn_community_browser_processRequest("method=uclan&a0=" @ %id); } // set profile website link function tn_community_browser_user_website(%website) { %website = tn_community_browser_urlescape(%website); tn_community_browser_processRequest("method=usite&a0=" @ %website); } // set the filename of the displayed user picture in the in-game browser function tn_community_browser_user_picture(%picture) { %picture = tn_community_browser_urlescape(%picture); tn_community_browser_processRequest("method=upict&a0=" @ %picture); } // set info string to given data function tn_community_browser_user_info(%info) { %guid = getField($LoginCertificate, 1); %uuid = $TribesNext::Community::UUID; %boundary = "-------------------------"; %rand = getRandom(10000, 99999) @ getRandom(10000, 99999) @ getRandom(10, 9999); %formelem = "Content-Disposition: form-data; name=\""; %payload = "--" @ %boundary @ %rand @ "\r\n"; // GUID element %payload = %payload @ %formelem @ "guid\"\r\n\r\n" @ %guid @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // UUID %payload = %payload @ %formelem @ "uuid\"\r\n\r\n" @ %uuid @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // method %payload = %payload @ %formelem @ "method\"\r\n\r\nuinfo\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // info %payload = %payload @ %formelem @ "a0\"\r\n\r\n" @ %info @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; %header = "Content-Type: multipart/form-data; boundary=" @ %boundary @ %rand @ "\r\n"; %header = %header @ "Content-Length: " @ strlen(%payload) @ "\r\n\r\n"; tn_community_browser_processRequest("", %header @ %payload); } // accept an invitation to the specified clan ID -- errors if no such invite exists or is invalid // can also produce an error if the user is in the maximum number of clans (but will not burn the // invite in the process -- can retry after leaving an existing clan) function tn_community_browser_user_acceptInvite(%id) { tn_community_browser_processRequest("method=uaccept&a0=" @ %id); } // ditto to above, but rejects the invite instead function tn_community_browser_user_rejectInvite(%id) { tn_community_browser_processRequest("method=ureject&a0=" @ %id); } // leave a clan -- this will always succeed provided the user was a member of it. // if the user was actively using this clan's tag, and they are still a member of at least one // clan, the active tag will be set to the clan that the user has been a member of the longest function tn_community_browser_user_leaveClan(%id) { tn_community_browser_processRequest("method=uleave&a0=" @ %id); } // create a clan -- specify the tag/name/info function tn_community_browser_user_createClan(%tag, %append, %name, %info, %recruiting) { // do as POST since the contents can be longer than URI length limits %guid = getField($LoginCertificate, 1); %uuid = $TribesNext::Community::UUID; %boundary = "-------------------------"; %rand = getRandom(10000, 99999) @ getRandom(10000, 99999) @ getRandom(10, 9999); %formelem = "Content-Disposition: form-data; name=\""; %payload = "--" @ %boundary @ %rand @ "\r\n"; // GUID element %payload = %payload @ %formelem @ "guid\"\r\n\r\n" @ %guid @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // UUID %payload = %payload @ %formelem @ "uuid\"\r\n\r\n" @ %uuid @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // method %payload = %payload @ %formelem @ "method\"\r\n\r\ncreate\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // tag %payload = %payload @ %formelem @ "a0\"\r\n\r\n" @ %tag @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // append %payload = %payload @ %formelem @ "a1\"\r\n\r\n" @ %append @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // name %payload = %payload @ %formelem @ "a2\"\r\n\r\n" @ %name @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // info %payload = %payload @ %formelem @ "a3\"\r\n\r\n" @ %info @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; // append %payload = %payload @ %formelem @ "a4\"\r\n\r\n" @ %recruiting @ "\r\n"; %payload = %payload @ "--" @ %boundary @ %rand @ "\r\n"; %header = "Content-Type: multipart/form-data; boundary=" @ %boundary @ %rand @ "\r\n"; %header = %header @ "Content-Length: " @ strlen(%payload) @ "\r\n\r\n"; tn_community_browser_processRequest("", %header @ %payload); } schedule(3000, 0, tn_community_Browser_request_cert);