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, 05: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:
<?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($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
            
$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($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
        
$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] < && $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($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));
list(,
$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        
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!
__________________
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 06:17 AM. Reason: Changed levelpath