Ковыряем Шарарам — 1 часть

от автора

Привет Хабр! Я думаю многие здесь знают про игру «Шарарам». А если не знаете то лучше не знать узнаете.

Я решил сделать персонально свой сервер этой игры.

Не смотря на то что возможно скорее всего для аудитории Хабра эта статья покажется банальной, но мне тупо негде это выложить на общее обозрение.

Инструменты

  • Любой браузер с инспектором
  • Adobe Flash Media Server (старую версию из 2009 так как новые не умеют в флэш. Спокойно ищется на всяких торрент трекерах) или Red5
  • Знание ECMAScript
  • Декомпиль флешек, я выбрал JPEXS Free Flash Decompiler потому что бесплатно
  • Adobe Flash Content Debugger

Логотип

Спасибо за логотип EarthShaker’у

Первые шаги

  1. Регаемся в игре
  2. Смотрим в инспекторе какой мусор нам шлет HTTP сервер
  3. Находим /async/ServerAction и радостно кликаем по добыче
  4. С удивлением обнаруживаем такую картину. В CDATA какая то муть шифрованная (благодаря друзьям-криптоманьякам выяснилось что это RC4)

Поиски ключа

Вроде бы все уже хорошо, но у нас нет ключа. Поэтому скачиваем base.swf из хтмл страницы игры и открываем его на обследование в декомпиль. Благодаря наличию Адоб Флэша я попробовал данный кусок кода

trace(_root);

который вернул _level0 в лог. Защита от школоанонимусов??

Угадываем что у Шарарама в качестве игрового сервера

Это было сделать не сложно. Всего лишь гуляем по исходникам и обнаруживаем файл FmsAPI. Гуглим че за FMS и…

это к сожалению не то, поэтому гугланём чё-то посерьезнее

Бинго, но я все еще сомневался, поэтому идем в Википедию.

Ну это уже серьезный аргумент. Можно уже 100% утверждать что это оно.

Бороздил гугл, оказалось что еще есть Red5 (да, я пытался сделать и на нем но чето дело не пошло).

Делаем сервак

Для начала напишем серверную сторону.

Мой php-говнокод для /async/* выглядит так (обьяснения в комментах в коде)

<?php // просто для эстетичности header("Content-type: text/xml"); // включаем rc4 и остальные мелочи include "crypto.php"; include "utils.php"; include "settings.php";  // смотрим че нас просят switch ($_GET["action"]) {    // инфа о юзере     case 'ServerAction':      // данные которые мы зашифруем и спакуем в CDATA-ноды      // конфиг (впринципе можно и не редактировать)         $config = '<config><item Id="1" Parameter="AccessRoleFlags" Value="0" Type="number" /><item Id="3" Parameter="IsPreloaderFast" Value="0" Type="bool" /><item Id="4" Parameter="InitialVolumeValue" Value="30" Type="number" /><item Id="6" Parameter="IsPreloaderEnabled" Value="1" Type="bool" /><item Id="7" Parameter="IsStartupHomeLocation" Value="0" Type="bool" /><item Id="8" Parameter="SwfVersion" Value="" Type="string" /><item Id="9" Parameter="SynchronizeAvatarRotation" Value="1" Type="bool" /><item Id="10" Parameter="StatisticsSendInterval" Value="0" Type="number" /><item Id="12" Parameter="LanguageId" Value="1" Type="number" /><item Id="13" Parameter="SnId" Value="1" Type="number" /><item Id="14" Parameter="IsInternational" Value="0" Type="bool" /><item Id="15" Parameter="AutoServerSelectionAllowed" Value="1" Type="bool" /><item Id="16" Parameter="DaysToFullSoil" Value="28" Type="number" /><item Id="17" Parameter="DaysToHalfSoil" Value="14" Type="number" /><item Id="18" Parameter="CurrentQuest" Value="421" Type="number" /><item Id="20" Parameter="TypeWeapon" Value="3" Type="number" /><item Id="21" Parameter="SkipTutorial" Value="1" Type="bool" /><item Id="23" Parameter="CurrentQuestGroup" Value="6161" Type="string" /><item Id="24" Parameter="IsNewRegistration" Value="1" Type="bool" /><item Id="25" Parameter="IsMotivatingAdsOn" Value="0" Type="bool" /></config>';                 // cписок серверов. можно либо вынести инфу о серве в другой файл        // или редачить её тут       // особый смысл имеют TRId (название сервера),  RTMPUrl (ссылка на сервер) и в принципе все. Остальное чисто косметическое.             $serversList = '<servers><item Id="1" TRId="'.$gameServer_name.'" RId="5" RTMPUrl="rtmp://'.$gameServer_ip.':'.$gameServer_port.'/'.$gameServer_appname.'" Load="46" QuestLocationLoad="0" FriendsCount="0" ClubsCount="4" Weight="5.1" /></servers>';                   // айди, hwid (wtf??), тикет (для фронтэндеров - это типа JWT) и RoleFlags это типа кто юзер (картный, безкартный, модер, админ, etc)         $userData = '<user UserId="1" hwId="'. getGUID() .'" ticketId="'. getGUID() .'" RoleFlags="2" />';         // тут тоже особо ничего редачить не надо         $system = '<system ServerDate="'.date('Y-m-d H:i:s').'" RPath="fs/3p897j5lf4e0j.swf" RVersion="56" />';         // всякая инфа о юзере и наши CData которые мы шифруем прямо там         echo '<?xml version="1.0" encoding="utf-8"?> <response>     <promotion>         <i MRId="20106" State="1" />         <i MRId="30896" State="7" />     </promotion>     <promotion_banner>         <i MRId="30896" />     </promotion_banner>     <promotion_whats_new>         <i Id="386" TypeId="1" MRId="20143" />         <i Id="611" TypeId="2" MRId="27179" />         <i Id="784" TypeId="2" MRId="30841" />         <i Id="785" TypeId="2" MRId="30895" />         <i Id="786" TypeId="2" MRId="30897" />     </promotion_whats_new>     <preloader>         <i MRId="30894" ShowTime="20;00" />     </preloader>     <sn_status IsBinded="0" />     <phone>         <messages/>     </phone>     <user_name Value="test" />     <postcard>         <messages/>     </postcard>     <licence_promotion>         <item Id="1" GroupId="0" OrderId="0" MRId="14763" />         <item Id="2" GroupId="0" OrderId="1" MRId="14764" />         <item Id="3" GroupId="0" OrderId="2" MRId="14765" />         <item Id="4" GroupId="1" OrderId="0" MRId="14766" />         <item Id="5" GroupId="1" OrderId="1" MRId="14767" />         <item Id="6" GroupId="1" OrderId="2" MRId="14768" />         <item Id="7" GroupId="2" OrderId="0" MRId="20597" />         <item Id="8" GroupId="2" OrderId="1" MRId="20598" />         <item Id="9" GroupId="2" OrderId="2" MRId="20599" />     </licence_promotion>     <flags EntranceCount="2600" />     <tutorial>         <item Id="-1" State="1" />         <item Id="1" State="1" />         <item Id="2" State="1" />         <item Id="3" State="1" />         <item Id="4" State="1" />         <item Id="5" State="1" />     </tutorial>     <miniquest>         <i Id="148515433" MiniquestId="90004" IsPostponed="0" StartDate="2018-06-06T18:58:28.113">             <i Id="298265808" TaskId="900041" IsFinished="0" Counter="3" />             <i Id="298265809" TaskId="900042" IsFinished="0" Counter="0" />             <i Id="298265810" TaskId="900043" IsFinished="1" Counter="0" />         </i>     </miniquest>     <grants ReceivingCount="0" />     <requests ReceivingCount="0" />     <cdata value="'. encrypt($config) .'" />     <cdata value="'. encrypt($system) .'" />     <cdata value="'. encrypt($userData) .'" />     <cdata value="'. encrypt($serversList) .'" /> </response>';         break;   // простой php-пинг     case 'Ping':         echo '<response isPong="true" />';         break;     // add more below     default:         echo "<!-- there's nothing -->";         break; } ?> 

В файле settings.php это

<?php  // php settings error_reporting(E_ERROR | E_PARSE);  // server settings $gameServer_ip = "127.0.0.1"; $gameServer_port = 1935; $gameServer_name = 202; // check http://sharaball.ru/fs/3p897j5lf4e0j.swf for strings you can use (also, you can edit this file in any SWF editor) $gameServer_appname = "shararam"; // название инстанса на стороне fms  ?> 

В файле utils.php это

<?php  // http://guid.us/GUID/PHP function getGUID(){         $charid = strtoupper(md5(uniqid(rand(), true)));         $hyphen = chr(45);// "-"         $uuid = substr($charid, 0, 8).$hyphen             .substr($charid, 8, 4).$hyphen             .substr($charid,12, 4).$hyphen             .substr($charid,16, 4).$hyphen             .substr($charid,20,12);         return $uuid; } ?> 

В crypto.php это

 <?php  	 function rc4( $key_str, $data_str ) {       // convert input string(s) to array(s)       $key = array();       $data = array();       for ( $i = 0; $i < strlen($key_str); $i++ ) {          $key[] = ord($key_str{$i});       }       for ( $i = 0; $i < strlen($data_str); $i++ ) {          $data[] = ord($data_str{$i});       }      // prepare key       $state = array( 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,                       16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,                       32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,                       48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,                       64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,                       80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,                       96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,                       112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,                       128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,                       144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,                       160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,                       176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,                       192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,                       208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,                       224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,                       240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 );       $len = count($key);       $index1 = $index2 = 0;       for( $counter = 0; $counter < 256; $counter++ ){          $index2   = ( $key[$index1] + $state[$counter] + $index2 ) % 256;          $tmp = $state[$counter];          $state[$counter] = $state[$index2];          $state[$index2] = $tmp;          $index1 = ($index1 + 1) % $len;       }       // rc4       $len = count($data);       $x = $y = 0;       for ($counter = 0; $counter < $len; $counter++) {          $x = ($x + 1) % 256;          $y = ($state[$x] + $y) % 256;          $tmp = $state[$x];          $state[$x] = $state[$y];          $state[$y] = $tmp;          $data[$counter] ^= $state[($state[$x] + $state[$y]) % 256];       }       // convert output back to a string       $data_str = "";       for ( $i = 0; $i < $len; $i++ ) {          $data_str .= chr($data[$i]);       }       return $data_str;    }  function encrypt($str){ 	return bin2hex(rc4("_level0", $str)); } ?> 

Мой htaccess

Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteRule ^async/(.*) asyncController.php?action=$1

Код сервера

Это уж слишком старый образец, там уже было шифрование в rc4 на сервере, я новый потерял поэтому придется показать вам этот ужас.

H2CA разбивает строку в массив чтобы сервер её скушал, такова обсфукация

 /* * RolyPolyWorld Server Code * by Semen Elkin, 2018 */  function H2CA(hex) {  var _loc3_ = [];  var _loc1_ = hex.substr(0, 2) != "0x" ? 0 : 2;  while (_loc1_ < hex.length) {   _loc3_.push(parseInt(hex.substr(_loc1_, 2), 16));   _loc1_ = _loc1_ + 2;  }  return _loc3_; } Client.prototype._LS = function(descriptor, startPoint, startState) {  return ""; }  Client.prototype._NSF = function() {  return ""; }  Client.prototype.$ = function(CMD, srvName, _unknown, __unknown, callback) {  trace("CMD: " + CMD);  if (CMD == "_I") {   // return UserInitData   return [H2CA("e4ba5848485429d25723c62654510684f67e7b2cffb0debd608de7bca09d0b10f8a0c511b52c5fb57adc0321b8edef0b0cde086422a751a8604104a1d6b5bd050e19ac989ec6f44ff7f6998af46ffac822fe0673c54823fd8b1744f6b09907cb69e703cc4941ca27c0783ea6085f35eaf0614ba95507eeca1e2662d40c43857b0fa1cc045851c6a3d8e81cac73468c7ed174731c50b2141576a808f7a4cb7026e2253ebff413b1a3bc5907c9a13783dd8cdeccf636c48720cea4cf3040eb339a4329ca4c731218719e9366d6ce24ec2fee9f67ca586bdf0c6764051deb33972c640a6775bb206c707003e22e078ef18e77faf6e84423332f4212a2ae12ba56a537f05fac4fa7598487dd138396db4db00a85c28a533d3a2645f00fa2a0b1c4ffdd5b5d015c935909e23950a63ae37f2d1345d86296470633f47d8b9c6c423a2d429e6b06b596b4c914cf12b850640aa91f51d456994dc57c2a4cb32116b5b4c4a1d5768eecfa2e158d4c42f64294793c0da42bc5c949ae7f0501b488906bb4609c0443c7c8d3b675605762aec6dcda5b813f3abcf8ec8706c137889c0809bfd90c1e191aacc84d35317b2418e6cfc8429d1f0b0532b0e4ff0e1c57f8a46c64f806cc8b1509691b0266b921f61d670a73480c4e83935438e9f1a84708f755ab3e66e78a6ae3d2a88ee3e8083a994e6212162d388a6df2f100e11ea5d2367b8c016804790cbbb4bcadd1f415dddd8814672a235a6a7236521010596a0abe0e8d8ba9930e4c85c103d8dc12439482c6bde7d215b2f43dd20a3862f191fb134d8a590dda31ddbe4575a197db52170715c6e302038554c953c8a6875a26240452c75e19ba0fdac1c6894a134bb998011fd88b1c175face045a7d192159d84c1d848996a367055c0b5b5efad7827d3dc3e9dd3c361cbc59c915089ed79768f9e1cf6ad60acbd7e418e6c0dfb63389135745bcdb45fb1c83b6471223f0e00f09203f6a580ae863c2c7c1ecd7f8117daa623868e5f040e74ce8c409e2d26ae0b51f8f4c1dfb15114098aa3f7f38703d53d1654d393ae82d6b65a19a0c782373789c9b6f55bfddd224e977bcf8b15a810f5d0888380d4543361c7daaf12f3cdc02f098f044a04c47996439820d82a22dc8439e0a0470cf4989dae13a827fb946ef29271ead58ae31934ba490492f4d4f97a440c3b1983e9eb431050f1e14ead8ac032973ffad1a257cd652976ec9d8a4c8c480be6b254ad017d6e8d25c97edd6723880a50f94860fbc0b5bbd6b9234971a251fd351d17bc12ebf71b47f72c2c393e2d79be2779d27612522942a5629c453f6063c4905d5b64749c1690dd2d918bf7845cba8ff3d9b0726dd724641926f6493a1438af12f1263cf8e9781ef5ac8e9ac4ce63db2e8b2761431d0fdc1f70f8b75908f597697aeaef3849e2b525681d13d493707e45f40f07461cea503ba038ec76981a6abf733bea79eff7121b97515943196417660fb854e43fba68d2bfbb5fc5ecf66f2cfffa9c62dd60731d4f92be76d63da3f4f19ad1a7b41ff7bdcf4c7e6e5629c475b0fed66768681f76d5bab4287c355eb951953a3795d381afed2aed639782fda5377c23d67d90c3f6f5fcea5c41a5567082c32cfb4886fe63aec9a6373ce924072fab5ff340b415470e8d973da687319b9259ccf0ebd78b2c2d05453463f7efb8278188b5a9e6fef9b9c26051af9295521015ec19a8997cd76903e65eca7a2538ff2c4c07f6df5e951485242f171f07bc72f99a69fcd3119dabfaf3e4be78264a32d0f82d2de290ec62b4ed5b9d1db59d42e9ab41bad695ff25a47271cae2ca52013743cf8b72c3315896e65a0f8158ac9b92a010002d4b846d0c984274e65be446e237397633929bd1fdfceeca06deeaa33f6097b8a203042ff8a72d342061487e2a335a688d28334b87313709bd0cc0f99d6dcc961f9f4d628d812a2bb4478263817a714cf9fd50423f28c70c1ed03222764630faf695da3936aa384315b63d2b9b44f1c911df43fba1f8353787eee6ab2be85ae010c2cfd60ce3c8522cdc32df85202abafa4925bea3bf2c5766dfb0f56e0e882847d57ff9e4c9df52b8652319a3008e22becc5a162fb5e90ca62f961f42e342003d0ca98d48eaafa9a698be8734e42db75befc380ff67cdecdc8297315bda07f1c9eebda90ecc128f01e7187eb14971541da50b7878e897bea0ac8ebefd3a4115b3e21a0bc07dd92f5050fca020e63a3c8a9d123327fb8d0200f4d85892cc906bc1f4865e8c75d0b68a43f54e0204d3a18886e125a478a6da9129e5f79f4f4bbb4f4385d84aa3392d752c44dadbdca771a8a8202a22631e02559b7deb2e8f8aaa52eef394")];  } else if (CMD == "_UFG") {   // Friends list get   return ""; quests  } else if (CMD == "_UFR") {   // Friends requests get   return "";  } else if (CMD == "_CM") {   // GetClubMap   return "<clubmap />";  } else if (CMD == "_SNFP") {   // GetFriendPanelData   return '<root><L4><i UserId="3490071" UserName="56" AvatarUrl="https://sharaball.ru/shimg?u275AF9B0E0FB47AE" IsOnline="true" Level="59" RoleFlags="2" IsHomeLocked="true" /><i UserId="22033" UserName="UberSoldat" AvatarUrl="https://sharaballru/shimg?u7705945283620CEC" IsOnline="true" Level="50" RoleFlags="2" IsHomeLocked="false" /><i UserId="26514836" UserName="953" AvatarUrl="https://sharaballru/shimg?u70A0C3FFDC2AE686" IsOnline="true" Level="44" RoleFlags="0" IsHomeLocked="true" /><i UserId="4294784" UserName="-22" AvatarUrl="https://sharaballru/shimg?uA0F2D2940A2C0680" IsOnline="false" Level="66" RoleFlags="0" IsHomeLocked="true" /><i UserId="6514777" UserName=" 7" AvatarUrl="https://sharaballru/shimg?u7633EEBAAC8D8750" IsOnline="false" Level="62" RoleFlags="0" IsHomeLocked="true" /><i UserId="15918373" UserName="Gamer9999" AvatarUrl="https://sharaballru/shimg?u3F6E105179A94CF9" IsOnline="false" Level="60" RoleFlags="2" IsHomeLocked="false" /><i UserId="5499397" UserName="2014" AvatarUrl="https://sharaballru/shimg?uFAA76A3F45E04650" IsOnline="false" Level="59" RoleFlags="0" IsHomeLocked="true" /><i UserId="6765542" UserName="2399" AvatarUrl="https://sharaballru/shimg?uBC8AF14DC9568867" IsOnline="false" Level="57" RoleFlags="0" IsHomeLocked="true" /><i UserId="6091024" UserName="60" AvatarUrl="https://sharaballru/shimg?u6254ABCD6C72BA40" IsOnline="false" Level="55" RoleFlags="0" IsHomeLocked="true" /><i UserId="5335890" UserName="992" AvatarUrl="https://sharaballru/shimg?uB51CD240A8D9A6F8" IsOnline="false" Level="54" RoleFlags="0" IsHomeLocked="true" /><i UserId="7403986" UserName="" AvatarUrl="https://sharaballru/shimg?uAFC6BB4C6CB5523B" IsOnline="false" Level="54" RoleFlags="0" IsHomeLocked="true" /><i UserId="3711098" UserName="12345x" AvatarUrl="https://sharaballru/shimg?u30D03C19372FD998" IsOnline="false" Level="53" RoleFlags="0" IsHomeLocked="true" /><i UserId="2477499" UserName="" AvatarUrl="https://sharaballru/shimg?u2FDDD1060A5F77A4" IsOnline="false" Level="52" RoleFlags="0" IsHomeLocked="true" /><i UserId="6881717" UserName="" AvatarUrl="https://sharaballru/shimg?uA1B439427D7B3055" IsOnline="false" Level="52" RoleFlags="0" IsHomeLocked="true" /><i UserId="3747929" UserName="329" AvatarUrl="https://sharaballru/shimg?uC60A8606BA6F5F20" IsOnline="false" Level="51" RoleFlags="0" IsHomeLocked="true" /><i UserId="491914" UserName="votetu" AvatarUrl="https://sharaballru/shimg?uF843320FF79B6387" IsOnline="false" Level="48" RoleFlags="0" IsHomeLocked="true" /><i UserId="5143339" UserName=" 908" AvatarUrl="https://sharaballru/shimg?u2521238E5E881E10" IsOnline="false" Level="48" RoleFlags="0" IsHomeLocked="true" /><i UserId="7164879" UserName="SuperKohka" AvatarUrl="https://sharaballru/shimg?uDF898434F4FA678A" IsOnline="false" Level="48" RoleFlags="0" IsHomeLocked="true" /><i UserId="21200791" UserName="Alsoa" AvatarUrl="https://sharaballru/shimg?uA418D0DB845DEDF5" IsOnline="false" Level="48" RoleFlags="2" IsHomeLocked="false" /><i UserId="28287949" UserName="630" AvatarUrl="https://sharaballru/shimg?uF02BE2EAF00206CF" IsOnline="false" Level="48" RoleFlags="2" IsHomeLocked="true" /><i UserId="6858621" UserName="200125" AvatarUrl="https://sharaballru/shimg?u02E14C376A340686" IsOnline="false" Level="46" RoleFlags="0" IsHomeLocked="true" /><i UserId="5116798" UserName=" 2" AvatarUrl="https://sharaballru/shimg?uBD09B4CE3AE8832A" IsOnline="false" Level="43" RoleFlags="0" IsHomeLocked="true" /><i UserId="6858399" UserName="wosso" AvatarUrl="https://sharaballru/shimg?uD2CABA24168A42DD" IsOnline="false" Level="43" RoleFlags="0" IsHomeLocked="true" /></L4></root>';  } else if (CMD == "_D") {   // UpdateUserData   return {    callback_uid: callback   };  } else if (CMD == "_LG") {   // GetLocation   return '<location ID="28" IsHome="0" IsClub="0" IsLocked="0" IsVisaAccessPermitted="1" MediaResourceID="30644" x="550.0" y="380.0" Name="test">   <options>     <Constraints>       <item ID="0" Type="Q" QuestId="390" StepId="23" StateCode="1" Equally="1" Value="2" RoomState="0" />    </Constraints>  </options>  <object ID="28002" AObjectTypeId="2" AObjectId="61" AObjectRefId="25" MediaResourceID="30648" x="634.0" y="197.0" />   <object ID="28003" AObjectTypeId="2" AObjectId="70" AObjectRefId="19" MediaResourceID.="30645" x="674.0" y="227.0" />   <object ID="28004" AObjectTypeId="2" AObjectId="71" AObjectRefId="30" MediaResourceID="30647" x=".135.0" y="153.0" />   <object ID="28010" AObjectTypeId="2" AObjectId="532" AObjectRefId="54" MediaResourceID="3587" x="130.0" y="33.0.0">     <options>       <override AObjectTypeId="18" />       <conditions>        <User IsSecretAgent="1" />      </conditions>     </options>  </object>   <object ID="28733" AObjectTypeId="2" AObjectId="733" AObjectRefId="6" MediaResourceID="30646" x="490.0" y="120.0" /> </location>';  } else if (CMD == "_UOG") {   if ( __unknown == "whats_new_data"){     return "1|2|3";   } else if ( __unknown == "pet_battle_news"){     return "1|2|3";   } else {     trace("_UOG OPTION " + __unknown);   }  } else if (CMD == "_UOS") {   // SetUserOption  } else if (CMD == "_GOGI") {   // GetGroupObjectInfo   return '<group_object UOGId="-6163" ObjectGroupId="6163" ObjectGroupTypeId="101" ControllerType="4" Stored="0" ContorollerMRId="30781"> <item Id="6163001" AObjectId="828" AObjectTypeId="2" AObjectRefId="27" MediaResourceID="30775" LocationId="19" X="284" Y="136" IsActive="1" IsInterractable="1" /> <item Id="6163002" AObjectId="3193" AObjectTypeId="50" MediaResourceID="30373" LocationId="27" X="295" Y="332" Frame="F$0" IsActive="1" IsInterractable="1" /> <item Id="6163003" AObjectId="3194" AObjectTypeId="50" MediaResourceID="30774" LocationId="85" X="475" Y="303" Frame="F$0" IsActive="1" IsInterractable="1" /> <item Id="6163004" AObjectId="3195" AObjectTypeId="50" MediaResourceID="30776" LocationId="85" X="116" Y="123" Frame="F$0" IsActive="1" IsInterractable="1" /> <item Id="6163005" AObjectId="3196" AObjectTypeId="50" MediaResourceID="30777" LocationId="85" X="282" Y="100" Frame="F$0" IsActive="1" IsInterractable="1" /> <item Id="6163006" AObjectId="3197" AObjectTypeId="50" MediaResourceID="30778" LocationId="85" X="453" Y="160" Frame="F$0" IsActive="1" IsInterractable="1" /> </group_object>';  } else if (CMD == "_ULNS") {   // SetUserLastNewspaper   return "asd";  } else if (CMD == "_DA") {   return '<kek> <ID>1</ID> <IsSecretAgent>1</IsSecretAgent> <IsMember>1</IsMember> <IsPresent>1</IsPresent> <IsActive>1</IsActive> <Units>5</Units> <MessageID>2</MessageID> </kek >';  } else {   trace("Unknown command: " + CMD);  } } Client.prototype._SCD = function(callback) { // get server time  return 123; }   application.onConnect = function(client) {  this.acceptConnection(client); } 

XML который мы шлем серверу выглядит так. Ничего особенного.

<userInitData>     <user Id="1" RoleFlags="2" Level="100" PositiveEnergy="11" IsMinorSecretAgent="1" MagicTickets="999" UsualTickets="999" /> </userInitData> <account>     <PhoneCardBalance>123</PhoneCardBalance>     <WeaponsCount>2</WeaponsCount>     <OxigenUnits>5</OxigenUnits> </account> <secret_agent>     <StartDate>000</StartDate>     <Number>123</Number>     <Interval>2</Interval> </secret_agent> <user_avatar></user_avatar> <smiles>     <Id>1</Id> </smiles> <pets /> <pet_battle_places></pet_battle_places> <user_magic_abilities>     <Id>1</Id>     <ExpirationDate>DATE</ExpirationDate>     <IsLimited>false</IsLimited> </user_magic_abilities> <user_phone>     <BufferSize>1</BufferSize>     <SkinMediaResourceID>112</SkinMediaResourceID>     <PhoneId>2</PhoneId>     <Balance>999</Balance> </user_phone> <quests>     <Id>148515433</Id>     <StateCode>90004</StateCode>     <UpdateDate>2018-06-06T18:58:28.113</UpdateDate>     <RecordDate>2018-06-06T18:58:28.113</RecordDate>     <StartDate>2018-06-06T18:58:28.113</StartDate>     <LastFinishedStep>0</LastFinishedStep>     <GamesScore>0</GamesScore>     <GamesCount>0</GamesCount>     <TeleportId>0</TeleportId>     <MRId>1</MRId>     <IconMRId>5</IconMRId>     <EndDate></EndDate> </quests> <questgamedata></questgamedata> <magiclessons></magiclessons> <ufoquestinfo></ufoquestinfo> <res_objects></res_objects> <actions></actions> <spend_cones></spend_cones> <options></options> <mission_dobject></mission_dobject> <smiles></smiles> <positive_energy></positive_energy> <giftbox_digger></giftbox_digger> <object_groups></object_groups> <game_award_pack></game_award_pack> <sn_og_status></sn_og_status> <notices></notices> <controller></controller> <bonus_day></bonus_day> <informer_bonus></informer_bonus> <nift></nift> <sharagent></sharagent> <stpack></stpack> <yavideo></yavideo> 

Встретимся в следующем эпизоде!


ссылка на оригинал статьи https://habr.com/post/426655/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *