Sie sind nicht angemeldet.

  • Anmelden

61

15.11.2005, 17:37

also alles was hier drin steht bringt dir nix ?

Zitat

php
//****************************************************************************************************************
// AoM Rec Game Decoder v0.3 beta
//
// ReturnRecGameXml - opens the file and if its a valid AoM rec game returns an xml file with the information
// ParseRecGameXml - Parses the xml file into a more readable form, call a print_r() on the result to see
// how it looks like
//
// This code is distributed as is. There is no waranty that it works and no waranty that it will still work in the future.
// Use it on your on risk!!!
// special thanx go out to Aleste from the Planet Age of Mythology Forum for telling me how to read the rec game
// this PHP Code is (c) 07.2003 by R. Vornholt - You can use it freely as long as this information stays.
// If you want to contact me send me a mail to doc_santonian@die-ohne-clan.de or visit my website at
// http://www.die-ohne-clan.de. If you like the code, visit at least the website and write a few lines at the forum
// or into the guestbook.

// CHANGELOG
//
// - 30.09 - Added support for The Titans Expansion
// - 18.12 - Added support for REALCIVILIZATION attribute in array (cubensis)


//****************************************************************************************************************
//XML DESCRIPTION: (I could not determin the use of a few values, if you can tell me what these values are for, please tell me)
//
// FILENAME: name of the map
// CURRENTPLAYER: Id of the player to whom this rec belongs
// - In SinglePlayer it's always -1
// SCENARIOFILENAME: ???
// GAMETYPE: always 2
// FILENAMECRC: CRC
// GAMESTARTTIME Starttime of game in Seconds - can be used in PHP date function
// - In Singleplayer its always 0
// MAPVISIBILITY: 0 => Normal, 1 => Revealed
// WORLDRESOURCES: it's always 1, is there a way to change it anyway?
// MAPSIZE: 0 => Normal Map, 1 => Large Map
// RESTRICTEDPAUSES: 0 => Unlimited, else the number of pauses
// GAMEMODE: 0 => Supremacy, 1 => Conquest, 2 => Ligthning, 3 => Deathmatch
// HANDICAPMODE: 0 => No Handicap, 1 => Handicap Free, 2 => Automatic
// - I guess that if the Handicap is 2 it's a rated match
// MAPSEED The Random Seed value to use to generate the same map from the RMS
// DIFFICULTY: 0 => Easy, 1 => Moderate, 2 => Hard, 3 => Titan
// NUMPLAYERS: No. of players
//
// GAMEFLAGS: LOCKEDTEAMS, ALLOWCHEATS, TEAMSHARERESOURCES, TEAMSHAREPOPULATION
// - They have no values afak, they exist or they don't, if they exist they are switched on
//
// PLAYER:
// CLIENTID: Player ID starting with 0
// CONTROLLEDPLAYER Player ID starting with 1
// NAME: Player Name
// - If Player is AI it's the type of AI (Balanced, Boomer, ...)
// RATING: Rating of that player at gametime in that gamemode
// - in Singleplayer it's always 500 for all player
// - in LAN Games it's always 0 for all players
// TYPE: 0 => HumanPlayer, 1 => AI Player, 4 => Observer (Titans only)
// TRANSFORMCOLOR1: ???
// TRANSFORMCOLOR2: ???
// TEAM: Team Info
// - In 1vs1 Rated Games both players have 255 as team
// - 255 is Random Team!!!
// CIVILIZATION (AoM): 0 => Zeus, 1 => Poseidon, 2 => Hades,
// 3 => Isis, 4=> Ra, 5 => Set,
// 6 => Odin, 7 => Thor, 8 => Loki,
// 9 => Random All,
// 10 => Random Greek, 11=> Random Norse, 12 => Random Egyptian
//
// CIVILIZATION (Titans): 0 => Zeus, 1 => Poseidon, 2 => Hades,
// 3 => Isis, 4=> Ra, 5 => Set,
// 6 => Odin, 7 => Thor, 8 => Loki,
// 9 => Cronos, 10 => Oranos, 11 => Gaia,
// 12 => Random All, 13 => Random Greek
// 14 = > Random Norse, 15 => Random Egyptian, 16 => Random Atlantean
// AIPERSONALITY: name of Computer AI
//
//
//===============================================================================================================
//
// EXTRA INFORMATION CONTAINED IN THE RECORDED GAME FILE
// -----------------------------------------------------
//
// further down in the file there comes more information but in a binary form. This is what I found out so far:
//
// Team Information:
//
// (the xml team info is 255 for all in random team)
//
// look for the string "Team #" then it goes like this:
//
// Team #ABCCCDCCCDCCCD
//
// A -> Team number in ascii
// B -> no. of players in team in binary
// C -> null value
// D -> playerid in binary
//
// the CCCD block loops B times
//
// The other bytes in the team info I could not (yet) figure out.
//
// Civilisation:
//
// After the team info there is info about each player. Look for the name and then the 11th byte is the civ id
// in binary. If someone chose random team here is the civ he got in the end.
//****************************************************************************************************************


