Rumah > php教程 > php手册 > PHP的分析文件程序,要翻译成C#

PHP的分析文件程序,要翻译成C#

WBOY
Lepaskan: 2016-06-06 19:46:07
asal
1197 orang telah melayarinya

?php /* ************************************************************************* * AOC Recorded Games Analyzer * --------------------------- * begin : Monday, December 3, 2007 * copyright : (c) 2007-2008 biegleux * email : biegleux(at)gma

/* *************************************************************************
 *                       AOC Recorded Games Analyzer
 *                       ---------------------------
 *    begin            : Monday, December 3, 2007
 *    copyright        : (c) 2007-2008 biegleux
 *    email            : biegleux(at)gmail(dot)com
 *
 *    recAnalyst v0.9.1 2008/11/07
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program.  If not, see http://www.gnu.org/licenses/.
 *
 *    Thanks to bari [aocai-lj(at)infoseek.jp] for sharing mgx file format
 *    description.
 *
 *    Note: Code is not fully optimized, any suggestions appreciated.
 ************************************************************************* */
/**
 * Defines RecAnalyst class.
 *
 * @package recAnalyst
 * @version $Id: recAnalyst.class.php 5 2008-11-08 15:04:10Z biegleux $
 * @author biegleux
 * @copyright copyright (c) 2008 biegleux
 * @license http://www.opensource.org/licenses/gpl-3.0.html GNU General Public License version 3 (GPLv3)
 * @link http://recanalyst.sourceforge.net/
 * @filesource
 * @todo rar extension support
 * @todo test for server zlib/zip extension support
 * @todo implement method/member for holding analyze time
 */

// uncomment following line if we want to debug
//define ('RA__DEBUG', true);
if (defined ('RA__DEBUG'))
{
 error_reporting (E_ALL | E_STRICT);
}

/**#@+
 *
 * @ignore
 */
// error codes
define ('RA__NO_ERROR',      0x00);
define ('RA__FILE_NOT_SPECIFIED',   0x01);
define ('RA__FORMAT_NOT_SUPPORTED',   0x02);
define ('RA__UNABLE_TO_OPEN_ZIP_ARCHIVE', 0x03);
define ('RA__ZIP_ARCHIVE_EMPTY',   0x04);
define ('RA__OLD_FORMAT_VER',    0x05);
define ('RA__EMPTY_HEADER_STREAM',   0x06);
define ('RA__ERROR_IN_UNCOMPRESSED_STREAM', 0x07);
define ('RA__RAR_EXTENSION_NOT_INSTALLED', 0x08);
define ('RA__RAR_NOT_IMPLEMENTED',   0x09);
define ('RA__MORE_FILES_PER_ARCHIVE',  0x0A);
define ('RA__NO_RECGAME_FOUND',    0x0B);
define ('RA__ERROR_IN_HEADER_STREAM',  0x0C);

require_once ('recAnalyst.config.php');
require_once ('recAnalyst.consts.php');
require_once ('gameSettings.class.php');
require_once ('player.class.php');
require_once ('parentList.class.php');
require_once ('playerList.class.php');
require_once ('team.class.php');
require_once ('teamList.class.php');
/**#@-*/

/**
 * RecAnalyst class
 *
 * RecAnalyst implements analyzing of recorded games.
 *
 * @package recAnalyst
 */
class RecAnalyst
{
 const mgxExt = '.mgx';
 const rarExt = '.rar';
 const zipExt = '.zip';

 /**
  * Internal storage for new members.
  *
  * @var array
  */
 private $data;

 /**
  * Input filename we wish to analyze.
  *
  * @var string
  */
 public $fileName;

 /**
  * Internal stream containing header information.
  *
  * @var string
  */
 private $headerStream;

 /**
  * Internal stream containing body information.
  *
  * @var string
  */
 private $bodyStream;

 /**
  * Holds a code of the recent error.
  *
  * @var int
  */
 private $lastError;

 /**
  * An array containing map data.
  *
  * $var array
  */
 private $mapData;

 /**
  * Map width.
  *
  * @var int
  */
 private $mapWidth;

 /**
  * Map height.
  *
  * @var int
  */
 private $mapHeight;

 /**
  * Game settings information.
  *
  * @var GameSettings
  */
 public $gameSettings;

 /**
  * List of players in the game.
  *
  * @var PlayerList
  */
 public $playerList;

 /**
  * List of teams in the game.
  *
  * @var TeamList
  */
 public $teams;

 /**
  * An array containing pre-game chat.
  *
  * @var array
  */
 public $pregameChat;

 /**
  * An array containing in-game chat.
  *
  * @var array
  */
 public $ingameChat;

 /**
  * An associative array containing "unit_type_id - unit_num" pairs.
  *
  * @var array
  */
 public $units;

 /**
  * An associative multi-dimesional array containing "building_type_id - building_num" pairs for each player.
  *
  * @var array
  */
 public $buildings;

 /**
  * An associative multi-dimesional array containing information about trading.
  *
  * @var array
  */
 public $trading;

