A better J2L Event reader/parser
Aah, I haven't seen those pages before, thanks!
That solution is much more simpler than mine..
Anyway, it was so interesting that I made a PHP script to get all the event data and it's parameters.
It's heavily commented, so you easy understand what it does :P
PHP Code:
<?php /* This code is made by DJazzy of J2NSM, and a few lines are from Stijn's J2L reader PHP-class. Thanks to Neobeo, who made the research, and to Jerry for his questions.
Changelog: -changed the behavior for Generators -some small changes in the parameter loop -rearranged the code
Todo: -add error handling */
// If you are not using PHP5, then use this function if(!function_exists('str_split')) { function str_split($string,$string_length=1) { if(strlen($string)>$string_length || !$string_length) { do { $c = strlen($string); $parts[] = substr($string,0,$string_length); $string = substr($string,$string_length); } while($string !== false); } else { $parts = array($string); } return $parts; } }
function getJcsIni($path) { // Open the JCS.ini file for reading $handle = fopen($path, "r"); // Init the main JCSini variable (local) $JCSini=array(); // Init the read variable, when true: put data in the JCSini variable $read=false; // If the file could be opened for reading, continue if ($handle) { // Index for each EventID $i=0; // Start the while loop, loops until End Of File is found while (!feof($handle)) { // Store data buffer, read max 4096 bytes, a row in the file $buffer = fgets($handle, 4096); // If it find the row with "Events" in it, set read to true, index to 1 and continue to next loop/row if(strpos($buffer,'Events') && strlen($buffer)==10 && $read==false) {$i=1;$read=true;continue;} // If read is true, start store the event info in the JCSini variable if($read==true) {$JCSini[$i] = explode("|",preg_replace('/(\d+)\=/i','',$buffer));} // Only store 255 variables if($i==255) break; // Increment index with 1 $i++; } // End WHILE-loop // Close the file fclose($handle); // Return JCSini return $JCSini; } // End IF-statement // If it couldn't open file for reading, return FALSE return false; } // End of function function parseEventMap($eventdata,$JCSini) { // Split up the EventMap using str_split (PHP5) $eventdata = str_split($eventdata,4); // The main variable containing all events $Event=array(); // Init the EventIndex variable $i=0; // Main loop. Loop through each event foreach($eventdata as $val) { // If there are no event, or an event with ID 0, skip this and continue on next if(ord(substr($val,0,1))==0) {$i++;continue;} // Get the field of bits list(,$bitfield) = unpack('V', substr($val, 0, 4)); // Make it 32-bit, add zeros until it is 32-bit length $fullBitfield = str_pad(decbin($bitfield),32,"0",STR_PAD_LEFT); // Store the Event ID $Event[$i]['id']=bindec(substr($fullBitfield,-8,8)); // Store the name, trim away NULLs and white spaces $Event[$i]['name']=trim($JCSini[$Event[$i]['id']][0]); // Store the short name, that is displayed on the event in JCS. Rows are separated by a "\n" (linebreak) $Event[$i]['shortname']=trim($JCSini[$Event[$i]['id']][3]).((trim($JCSini[$Event[$i]['id']][4])=="")?"":"\n".trim($JCSini[$Event[$i]['id']][4]).""); // Store difficulty. 0 = Normal, 1 = Easy, 2 = Hard, 3 = MP only $Event[$i]['difficulty']=bindec(substr($fullBitfield,-10,2)); // Store the illuminate checkbox's value $Event[$i]['illuminate']=(substr($fullBitfield,-11,1)==1)? true : false; // Stores true if the event is an generator (event 216), else false $Event[$i]['generator']=($Event[$i]['id']==216)? true : false; // Init a temporary variable, that will contain the bitfields names and lengths $param=array(); // Init a temporary variable, to store all data of the final parameters $params=array(); // Init the final result variableof the parameters, fill with NULL if some parameter don't exists $Event[$i]['params']=array(NULL,NULL,NULL,NULL); // Parameter index holder $p=0; // Init variable that holds the last position for reading bitfields $lastpos=-12; // Loop through each parameter for($j=5;$j <= 8; $j++) { // If there was no parameter at this id, break the loop if(!($JCSini[$Event[$i]['id']][$j])) {$param[$j]=null;break;} // Split up name and the bitfield length number $param[$p]=explode(":",$JCSini[$Event[$i]['id']][$j]); // Store the current parameter's name $params[$p]['name']=$param[$p][0]; // Store the value of the current parameter $params[$p]['value']=bindec(substr($fullBitfield,$lastpos-intval(str_replace("-","",$param[$p][1])),intval(str_replace("-","",$param[$p][1])))); // This IF-statement handles negative bitfield lengths if($param[$p][1] < 0 && $params[$p]['value'] >= bindec("".pow(10,intval(str_replace("-","",$param[$p][1]))-1))) // If current parameter is negative, store it's value again $params[$p]['value']=-(bindec(pow(10,intval(str_replace("-","",$param[$p][1]))))-$params[$p]['value']); // Change the last position for reading, going on next parameter $lastpos-=intval(str_replace("-","",$param[$p][1])); // Store the temporary data to the Event variable $Event[$i]['params'][$p]=$params[$p]; // Increment the index with 1 $p++; } // End FOR-loop // Do this if the event is a Generator if($Event[$i]['generator']) { // Re-store the new EventID $Event[$i]['id']=$params[0]['value']; // Re-store the new name $Event[$i]['name']=trim($JCSini[$Event[$i]['id']][0]); // Re-store the new shortname $Event[$i]['shortname']=trim($JCSini[$Event[$i]['id']][3]).((trim($JCSini[$Event[$i]['id']][4])=="")?"":"\n".trim($JCSini[$Event[$i]['id']][4]).""); } // End Generator IF-statement // Increment the EventIndex variable with 1 $i++; } // End FOREACH-loop // Return the Event variable return $Event; } // End function
// Path to your JCS.ini $JCSiniPath = "JCS.ini";
// Read, parse and store it in JCSini $JCSini = getJcsIni($JCSiniPath);
// Enter the path where your J2L file is located $infile = "level.j2l";
// Open file for reading $f=fopen($infile,"r");
// Store the J2L file header $header = fread($f, 262);
// Init the variable where it store compressed sized $offsets = array();
// Store the sizes in the offsets variable list(,$offsets['info_c']) = unpack('V', substr($header, 230, 4)); list(,$offsets['evnt_c']) = unpack('V', substr($header, 238, 4));
// Read the levelinfo stream (needed to move the fread file pointer) $LevelInfo = gzuncompress(fread($f, $offsets['info_c']));
// Read the actual event stream $EventData = gzuncompress(fread($f, $offsets['evnt_c']));
// Close the file fclose($f);
// Make the actual parsing of the eventmap stream $events=parseEventMap($EventData,$JCSini);
// Output the EventMap print_r($events); ?>
If you would find any errors or bugs, please report them! Enjoy!
The first working code was made in three hours!
Last edited by djazz; Jan 3, 2010 at 06:17 AM.
Reason: Changed levelpath
|