View Single Post
djazz djazz's Avatar

JCF Member

Joined: Feb 2009

Posts: 257

djazz is OFF DA CHARTdjazz is OFF DA CHARTdjazz is OFF DA CHART

Jan 2, 2010, 04:50 PM
djazz is offline
Reply With Quote
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:
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.

-changed the behavior for Generators
-some small changes in the parameter loop
-rearranged the code

-add error handling

// If you are not using PHP5, then use this function
if(!function_exists('str_split')) {
str_split($string,$string_length=1) {
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);

getJcsIni($path) {
// Open the JCS.ini file for reading
$handle fopen($path"r");
// Init the main JCSini variable (local)
// Init the read variable, when true: put data in the JCSini variable
// If the file could be opened for reading, continue
if ($handle) {
// Index for each EventID
// 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($handle4096);
// 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
// End WHILE-loop
        // Close the file
// 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
// Init the EventIndex variable
// 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($val04));
// 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
// Store the name, trim away NULLs and white spaces
// Store the short name, that is displayed on the event in JCS. Rows are separated by a "\n" (linebreak)
// Store difficulty. 0 = Normal, 1 = Easy, 2 = Hard, 3 = MP only
// 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
// Init a temporary variable, to store all data of the final parameters
// Init the final result variableof the parameters, fill with NULL if some parameter don't exists
// Parameter index holder
// Init variable that holds the last position for reading bitfields
// 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
// Store the current parameter's name
// Store the value of the current parameter
// This IF-statement handles negative bitfield lengths
if($param[$p][1] < && $params[$p]['value'] >= bindec("".pow(10,intval(str_replace("-","",$param[$p][1]))-1)))
// If current parameter is negative, store it's value again
// Change the last position for reading, going on next parameter
// Store the temporary data to the Event variable
// Increment the index with 1
// End FOR-loop
        // Do this if the event is a Generator
if($Event[$i]['generator']) {
// Re-store the new EventID
// Re-store the new name
// Re-store the new shortname
// End Generator IF-statement
        // Increment the EventIndex variable with 1
// 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

// Store the J2L file header
$header fread($f262);

// Init the variable where it store compressed sized
$offsets = array();

// Store the sizes in the offsets variable
list(,$offsets['info_c']) = unpack('V'substr($header2304));
$offsets['evnt_c']) = unpack('V'substr($header2384));

// 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        

// Make the actual parsing of the eventmap stream

// Output the EventMap
If you would find any errors or bugs, please report them! Enjoy!

The first working code was made in three hours!
WebJCS 2 (new and in progress)
WebJCS 1 (old but complete)
SGIP Simple Games in Progress list
Level Packer v2 - With a GUI!
PHP Tileset Compiler

Last edited by djazz; Jan 3, 2010 at 05:17 AM. Reason: Changed levelpath