 /**
  * Constructor.
  *
  */
 public function __construct ()
 {
  $this->data = array ();
  $this->fileName = '';
  $this->headerStream = '';
  $this->bodyStream = '';
  $this->lastError = RA__NO_ERROR;
  $this->gameSettings = new GameSettings ();
  $this->playerList = new PlayerList ();
  $this->teams = new TeamList ();
  $this->pregameChat = array ();
  $this->ingameChat = array ();
  $this->units = array ();
  $this->buildings = array ();
  $this->mapData = array ();
  $this->mapWidth = $this->mapHeight = 0;
  $this->trading = array ();
 }

 /**
  * Destructor.
  *
  */
 public function __destruct ()
 {
 }

 /**
  * Callback method for setting a property.
  *
  * @param mixed $nm
  * @param mixed $val
  */
 public function __set ($nm, $val)
 {
  $this->data[$nm] = $val;
 }

 /**
  * Callback method for getting a property.
  *
  * @param mixed $nm
  */
 public function __get ($nm)
 {
  return $this->data[$nm];
 }

 /**
  * Returns code of the recent error.
  *
  * @return int
  */
 public function getLastError ()
 {
  return $this->lastError;
 }

 /**
  * Represents the error code as a string information.
  *
  * @param int $errCode error code
  * @static
  * @return string error string
  */
 public static function errorCodeToString ($errCode)
 {
  switch ($errCode)
  {
   case RA__NO_ERROR:
    $errString = 'No error occured.';
    break;
   case RA__FILE_NOT_SPECIFIED:
    $errString = 'No file has been specified for analyzing.';
    break;
   case RA__FORMAT_NOT_SUPPORTED:
    $errString = 'File format is not supported.';
    break;
   case RA__UNABLE_TO_OPEN_ZIP_ARCHIVE:
    $errString = 'Unable to open zip archive.';
    break;
   case RA__ZIP_ARCHIVE_EMPTY:
    $errString = 'Empty zip archive.';
    break;
   case RA__MORE_FILES_PER_ARCHIVE:
    $errString = 'Only one file per archive is supported for analyzing.';
    break;
   case RA__OLD_FORMAT_VER:
    $errString = 'Old mgx file format.';
    break;
   case RA__EMPTY_HEADER_STREAM:
    $errString = 'Empty header stream.';
    break;
   case RA__ERROR_IN_UNCOMPRESSED_STREAM:
    $errString = 'Error in uncompressed stream.';
    break;
   case RA__RAR_EXTENSION_NOT_INSTALLED:
    $errString = 'Rar extension is not installed on server.';
    break;
   case RA__RAR_NOT_IMPLEMENTED:
    $errString = 'Support for rar archives is not implemented.';
    break;
   case RA__NO_RECGAME_FOUND:
    $errString = 'No recorded game has been found in archive.';
    break;
   case RA__ERROR_IN_HEADER_STREAM:
    $errString = 'Error in header stream.';
    break;
   default:
    $errString = '';
    break;
  }
  return ($errString);
 }

 /**
  * Converts game's time to string representation.
  *
  * @param int $time game time
  * @param string $format desired string format
  * @static
  * @return string time in formatted string
  */
 public static function gameTimeToString ($time, $format = '%02d:%02d:%02d')
 {
  if ($time == 0)
   return '-';

  $hour   =  (int)($time / 1000 / 3600);
  $minute = ((int)($time / 1000 / 60)) % 60;
  $second = ((int)($time / 1000)) % 60;

  return sprintf ($format, $hour, $minute, $second);
 }