function ReturnRecGameXml($fileName)
{
define( "GAME_SETTINGS_BLOCKSIZE", 0x400 );
define( "GAMESETTINGSOFFSET", 0x59A );
define( "TITAN_ADDITIONAL_SETTINGS_OFFSET", 0x28 );

define( "GAME_SETTINGS_STARTTAG", ASCIItoUTF16( '<GameSettings>' ) );
define( "GAME_SETTINGS_ENDTAG", ASCIItoUTF16( '</GameSettings>' ) );

global $_REAL_CIV;

$xml="";
$xPack=0; //0-> AoM, 1->Titans

$fp = fopen($fileName, "r");

//---- Make sure the file opened
if($fp == null) return false;

//---- Check the header bytes are correct = 'l33t'
$header = fread($fp, 4); //its a 4 byte header
if($header != "l33t") return false;

//---- See how many bytes the uncompressed data will expand to
$sizeBytes = fread($fp, 4);

$size = (int) ord($sizeBytes[0]) //get original file size
+ (ord($sizeBytes[1]) << 8)
+ (ord($sizeBytes[2]) << 16)
+ (ord($sizeBytes[3]) << 24);

$compressedData = fread($fp, filesize($fileName)-8);
$uncompressed = gzuncompress($compressedData, $size);


//---- Check to make sure the uncompressed data is valid
if($uncompressed == null) return false;

//---- See if we can extract the XML data from the random mess
$uc_nullfree = substr($uncompressed, GAMESETTINGSOFFSET);

//---- Check of this as an AoM game, or an AoT game
if(strpos($uc_nullfree, GAME_SETTINGS_STARTTAG) == 2)
$xPack = 0;
else
{
$uc_nullfree = substr($uc_nullfree, TITAN_ADDITIONAL_SETTINGS_OFFSET);
if(strpos($uc_nullfree, GAME_SETTINGS_STARTTAG) == 2)
$xPack = 1;
else
return false;
}

$final = "";
$pos = 0;

$end = strpos($uc_nullfree, GAME_SETTINGS_ENDTAG);

$skipSize = 4;

while($pos < $size)
{
$final .= substr($uc_nullfree, $pos, GAME_SETTINGS_BLOCKSIZE);
$pos += GAME_SETTINGS_BLOCKSIZE + $skipSize;

if($pos > $end) //there was a skip after the xml where no skip should be... this should work
$skipSize=0;
}


//---- Extract the XML from the data
$end = strpos($final, GAME_SETTINGS_ENDTAG);
$xml = substr($final, 2, $end-2);

//---- Convert the UTF-16 UNICODE into 8 bit ASCII
$xml = UTF16toASCII($xml);


//---- BINARY FIXES

//-- This finds the Actual Team # for the players, no 255 in here!!
$start = strpos($final, "Team #", 0);
$first_start = $start;
while($start !== false)
{
$teamstr = substr($final, $start, 100);

for($m=0; $m<ord($teamstr[7]); $m++)
{
$xml .= "\t<REALTEAM TeamId=\"".($teamstr[6]-1)."\" PlayerId=\"".(ord($teamstr[7 + (4*($m+1))])-1)."\" ></REALTEAM>\n";
}
$start = strpos($final, "Team #", $start+6);
};

//-- We can't actually extract the player names yet, until we have XML decoded
//-- so we have to store the REALCIVILIZATION memory block in a global for now
//-- Grab too much, we can refine it later.. (cubensis)
if( $first_start !== false ) $_REAL_CIV = substr( $final, $first_start, 4000 );

//---- Format the XML, with the inserted tags
$ret_xml = "<GameSettings>\n";
$ret_xml .= "\t<XPACK>".$xPack."</XPACK>\n";
$ret_xml .= substr($xml, strlen("<GameSettings>"));
$ret_xml .= "</GameSettings>";

return($ret_xml);
}




function startElementHandler($parser, $name, $attribs)
{
global $xmldata;
global $i;
global $lastName;
global $playerStart;

$lastName = $name;
if($name == "GAMEFLAGS")
$xmldata["$name"] = $attribs;
else
{
switch($name)
{
case "REALTEAM":
$xmldata[$name][$attribs["PLAYERID"]] = $attribs["TEAMID"];
break;

default:
if($name == "PLAYER")
{
$i++;
$playerStart = true;
}

if($playerStart === true)
{
if($name == "PLAYER")
$xmldata["$name"][$i] = $attribs;
else
$xmldata["$name"][$i] = 0;
}
else
$xmldata["$name"] = 0;

break;
}
}
}




function endElementHandler($parser, $name)
{
}




function cdataHandler($parser, $data)
{
global $xmldata;
global $lastName;
global $playerStart;
global $i;

if((ord($data) != 10) && (ord($data) != 9))
{
switch($lastName)
{
case "REALTEAM":
//do nothing
break;

default:
if($playerStart === true)
$xmldata["$lastName"][$i] = $data;
else
$xmldata["$lastName"] = $data;
break;
}
}
}




function ParseRecGameXml($xml)
{
if( $xml === false ) return false;

global $xmldata;
global $lastName;
global $i;
global $playerStart;
$xmldata = array();
$i = -1;
$playerStart = false;


$parser = xml_parser_create();

xml_set_element_handler($parser, "startElementHandler", "endElementHandler");
xml_set_character_data_handler($parser, "cdataHandler");
if (!xml_parse($parser, $xml, true))
die(sprintf("XML error %d %d", xml_get_current_line_number($parser), xml_get_current_column_number($parser)));

return $xmldata;
}

//- (cubensis)
function UTF16toASCII( $unicode )
{
$data = "";

//---- Implemented a slightly cleaner way of doing this, which doesn't compress 0 value pairs
$i = -2;
$len = strlen( $unicode );
while( $i < $len ) $data .= $unicode[$i+=2];

return $data;
}

//- (cubensis)
function ASCIItoUTF16( $ascii )
{
$data = "";

$len = strlen( $ascii );
for( $i = 0; $i < $len; $i++ )
{
$data .= $ascii[$i];
$data .= chr(0);
}

return $data;
}

//- (cubensis)
function InsertRealCivsIntoArray( $array )
{
if( $array === false ) return false;

global $_REAL_CIV;

//---- For each player in the NAME block, try to extract their
//---- real civilization from the binary block


foreach( $array['NAME'] as $id => $name )
{
$name_search = ASCIItoUTF16($name);

$pos = strpos( $_REAL_CIV, $name_search );
$len = strlen( $name_search );

$offset = $pos + $len + 9;
$real_civ = ord($_REAL_CIV[$offset]);

$array['REALCIVILIZATION'][$id] = $real_civ;
}

return $array;
}


//- (cubensis)
function CivNameFromID( $id, $is_titans = false )
{
$titans = array(
0 => "Zeus", 1 => "Poseidon", 2 => "Hades",
3 => "Isis", 4 => "Ra", 5 => "Set",
6 => "Odin", 7 => "Thor", 8 => "Loki",
9 => "Cronos", 10 => "Oranos", 11 => "Gaia",
12 => "Random All", 13 => "Random Greek", 14 => "Random Norse",
15 => "Random Egyptian", 16 => "Random Atlantean" );

$aom = array(
0 => "Zeus", 1 => "Poseidon", 2 => "Hades",
3 => "Isis", 4 => "Ra", 5 => "Set",
6 => "Odin", 7 => "Thor", 8 => "Loki",
9 => "Random All", 10 => "Random Greek", 11 => "Random Norse",
12 => "Random Egyptian" );

return $is_titans ? $titans[$id] : $aom[$id];
}

/*
$file = 'C:\Documents and Settings\andy\My Documents\My Games\Age of Mythology\Savegame\Recorded Game 3.rcx';
//$file = 'C:\Games\Microsoft Games\Age of Mythology\savegame\Recorded Game 1.rec';

$xml = ReturnRecGameXml( $file );
$array = ParseRecGameXml( $xml );
$array = InsertRealCivsIntoArray( $array );


print_r($array);
*/
?>

62

15.11.2005, 17:42

Sagt einfach sobald ihr eine gemeinsame Final und somit gut brauchbare Lösung für den Otto-Normalspieler habt;), danke.

63

15.11.2005, 17:44

die lösung von plexiq funktionier für ottonormalspieler schon ausgezeichnet. mich treibt nur der ehrgeiz das ich ein offlinetool will ;)

@faith:
bitte editier das raus das ist eklig lang. ich hab den ganzen tag schon über diesem code gebrütet.

[edit:
ausserdem sind die dateien offensichtlich doch anders aufgebaut. zumindest konnte ich keine xml start bzw endtags wie <GameSettings> finden. entweder weil es sie nicht gibt oder weil ich vor lauter wald die bäume nicht mehr sehe. aber da das tool "as is" auch nicht mit aoe3 recs funktioniert...]

[edit2:
bei meinem tool klappt eigentlich alles, bis auf das er jeden 2. playernamen nicht findet - weil der entsprechende string in den decodierten daten nicht auffindbar ist (gameplayer0name, gameplayer1name, gameplayer2name, etc.. 1,3,5 und 7 findet er ohne probs ..)

[edit3 ^^:

Zitat


ps@zelos:~/development/workspace/aoe3rectool/ant/build$ java -jar aoe3rectool.jar /home/ps/tmp/3v3_faith_wischn_lat_vs_inc_hackl_sd_vision.age3rec

Map: New England
MapExt: randommaps.set
Player 0:
Player 1: -WW- Killy
Player 2:
Player 3: -WW-würmchen
Player 4:
Player 5: LClan Inc
Player 6:
Player 7: Player 7


das ist ein spiel von dir .. die nicht vorhandenen "Player X" muss ich noch ausblenden - die stehen aber wirklich so im file drinnen ^^

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »fast_tam« (15.11.2005, 17:53)


64

15.11.2005, 18:20

mhm ist tatsächlich ein coding problem. das sollte aber machbar sein ^^

[edit: codierungsproblem mein ich - es ist doch noch garnicht so spät ^^]

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »fast_tam« (15.11.2005, 18:50)


65

15.11.2005, 19:09

Ich habe ein ganz anderes Problem: Keine Replays!

Offenbar scheint die überwiegende Mehrzahl meiner Gegner keinen Wert darauf zu legen, so dass das Spiel immer ohne Rec startet ?(

66

16.11.2005, 12:36

es ist vollbracht. das einzige was mich noch echt wurmt ist das ich die teamID nicht so einfach herausbekomme da ich wegen diesem verschissenen (sorry^^) format einige daten wegschmeissen muss. für die technik freaks: die kodierung ist so saublöd das ich einfach alle "00" werte wegschmeisse - das bringt die daten in ein einigermaßen lesbares format.

das archiv enthält wie der vorgänger das kommandozeilenprog sowie das object welches einige public methoden zum auslesen der infos besitzt.

ps@zelos:~/development/workspace/aoe3rectool/ant/build$ java -jar aoe3rectool.jar /home/ps/tmp/test.age3rec

beispielausgabe:

Zitat


Map: New England
MapExt: randommaps.set
Number of Players: 6
Player 1: [ Dutch ] -WW- Killy
Player 2: [ Ottomans ] CF CF_Faithhealer
Player 3: [ Portuguese ] -WW- würmchen
Player 4: [ Germans ] LClan BeN_de
Player 5: [ Ottomans ] LClan Inc
Player 6: [ French ] NoX SD_VisionSLR


ich komme die nächsten tage wohl nicht dazu daraus ein endusertaugliches programm zu machen welches die info dann auch verwertet indem es datein umbenennt^^
am wochenende eventuell.
»fast_tam« hat folgende Datei angehängt:
  • aoe3rectool.zip (5,19 kB - 87 mal heruntergeladen - zuletzt: 14.10.2023, 15:26)

Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von »fast_tam« (16.11.2005, 16:16)


67

16.11.2005, 15:29

hmmmm - die teamids machen mir kopfschmerzen. es gibt zwar ein derartiges feld aber das ist fast immer gleich. ich fürchte die teamid steht nur drin wenn es fixe teams waren, bei random teams wird keine teamid vergeben x_X

68

18.11.2005, 10:37

Ich hab mein mod für AoM rec games auch für Age3 rec games fertig. Inklusive der tatsächlichen TeamId, wer den Code will einfach melden.

70

18.11.2005, 14:43

Zitat

Original von DoC_Santonian
Ich hab mein mod für AoM rec games auch für Age3 rec games fertig. Inklusive der tatsächlichen TeamId, wer den Code will einfach melden.


hier! *meld*
vielleicht hast du das schöner gelöst als ich ;)