 /**
  * Extracts header and body streams from an archive.
  *
  * @return bool
  */
 private function extractStreamsFromArchive ()
 {
  if (!$this->fileName)
  {
   $this->lastError = RA__FILE_NOT_SPECIFIED;
   return false;
  }

  $ext = strrchr ($this->fileName, '.');
  if (strcasecmp ($ext, self::rarExt) != 0 && strcasecmp ($ext, self::zipExt) != 0)
  {
   $this->lastError = RA__FORMAT_NOT_SUPPORTED;
   return false;
  }

  if (strcasecmp ($ext, self::rarExt) == 0)
  {
   if (!function_exists ('rar_open'))
   {
    $this->lastError = RA__RAR_EXTENSION_NOT_INSTALLED;
    return false;
   }
   // stub
   $this->lastError = RA__RAR_NOT_IMPLEMENTED;
   return false;
  }

  if (strcasecmp ($ext, self::zipExt) == 0)
  {
   $zip = new ZipArchive ();

   if ($zip->open ($this->fileName) !== true)
   {
    $this->lastError = RA__UNABLE_TO_OPEN_ZIP_ARCHIVE;
    return false;
   }

   if ($zip->numFiles == 0)
   {
    $zip->close ();
    $this->lastError = RA__ZIP_ARCHIVE_EMPTY;
    return false;
   }

   if ($zip->numFiles != 1)
   {
    $zip->close ();
    $this->lastError = RA__MORE_FILES_PER_ARCHIVE;
    return false;
   }

   $mgx_found = false;

   for ($i = 0; false !== ($stat = $zip->statIndex ($i)); $i++)
   {
    // skip directories and 0-bytes files
    if (!$stat['size'])
    {
     continue;
    }

    // skip non-mgx files
    $ext = strrchr ($stat['name'], '.');
    if (strcasecmp ($ext, self::mgxExt) != 0)
    {
     continue;
    }

    // get a file handler to the entry
    if (!($fp = $zip->getStream ($stat['name'])))
    {
     continue;
    }

    $mgx_found = true;

    // read data
    $packed_data = fread ($fp, 4);

    if ($packed_data === false || strlen ($packed_data)     {
     $zip->close ();
     $this->lastError = RA__ERROR_IN_HEADER_STREAM;
     return false;
    }

    $unpacked_data = unpack ("V", $packed_data);
    $header_len = $unpacked_data[1];

    if ($header_len == 0)
    {
     $zip->close ();
     $this->lastError = RA__OLD_FORMAT_VER;
     return false;
    }

    // skip next_pos
    $packed_data = fread ($fp, 4);
    $header_len -= 8;

    // TODO: getMemoryLimit ()
    if ($header_len > 1048576) // 1MB
    {
     $zip->close ();
     $this->lastError = RA__ERROR_IN_HEADER_STREAM;
     return false;
    }

    $read = 0;
    while ($read     {
     $read += strlen ($buff);
     $this->headerStream .= $buff;
    }

    $read = 0;
    while (!feof ($fp))
    {
     $buff = fread ($fp, 1024 * 8);
     $this->bodyStream .= $buff;
    }

    unset ($buff);
    fclose ($fp);
    $zip->close ();

    return true;
   } // endfor

   $zip->close ();

   if (!$mgx_found)
   {
    $this->lastError = RA__NO_RECGAME_FOUND;
    return false;
   }
  } // end zip uncompression
 }

 /**
  * Uncompresses header stream.
  *
  * @return string|bool uncompressed stream or false if an error occured
  */
 private function uncompressHeaderStream ()
 {
  if (!$this->headerStream)
  {
   $this->lastError = RA__EMPTY_HEADER_STREAM;
   return false;
  }

  //TODO: getMemoryLimit ()
  $this->headerStream = @gzinflate ($this->headerStream, 4194304); // 4MB

  if (!$this->headerStream)
  {
   $this->lastError = RA__ERROR_IN_HEADER_STREAM;
   return false;
  }

  return true;
 }

 /**
  * Analyzes header stream.
  *
  * @return bool true if analyzed successfully, otherwise false
  */
 private function analyzeHeaderStream ()
 {
  global $RA__MAPS;
  global $RA__GAME_STYLES;
  global $RA__DIFFICULTY_LEVELS;
  global $RA__GAME_TYPES;
  global $RA__GAME_SPEEDS;
  global $RA__CIVS;

  // initialize variables
  $constant2      = pack ('c*', 0x9A, 0x99, 0x99, 0x99, 0x99, 0x99, 0xF9, 0x3F);
  $separator      = pack ('c*', 0x9D, 0xFF, 0xFF, 0xFF);
  $unknown_const2 = pack ('c*', 0x98, 0x9E, 0x00, 0x00, 0x02, 0x0B);
  $trigger_info_pos = $game_setting_pos = 0;

  $string_id = pack ('c*', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);

  $pos = 0;
  $m_header_len = strlen ($this->headerStream);

  $len = strlen ($constant2);
  $pos = ($m_header_len - $len);

  $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
  // TODO: use substr_compare
  while ($pos > 0)
  {
   if (strcmp ($buff, $constant2) == 0)
   {
    $trigger_info_pos = $pos;
    break;
   }
   $pos -= $len + 1;
   $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
  }

  if ($trigger_info_pos == 0)
  {
   $this->lastError = RA__ERROR_IN_UNCOMPRESSED_STREAM;
   return false;
  }

  // getting Game_settings position
  $len = strlen ($separator);
  $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
  while ($pos > 0)
  {
   if (strcmp ($buff, $separator) == 0)
   {
    $game_setting_pos = $pos;
    break;
   }

   $pos -= $len + 1;
   $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
  }

  if ($game_setting_pos == 0)
  {
   // not found
   $this->lastError = RA__ERROR_IN_UNCOMPRESSED_STREAM;
   return false;
  }

/***************************************************************************************
note: Victory & Achievement data not found as described in mgx format description
obtaining Achievement data should be called after knowing num_player as it is required

  // getting Victory position, first is Disables
  $pos -= 8;
  $victory_pos = 0;
  $separator_first_pos = 0;
  $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
  while ($pos > 0)
  {
   if (strcmp ($buff, $separator) == 0)
   break;
   $pos -= $len + 1;
   $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
  }
  if ($pos != 0)
  {
   $pos -= 8;
   $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
   while ($pos > 0)
   {
    if (strcmp ($buff, $separator) == 0)
    {
     $victory_pos = $pos;
     break;
    }
    $pos -= $len + 1;
    $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
   }
  }
  if ($victory_pos != 0)
  {
   $pos -= 8;
   $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
   while ($pos > 0)
   {
    if (strcmp ($buff, $separator) == 0)
    {
     $separator_first_pos = $pos;
    break;
    }
    $pos -= $len + 1;
    $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
   }

   $pos = $victory_pos;

   // here should be victory condition, but isn't
   $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
   $unpacked_data = unpack ("V", $packed_data);
   $conquest = $unpacked_data[1];
   if (conquest == 0)
   {
    $this->gameSettings->victory = 'custom';
    $pos += 4;

    $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
    $unpacked_data = unpack ("V", $packed_data);
    $relics = $unpacked_data[1];
    $pos += 4;
    $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
    $unpacked_data = unpack ("V", $packed_data);
    $explored = $unpacked_data[1];
    $pos += 4;
    $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
    $unpacked_data = unpack ("V", $packed_data);
    $all = $unpacked_data[1];
    $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
    $unpacked_data = unpack ("V", $packed_data);
    $mode = $unpacked_data[1];
    $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
    $unpacked_data = unpack ("V", $packed_data);
    $score = $unpacked_data[1];
    $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
    $unpacked_data = unpack ("V", $packed_data);
    $time = $unpacked_data[1];

    if ($relics != 0)
    {
     $this->gameSettings->victory = sprintf ('Gain %d relics', $relics);
    }
    elseif ($explored != 0)
    {
     $this->gameSettings->victory = sprintf ('Percentage of explored map: %d', $explored);
    }
    else
    {
     switch ($mode)
     {
      case 0:
       $this->gameSettings->victory = 'Normal';
       break;
      case 1:
       $this->gameSettings->victory = 'Conquest';
       break;
      case 2:
       $this->gameSettings->victory = sprintf ('Score Limit: %d', $score);
       break;
      case 3:
       $this->gameSettings->victory = sprintf ('Time Limit: %d', $time);
       break;
     }
    }

   }
   elseif ($condition == 1)
   {
    $this->gameSettings->victory = 'Conquest';
   }
  }
  if ($separator_first_pos != 0)
  {
   $string_id_pos = 0;
   $len = strlen ($string_id);
   $pos = $separator_first_pos - $len;
   $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
   while ($pos > 0)
   {
    if (strcmp ($buff, $string_id) == 0)
    {
     $string_id_pos = $pos;
     break;
    }
    $pos -= $len + 1;
    $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
   }
   if ($string_id_pos != 0)
   {
    $pos = $string_id_pos - $len;
    $pos -= 4096;
    $pos -= 4;
    $pos -= 4;

    // num_player is not known till now, need to be called after obtaining it
    $pos -= 1473 * $num_player;
    // here should start Achievement, but doesn't :-(
    $pos += 13;
    $packed_data = substr ($this->headerStream, $pos, 4);
    $unpacked_data = unpack ("V", $packed_data);
    $total_point = $unpacked_data[1];
    //...
   }
  }
***************************************************************************************/

  // getting Game_Settings data
  // skip negative[2]
  $pos = $game_setting_pos + 8;

  $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
  $unpacked_data = unpack ("V", $packed_data);
  $map_id = $unpacked_data[1];

  $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
  $unpacked_data = unpack ("V", $packed_data);
  $difficulty = $unpacked_data[1];
  // skip unknown
  $pos += 4;

  if (array_key_exists ($map_id, $RA__MAPS))
  {
   $this->gameSettings->map = $RA__MAPS[$map_id][0];
   $this->gameSettings->gameStyle = $RA__GAME_STYLES[0];
  }
  else
  {
   $this->gameSettings->gameStyle = $RA__GAME_STYLES[2];
  }

  if (array_key_exists ($difficulty, $RA__DIFFICULTY_LEVELS))
  {
   $this->gameSettings->difficultyLevel = $RA__DIFFICULTY_LEVELS[$difficulty];
  }

  // getting Player_info data
  for ($i = 0; $i   {
   $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
   $unpacked_data = unpack ("V", $packed_data);
   $player_data_index = $unpacked_data[1];

   $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
   $unpacked_data = unpack ("V", $packed_data);
   $human = $unpacked_data[1];

   $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
   $unpacked_data = unpack ("V", $packed_data);
   $name_len = $unpacked_data[1];

   $playername = substr ($this->headerStream, $pos, $name_len); $pos += $name_len;

   // 0x00:invalid player, 0x02:human, 0x04:computer
   // index 0 is GAIA player
   if ($human == 0x00)
    continue;
   // sometimes very rarely index is 1
   if ($human == 0x01)
    continue;
   if ($human != 0x00 && $i != 0)
   {
    $player = new Player ();
    $player->name  = $playername;
    $player->index = $player_data_index;
    $player->human = ($human == 0x02);

    $this->playerList->addPlayer ($player);
   }
  } // endfor

  // Trigger_info
  $pos = $trigger_info_pos + 1;

  $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
  $unpacked_data = unpack ("V", $packed_data);
  $num_trigger = $unpacked_data[1];

  if ($num_trigger == 0)
  {
   $this->gameSettings->isScenario = false;

   // Other_data
   for ($i = 0; $i    {
    $packed_data = substr ($this->headerStream, $pos, 1); $pos += 1;
    $unpacked_data = unpack ("C", $packed_data);
    $team = $unpacked_data[1];

    if (($i + 1) playerList->getCount ())
    {
     if ($player = $this->playerList->getPlayer ($i))
     {
      $player->team = $team - 1;
     }
    }
   }

   // skip unknown[13]
   $pos += 13;

   $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
   $unpacked_data = unpack ("V", $packed_data);
   $pop_limit = $unpacked_data[1];

   $packed_data = substr ($this->headerStream, $pos, 1); $pos += 1;
   $unpacked_data = unpack ("C", $packed_data);
   $game_type = $unpacked_data[1];

   $packed_data = substr ($this->headerStream, $pos, 1); $pos += 1;
   $unpacked_data = unpack ("C", $packed_data);
   $lock_diplomacy = $unpacked_data[1];

   $this->gameSettings->popLimit = $pop_limit;
   $this->gameSettings->gameType = $RA__GAME_TYPES[$game_type];
   $this->gameSettings->lockDiplomacy = ($lock_diplomacy == 0x01);

   // here comes pre-game chat
   $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
   $unpacked_data = unpack ("V", $packed_data);
   $num_chat = $unpacked_data[1];
   for ($i = 0; $i    {
    $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
    $unpacked_data = unpack ("V", $packed_data);
    $chat_len = $unpacked_data[1];

    // 0-length chat exists
    if ($chat_len == 0)
    {
     continue;
    }

    $chat = substr ($this->headerStream, $pos, $chat_len); $pos += $chat_len;

    if ($chat[0] == '@' && $chat[1] == '#' && $chat[2] >= '1' && $chat[2]     {
     $chat = rtrim ($chat); // throw null-termination character
     $this->pregameChat[] = $chat;
    }
   }
   unset ($chat);
  }
  else
  {
   $this->gameSettings->isScenario = true;
   $this->gameSettings->map = '';
   $this->gameSettings->gameType = $RA__GAME_TYPES[3];
   $this->gameSettings->gameStyle = $RA__GAME_STYLES[2];
  }

  // skip AI_info if exists
  $pos = 0x0C;
  $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
  $unpacked_data = unpack ("V", $packed_data);
  $include_ai = $unpacked_data[1];

  if ($include_ai == 0x01)
  {
   $pos += 2;
   $packed_data = substr ($this->headerStream, $pos, 2); $pos += 2;
   $unpacked_data = unpack ("v", $packed_data);
   $num_string = $unpacked_data[1];
   $pos += 4;
   for ($i = 0; $i    {
    $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
    $unpacked_data = unpack ("V", $packed_data);
    $string_length = $unpacked_data[1];
    $pos += $string_length;
   }
   $pos += 6;
   // AI_data
   for ($i = 0; $i    {
    $pos += 10;
    $packed_data = substr ($this->headerStream, $pos, 2); $pos += 2;
    $unpacked_data = unpack ("v", $packed_data);
    $num_rule = $unpacked_data[1];
    $pos += 4;
    $pos = $pos + (400 * $num_rule);
   }
   $pos += 5544;
  }

  // getting data
  $pos += 4;
  $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
  $unpacked_data = unpack ("V", $packed_data);
  $game_speed = $unpacked_data[1];

  $pos += 37;
  $packed_data = substr ($this->headerStream, $pos, 2); $pos += 2;
  $unpacked_data = unpack ("v", $packed_data);
  $rec_player_ref = $unpacked_data[1];

  $packed_data = substr ($this->headerStream, $pos, 1); $pos += 1;
  $unpacked_data = unpack ("C", $packed_data);
  $num_player = $unpacked_data[1];

  $rec_player_ref--;  // 0 is GAIA, not appears in playerList
  $num_player--;
  $this->gameSettings->speed = $RA__GAME_SPEEDS[$game_speed];
  if ($player = $this->playerList->getPlayer ($rec_player_ref))
  {
   $player->owner = true;
  }

  if ($num_player playerList->getCount ())
  {
   $this->gameSettings->inGameCoop = true;
  }

  // getting map
  $pos += 62;
  $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
  $unpacked_data = unpack ("V", $packed_data);
  $map_size_x = $unpacked_data[1];
  $this->mapWidth = $map_size_x;

  $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
  $unpacked_data = unpack ("V", $packed_data);
  $map_size_y = $unpacked_data[1];
  $this->mapHeight = $map_size_y;

  $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
  $unpacked_data = unpack ("V", $packed_data);
  $num_unknown_data = $unpacked_data[1];
  // unknown data
  for ($i = 0; $i   {
   $pos += 1275;
   $pos += $map_size_x * $map_size_y;

   $packed_data = substr ($this->headerStream, $pos, 4); $pos += 4;
   $unpacked_data = unpack ("V", $packed_data);
   $num_float = $unpacked_data[1];
   /*
    if (num_float != 0x29)
    {
    // error = 1
    break;
    }
   */
   $pos += 4 * $num_float;
   $pos += 4;
  }
  $pos += 2;

  // map data
  // if error == 0 { do following + set flag map_loaded }
  $x = $y = 1;
  for ($i = 0; $i   {
   // terrain_id
   $packed_data = substr ($this->headerStream, $pos, 1); $pos += 1;
   $unpacked_data = unpack ("C", $packed_data);
   $terrain_id = $unpacked_data[1];
   // elevation
   $packed_data = substr ($this->headerStream, $pos, 1); $pos += 1;
   $unpacked_data = unpack ("C", $packed_data);
   $elevation = $unpacked_data[1];
   if ($x == $map_size_x + 1)
   {
    $x = 1;
    $y++;
   }
   $this->mapData[$x][$y][0] = $terrain_id;
   // TODO: elevation
   // we do not get elevation (memory exhaustive)
   // $this->mapData[$x][$y][1] = $elevation;
   $x++;
  }

  $pos += 128;
  $pos += $map_size_x * $map_size_y * 4;
  $pos += 15;
  /*
  // TODO: test for behavior if there is a Computer
  // getting Player_info position
  $len = strlen ($unknown_const2);
  $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
  while ($pos   {
   if (strcmp ($buff, $unknown_const2) == 0)
   {
    break;
   }
   $pos -= $len - 1;
   $buff = substr ($this->headerStream, $pos, $len); $pos += $len;
  }
  */
  $pos += 5138;

  foreach ($this->playerList as $player)
  {
   // skip cooping player, he/she has no data in Player_info
   $player_ = $this->playerList->getPlayerByIndex ($player->index);

   if ($player_ && ($player_ !== $player) && $player_->civId)
   {
    $player->civId = $player_->civId;
    $player->civ = $player_->civ;
    $player->colorId = $player_->colorId;
    $player->isCooping = true;
    continue;
   }
   $playerName = $player->name;

   while ($pos    {
    $buff = substr ($this->headerStream, $pos, strlen ($playerName));

    if (strcmp ($buff, $playerName) == 0)
    {
     break;
    }
    $pos++;
   }
   $pos += strlen ($playerName);

   // skip data (first byte is null char player's name terminator)
   $pos += 817;
   // civilization
   $packed_data = substr ($this->headerStream, $pos, 1); $pos += 1;
   $unpacked_data = unpack ("C", $packed_data);
   $civilization = $unpacked_data[1];

   $player->civId = $civilization;
   $player->civ = $RA__CIVS[$civilization][0];

   // skip unknown9[3]
   $pos += 3;
   // player_color
   $packed_data = substr ($this->headerStream, $pos, 1); $pos += 1;
   $unpacked_data = unpack ("C", $packed_data);
   $player_color = $unpacked_data[1];

   $player->colorId = $player_color;

   $pos += 4299;
  } // endfor

  // initialize variables
  $con1 = pack ('c*', 0x3A, 0x20);
  $con2 = pack ('c*', 0xA1, 0x47);

  $LANGUAGES = array (
   'en'  => pack ('c*', 0x4D, 0x61, 0x70, 0x20, 0x54, 0x79, 0x70, 0x65),
   'cz'  => pack ('c*', 0x54, 0x79, 0x70, 0x20, 0x6D, 0x61, 0x70, 0x79),
   'jp'  => pack ('c*', 0x83, 0x7D, 0x83, 0x62, 0x83, 0x76, 0x82, 0xCC, 0x8E, 0xED, 0x97, 0xDE),
   'cn'  => pack ('c*', 0xB5, 0xD8, 0xCD, 0xBC, 0xC0, 0xE0, 0xD0, 0xCD),
   'sp'  => pack ('c*', 0x54, 0x69, 0x70, 0x6F, 0x20, 0x64, 0x65, 0x20, 0x6D, 0x61, 0x70, 0x61),
   'de'  => pack ('c*', 0x4B, 0x61, 0x72, 0x74, 0x65, 0x6E, 0x74, 0x79, 0x70),
   'cn2' => pack ('c*', 0xA6, 0x61, 0xB9, 0xCF, 0xC3, 0xFE, 0xA7, 0x4F),
   'kr'  => pack ('c*', 0xC7, 0xA5, 0xC1, 0xD8, 0x0A, 0xC0, 0xDA, 0xBF, 0xF8),
   'fr'  => pack ('c*', 0x54, 0x79, 0x70, 0x65, 0x20, 0x64, 0x65, 0x20, 0x63, 0x61, 0x72, 0x74, 0x65, 0xA0),
   'it'  => pack ('c*', 0x54, 0x69, 0x70, 0x6F, 0x20, 0x64, 0x69, 0x20, 0x6D, 0x61, 0x70, 0x70, 0x61),
   'sp2' => pack ('c*', 0x54, 0x69, 0x70, 0x6F, 0x20, 0x64, 0x65, 0x20, 0x4D, 0x61, 0x70, 0x61),
   'ur'  => pack ('c*', 0xD2, 0xE8, 0xEF, 0x20, 0xCA, 0xE0, 0xF0, 0xF2, 0xFB));

  // getting map name (only if map is custom (44) and game type is not scenario (game_type still $00 in scenarios)
  // if map_id = 32 (Random Land Map), it is possible to obtain map if it's written in english
  if (!array_key_exists ($map_id, $RA__MAPS) && $game_type != 0x03 && !$this->gameSettings->isScenario)
  {
   $pos = $game_setting_pos - 11520;

   $mapFound = false;

   $buff = substr ($this->headerStream, $pos, 2); $pos += 2;
   // searching up to -100000 bytes, than stop
   while ($pos > $game_setting_pos - 11520 - 100000 && !$mapFound)
   {
    if (strcmp ($buff, $con1) == 0 || strcmp ($buff, $con2) == 0)
    {
     $pos -= 2;

     foreach ($LANGUAGES as $val)
     {
      $pos -= strlen ($val);
      $map_name = substr ($this->headerStream, $pos, strlen ($val)); $pos += strlen ($val);

      if (strcmp ($map_name, $val) == 0)
      {
       $mapName = '';
       $pos += 2; // skip ': '

       for ($i = 0; $i        {
        $buff = substr ($this->headerStream, $pos, 1); $pos += 1;

        if ($buff != chr (0x0A))
        {
         $mapName .= $buff;
        }
        else
        {
         $mapFound = true;
         break;
        }
       } // endfor
       break;
      } // endif
     } // end foreach
    } // endif

    $pos -= 3;
    $buff = substr ($this->headerStream, $pos, 2); $pos += 2;
   } // endwhile

   $this->gameSettings->map = ($mapFound) ? $mapName : $RA__GAME_STYLES[2];
  } // endif

  // build teams
  foreach ($this->playerList as $player)
  {
   if ($player->team == 0)
   {
    $found = false;
    foreach ($this->teams as $team)
    {
     if ($team->getIndex () != $player->team)
     {
      continue;
     }
     foreach ($team as $player_)
     {
      if ($player_->index == $player->index)
      {
       $team->addPlayer ($player);
       $found = true;
       break;
      }
     }
     if ($found)
     {
      break;
     }
    }
    if (!$found)
    {
     $team = new Team ();
     $team->addPlayer ($player);
     $this->teams->addTeam ($team);
    }
   }
   else
   {
    if ($team = $this->teams->getTeamByIndex ($player->team))
    {
     $team->addPlayer ($player);
    }
    else
    {
     $team = new Team ();
     $team ->addPlayer ($player);
     $this->teams->addTeam ($team);
    }
   }
  }

  return true;
 }

 /**
  * Analyzes body stream.
  *
  * @return bool true if successfully analyzed, otherwise false
  */
 private function analyzeBodyStream ()
 {
  $time_cnt = $pos = $trading_cnt = 0;
  $m_body_len = strlen ($this->bodyStream);
  $age_flag = array (0, 0, 0, 0, 0, 0, 0, 0);

  if (defined ('RA__DEBUG'))
  {
   global $RA__RESOURCES;
  }

  while ($pos   {
   $packed_data = substr ($this->bodyStream, $pos, 4); $pos += 4;
   $unpacked_data = unpack ("V", $packed_data);
   $type = $unpacked_data[1];
   if (defined ('RA__DEBUG'))
   {
    printf (nl2br ("type: %d/n"), $type);
   }

   switch ($type)
   {
    case 4:
     $packed_data = substr ($this->bodyStream, $pos, 4); $pos += 4;
     $unpacked_data = unpack ("V", $packed_data);
     $command = $unpacked_data[1];
     if ($command == 0x01F4)
     {
      // Game_start
      $pos += 20;
     }
     elseif ($command == -1)
     {
      // Chat
      $packed_data = substr ($this->bodyStream, $pos, 4); $pos += 4;
      $unpacked_data = unpack ("V", $packed_data);
      $chat_len = $unpacked_data[1];

      for ($i = 0; $i playerList->getCount (); $i++)
      {
       if (!($player = $this->playerList->getPlayer ($i)))
       {
        continue;
       }

       if ($player->feudalTime != 0 && $player->feudalTime        {
        $this->ingameChat[] = sprintf ('%d@#0%s advanced to Feudal Age', $player->feudalTime, $player->name);
        $age_flag[$i] = 1;
       }
       if ($player->castleTime != 0 && $player->castleTime        {
        $this->ingameChat[] = sprintf ('%d@#0%s advanced to Castle Age', $player->castleTime, $player->name);
        $age_flag[$i] = 1;
       }
       if ($player->imperialTime != 0 && $player->imperialTime        {
        $this->ingameChat[] = sprintf ('%d@#0%s advanced to Imperial Age', $player->imperialTime, $player->name);
        $age_flag[$i] = 1;
       }
      }

      $chat = substr ($this->bodyStream, $pos, $chat_len); $pos += $chat_len;

      if ($chat[0] == '@' && $chat[1] == '#' && $chat[2] >= '1' && $chat[2]       {
       $chat = rtrim ($chat); // throw null-termination character
       if (substr ($chat, 3, 2) == '--' && substr ($chat, -2) == '--')
       {
       }
       else
       {
        $this->ingameChat[] = sprintf ('%d%s', $time_cnt, $chat);
       }
      }
     }
     break;
    case 2:
     // Sync
     $packed_data = substr ($this->bodyStream, $pos, 4); $pos += 4;
     $unpacked_data = unpack ("V", $packed_data);
     $time_cnt += $unpacked_data[1]; // time_cnt is in miliseconds
     $packed_data = substr ($this->bodyStream, $pos, 4); $pos += 4;
     $unpacked_data = unpack ("V", $packed_data);
     $unknown = $unpacked_data[1];
     if ($unknown == 0)
     {
      $pos += 28;
     }
     $pos += 12;
     break;
    case 1:
     // Command
     $packed_data = substr ($this->bodyStream, $pos, 4); $pos += 4;
     $unpacked_data = unpack ("V", $packed_data);
     $length = $unpacked_data[1];

     $packed_data = substr ($this->bodyStream, $pos, 1);
     $unpacked_data = unpack ("C", $packed_data);
     $command = $unpacked_data[1];

     if (defined ('RA__DEBUG'))
     {
      $packed_data = substr ($this->bodyStream, $pos, 2);
      $unpacked_data = unpack ("v", $packed_data);
      $cmd = $unpacked_data[1];

      $format = nl2br ("(%s): 0x%02x - 0x%02x -> len: %d/n");
      printf ($format, self::gameTimeToString ($time_cnt), $cmd, $command, $length);
     }

     if (defined ('RA__DEBUG'))
     {
      $output = '';
      for ($i = $pos + 1; $i       {
       $packed_data = substr ($this->bodyStream, $i, 1);
       $unpacked_data = unpack ("C", $packed_data);
       $c = $unpacked_data[1];
       $output .=  $c . '|';
      }
      print (nl2br ($output . "/n"));
     }

     switch ($command)
     {
      case 0x0B:
       $pos += 1;
       $packed_data = substr ($this->bodyStream, $pos, 1); $pos += 1;
       $unpacked_data = unpack ("C", $packed_data);
       $player_number = $unpacked_data[1];
       $pos += 2;
       if ($player = $this->playerList->getPlayerByIndex ($player_number))
       {
        $player->resignTime = $time_cnt;
        $this->ingameChat[] = sprintf ('%d@#0%s resigned', $player->resignTime, $player->name);

        if (defined ('RA__DEBUG'))
        {
         $format = nl2br ("(%s) resigned player #%d: %s/n");
         printf ($format, self::gameTimeToString ($time_cnt), $player_number, $player->name);
        }
       }
       $pos += $length - 4;  // different from mgx format description
       break;
      case 0x65: // researches
       $pos += 8;
       // player_id
       $packed_data = substr ($this->bodyStream, $pos, 2); $pos += 2;
       $unpacked_data = unpack ("v", $packed_data);
       $player_id = $unpacked_data[1];
       // research_id
       $packed_data = substr ($this->bodyStream, $pos, 2); $pos += 2;
       $unpacked_data = unpack ("v", $packed_data);
       $research_id = $unpacked_data[1];
       if ($research_id == 101)
       {
        // feudal time
        if ($player = $this->playerList->getPlayerByIndex ($player_id))
        {
         $player->feudalTime = $time_cnt + 130 * 1000; // + research time (2:10)
        }
       }
       if ($research_id == 102)
       {
        // castle time
        if ($player = $this->playerList->getPlayerByIndex ($player_id))
        {
         // persians?
         $player->castleTime = ($player->civId == 0x08) ? $time_cnt + 144 * 1000 : $time_cnt + 160 * 1000;
        }
       }
       if ($research_id == 103)
       {
        // imperial time
        if ($player = $this->playerList->getPlayerByIndex ($player_id))
        {
         // persians?
         $player->imperialTime = ($player->civId == 0x08) ? $time_cnt + 162 * 1000 : $time_cnt + 190 * 1000;
        }
       }
       // else
       {
        if ($player = $this->playerList->getPlayerByIndex ($player_id))
        {
         $player->researches[$research_id] = $time_cnt;
        }
       }
       if (defined ('RA__DEBUG'))
       {
        $format = nl2br ("#%d -> %d/n");
        printf ($format, $player_id, $research_id);
       }
       $pos += ($length - 12);
       break;
      case 0x77

Label berkaitan:
sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Cadangan popular
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan