Convert Minecraft server world files into MCserver world files.
#31
Nice work. You can upload it to the SVN if you want me to take a loot at it
Reply
Thanks given by:
#32
(10-30-2011, 06:40 AM)FakeTruth Wrote: Nice work. You can upload it to the SVN if you want me to take a loot at it

That'd be great, I'll do that now. I have to warn you it's kind of messy, I have comments and commented out test lines everywhere.

The plan was to clean it up as I go along and do a final clean up before it was actually done.
Apparently, svn -remove FILE deletes the local copy as well as removes it from the svn list. Thank god for my hourly snapshot directory. >.>

I'll have it uploaded in a min. Just adding a few last minute comments... again. lol
R20 is up with what I've done with the converter.

http://code.google.com/p/mc-server/source/detail?r=20

It's ugly. Angel

I also left #include <iostream>
and a few commented out cout's in cChunkMap.cpp
:s
Reply
Thanks given by:
#33
Hey, mind uploading the php as well? Even if he won't be able to get it running fast enough, he wants to give it a try, he hasn't been able to do as much PHP as he'd like recently and this one sounds fun.
Reply
Thanks given by:
#34
(10-30-2011, 07:48 AM)necavi Wrote: Hey, mind uploading the php as well? Even if he won't be able to get it running fast enough, he wants to give it a try, he hasn't been able to do as much PHP as he'd like recently and this one sounds fun.

Sure thing.

It's simple and I didn't really make any comments. It was meant to just be a proof of concept sort of thing. It needs a LOT of memory to run and is ridiculously slow and inefficient. (kind of like the official minecraftBig Grin )[/code]

denotch.php:
Code:
<?php
   $mtime = microtime();
   $mtime = explode(" ",$mtime);
   $mtime = $mtime[1] + $mtime[0];
   $starttime = $mtime;
include('nbtparse.php');

function coord_to_bin($coord) {
    if ($coord < 0 ) {
        $coord_bin = '';
        $abs_coord = abs($coord);

        if ($abs_coord < 256 ) {
                $Pos_value = -(pow(2, 8) - $coord);
                $coord_bin .= pack("C*", $Pos_value);
                $coord_bin .= pack("C*", 255);
                $coord_bin .= pack("C*", 255);
                $coord_bin .= pack("C*", 255);
            } elseif ($abs_coord < 65536 ) {
                $first  = floor($coord / 256);
                $second = $coord - ($first * 256);
                $first  = -(pow(2, 8) - $first);
                $second = -(pow(2, 8) - $second);
                $coord_bin .= pack("C*", $second);
                $coord_bin .= pack("C*", $first);
                $coord_bin .= pack("C*", 255);
                $coord_bin .= pack("C*", 255);
                //$false_header .= pack("C*", 0);
            } elseif ($abs_coord < 16777216 ) {
                $first  = floor($coord / (256*256));
                $second = floor( ( $coord - ( $first * ( 256*256 ) ) ) / 256 );
                $third  = $coord - ($second * 256) - ( $first * ( 256*256 ) );
                $first  = -(pow(2, 8) - $first);
                $second = -(pow(2, 8) - $second);
                $third  = -(pow(2, 8) - $third);
                $coord_bin .= pack("C*", $third);
                $coord_bin .= pack("C*", $second);
                $coord_bin .= pack("C*", $first);
                $coord_bin .= pack("C*", 255);
            } else {
                echo 'error 1a at: ' . $i . ' with coord: ' . $coord;
            }
    } elseif ($coord < 256 ) {
        $coord_bin .= pack("C*", $coord);
        $coord_bin .= pack("C*", 0);
        $coord_bin .= pack("C*", 0);
        $coord_bin .= pack("C*", 0);
    } elseif ($coord < 65536 ) {
        $first  = floor($coord / 256);
        $second = $coord - ($first * 256);
        $coord_bin .= pack("C*", $second);
        $coord_bin .= pack("C*", $first);
        $coord_bin .= pack("C*", 0);
        $coord_bin .= pack("C*", 0);
        //$false_header .= pack("C*", 0);
    } elseif ($coord < 16777216 ) {
        $first  = floor($coord / (256*256));
        $second = floor( ( $coord - ( $first * ( 256*256 ) ) ) / 256 );
        $third  = $coord - ($second * 256) - ( $first * ( 256*256 ) );

        $coord_bin .= pack("C*", $third);
        $coord_bin .= pack("C*", $second);
        $coord_bin .= pack("C*", $first);
        $coord_bin .= pack("C*", 0);
    } elseif ($coord < 4294967296 ) {
        $first  = floor($coord / (256*256*256));
        $second = floor( ( $coord - ( $first * ( 256*256*256 ) ) ) / (256 * 256) );
        $third  = floor( ( $coord - ( $first * ( 256*256*256 ) ) - ( $second * ( 256*256 ) ) ) / 256 );
        $fourth = $coord - ( $first * ( 256*256*256 ) ) - ( $second * ( 256*256 ) ) - ( $third * ( 256 ) );
        $coord_bin .= pack("C*", $fourth);
        $coord_bin .= pack("C*", $third);
        $coord_bin .= pack("C*", $second);
        $coord_bin .= pack("C*", $first);
    } else {
        echo 'error 1b at: ' . $i . ' with coord: ' . $coord;
    }
    return($coord_bin);
}



// open this directory
$myDirectory = opendir("C:\\xampp\\htdocs\\minecraft\\region");

// get each entry
while($entryName = readdir($myDirectory)) {
    $dirArray[] = $entryName;
    //echo $entryName;
}

// close directory
closedir($myDirectory);

// sort 'em
sort($dirArray);

foreach ($dirArray as $dir) {
    //echo "<br />" . $dir;
    
}


//$my_file = file_get_contents("C:\\xampp\\htdocs\\minecraft\\region\\r.0.0.mcr");
//echo $my_file;



$filename = "C:\\xampp\\htdocs\\minecraft\\region\\r.0.0.mcr";
$handle = fopen($filename, "rb");
$contents = fread($handle, filesize($filename));
fclose($handle);
//echo filesize($filename);
$number = unpack("C*", $contents);
//print_r($number);

$chunk_array = array();



$pak_file  = '';
$pak_file .= pack("C*", 1); // Pakversion 1
$pak_file .= pack("C*", 1); // Chunkversion 1




$i = 1;

while ($i < 4096) {

    $num1 = $number[$i+0];
    $num2 = $number[$i+1];
    $num3 = $number[$i+2];
    $num4 = $number[$i+3];

    $total_offset = ($num1*256*256) + ($num2*256) + $num3;


    

    $chunk_start_offset = $total_offset*4096 + 1;
    $chunk_end_offset     = $chunk_start_offest+($num4*4096);


    $chunk_data_length = ($number[$chunk_start_offset]*256*256*256) + ($number[$chunk_start_offset+1]*256*256) + ($number[$chunk_start_offset+2]*256) + $number[$chunk_start_offset+3];
    $chunk_data_comptp = $number[$chunk_start_offset+4];
    $chunk_data        = '';

    //echo $chunk_data_length;
    //echo $num1;
    //echo $num1;
    //echo $num1;
    
    //echo $total_offset;
    
    $cat = 0;
    $re = $chunk_start_offset+5;
    $ri = 1;
    while ($re < (($chunk_start_offset + $chunk_data_length)+4) ) {
        $chunk_data .= pack("C", $number[$re]);
        $re++;
        $ri++;
        $cat ++;
    }
    //echo $number[$re];
    //exit();
    $deflate_chunk_data = gzuncompress($chunk_data);
    //$alpha_nbt = gzencode($deflate_chunk_data);



    //$filename = "php://temp//tmp.nbt";
    $filename = tempnam(sys_get_temp_dir(), "temp");
    $handle = fopen($filename, "wb");
    fwrite($handle, $deflate_chunk_data);
    //fclose($handle);


    $nbt = new nbt();
    $nbt->verbose = false;
    //$nbt->loaddata($deflate_chunk_data);
    $nbt->loadFile($filename);
    //$nbt->loadFile("tmp.nbt");
    $nbt->writeFile($tmp = tempnam(sys_get_temp_dir(), "nbt"));
    $nbt_array = $nbt->root[0];
    echo '<pre>';
    print_r($nbt_array);
    echo '</pre>';
    exit();
    $nbt_Data_array = $nbt_array['value'][0]['value'][0]['value'];
    $nbt_Entities_array = $nbt_array['value'][0]['value'][1]['value'];
    $nbt_LastUpdate_value = $nbt_array['value'][0]['value'][2]['value'];
    $nbt_xPos_value = $nbt_array['value'][0]['value'][3]['value'];
    $nbt_zPos_value = $nbt_array['value'][0]['value'][4]['value'];
    $nbt_TileEntities_array = $nbt_array['value'][0]['value'][5]['value'];
    $nbt_TerrainPopulated_value = $nbt_array['value'][0]['value'][6]['value'];
    $nbt_SkyLight_array = $nbt_array['value'][0]['value'][7]['value'];
    $nbt_HeightMap_array = $nbt_array['value'][0]['value'][8]['value'];
    $nbt_BlockLight_array = $nbt_array['value'][0]['value'][9]['value'];
    $nbt_Blocks_array = $nbt_array['value'][0]['value'][10]['value'];

    $nbt_Block_bin = '';
    foreach ($nbt_Blocks_array as $nbt_Blocks) {
        $nbt_Block_bin .= pack("C*", $nbt_Blocks);
    }

    foreach ($nbt_Data_array as $nbt_Data) {
        $nbt_Block_bin .= pack("C*", $nbt_Data);
    }

    foreach ($nbt_BlockLight_array as $nbt_BlockLight) {
        $nbt_Block_bin .= pack("C*", $nbt_BlockLight);
    }

    foreach ($nbt_SkyLight_array as $nbt_SkyLight) {
        $nbt_Block_bin .= pack("C*", $nbt_SkyLight);
    }

    $uncompressed_chunk_size  = strlen($nbt_Block_bin);
    $Compressed_Block_bin    = gzcompress($nbt_Block_bin);
    $compressed_chunk_size    = strlen($Compressed_Block_bin);


    $false_header = '';



    $false_header = coord_to_bin($nbt_xPos_value) . coord_to_bin($nbt_zPos_value) . coord_to_bin($compressed_chunk_size) . coord_to_bin($uncompressed_chunk_size);


    //$chunk_array[$i]['compressed_chunk_size']   = $compressed_chunk_size;
    //$chunk_array[$i]['uncompressed_chunk_size'] = $uncompressed_chunk_size;
    $chunk_array[$i]['Compressed_Block_bin']    = $Compressed_Block_bin;
    //$chunk_array[$i]['xCoord']                  = $nbt_xPos_value;
    //$chunk_array[$i]['zCoord']                  = $nbt_zPos_value;
    $chunk_array[$i]['false_header']            = $false_header;



    $i = $i+4;
}


$numchunks = 0;
$pakheader = '';
$pakblocks = '';

foreach ($chunk_array as $chunk) {
    $numchunks++;
    $pakblocks .= $chunk['Compressed_Block_bin'];
    $pakheader .= $chunk['false_header'];
}
$chunk_array = array();


if ($numchunks < 256 ) {
    $pak_file .= pack("C*", $numchunks);
    $pak_file .= pack("C*", 0);
} elseif ($numchunks < 1025 ) {
    $first  = floor($numchunks / 256);
    $second = $numchunks - ($first * 256);
    $pak_file .= pack("C*", $second);
    $pak_file .= pack("C*", $first);
} else {
    echo 'error 12x';
    exit();
}


$pak_file .= $pakheader;
$pak_file .= $pakblocks;





$filename = "C:\\xampp\\htdocs\\minecraft\\world\\X0_Z0.pak";
$handle = fopen($filename, "wb");

fwrite($handle, $pak_file);

fclose($handle);




$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);
echo "This page was created in ".$totaltime." seconds";


?>

nbtparse.php
Code:
<?php
/**
* Class for reading in NBT-format files.
* Based on the work of Justin Martin <frozenfire@thefrozenfire.com>.
* Altered to use BCMath rather than GMP, because BCMath comes by default with PHP >= 4.0.4, GMP never did.
*
* @author  Julian Rupp <mail@nuclearflux.net>
* @version 1.1
*
* Dependencies:
*  PHP 4.3+ (5.3+ recommended)
*  BCMath Extension
*/

extension_loaded("bcmath") or die("The NBT class requires the BCMath extension.");
class NBT {
    public $root = array();
    
    public $verbose = false;
    
    const TAG_END = 0;
    const TAG_BYTE = 1;
    const TAG_SHORT = 2;
    const TAG_INT = 3;
    const TAG_LONG = 4;
    const TAG_FLOAT = 5;
    const TAG_DOUBLE = 6;
    const TAG_BYTE_ARRAY = 7;
    const TAG_STRING = 8;
    const TAG_LIST = 9;
    const TAG_COMPOUND = 10;
    
    public function loadFile($filename) {
        //$fp = fopen("compress.zlib://{$filename}", "rb");
        $fp = fopen($filename, "rb");
        $this->traverseTag($fp, $this->root);
        return end($this->root);
    }
    
    public function writeFile($filename) {
        //$fp = fopen("compress.zlib://{$filename}", "wb");
        $fp = fopen($filename, "wb");
        foreach($this->root as $rootTag) if(!$this->writeTag($fp, $rootTag)) return false;
        return true;
    }
    
    public function purge() {
        $this->root = array();
    }
    
    protected function _signedlong2intstring($bin)
    {
        if(strlen($bin) != 8)
        {
            return(false);
        }
        list(,$firstHalf) = unpack("N", substr($bin,0,4));
        list(,$secondHalf) = unpack("N", substr($bin,4,4));
        $value = bcadd($secondHalf, bcmul($firstHalf, "4294967296"));
        if(bccomp($value, bcpow(2, 63)) >= 0) $value = bcsub($value, bcpow(2, 64));
        return($value);
    }
    
    protected function _intstring2signedlong($string)
    {
        #todo: input check

        $sbt = array();
        $sby = array();
        $ret = '';
        $c_remaining = $string;
        $c_mod = 0;

        for($i=0;$i<64;$i++)
        {
            $sbt[$i] = 0;
        }

        for($mp=63,$i=0;$mp>=0,$i<64;$mp--,$i++)
        {
            $c_mod = bcdiv($c_remaining,bcpow(2,$mp));
            $c_remaining = bcmod($c_remaining,bcpow(2,$mp));
            if(bccomp($c_mod,"1") >= 0)
            {
                $sbt[$i] = 1;
            }

            if(bccomp($c_remaining,"0") == 0)
            {
                break;
            }
        }

        for($i=0;$i<8;$i++)
        {
            $bin = '';
            for($j=0;$j<8;$j++)
            {
                $os = ($i*8)+$j;
                $bin .= $sbt[$os];
            }
            $sby[$i] = chr(bindec($bin));
        }
        $ret = implode($sby);
        if(bccomp($ret, bcpow(2, 63)) >= 0)
        {
            $ret = bcsub($ret, bcpow(2, 64));
        }

        return($ret);
    }
    
    protected function traverseTag($fp, &$tree) {
        if(feof($fp)) return false;
        $tagType = $this->readType($fp, self::TAG_BYTE); // Read type byte.
        if($tagType == self::TAG_END) {
            return false;
        } else {
            if($this->verbose) $position = ftell($fp);
            $tagName = $this->readType($fp, self::TAG_STRING);
            $tagData = $this->readType($fp, $tagType);
            if($this->verbose) echo "Reading tag \"{$tagName}\" at offset {$position}".PHP_EOL;
            $tree[] = array("type"=>$tagType, "name"=>$tagName, "value"=>$tagData);
            return true;
        }
    }
    
    protected function writeTag($fp, $tag) {
        if($this->verbose) echo "Writing tag \"{$tag["name"]}\" of type {$tag["type"]}".PHP_EOL;
        return $this->writeType($fp, self::TAG_BYTE, $tag["type"]) && $this->writeType($fp, self::TAG_STRING, $tag["name"]) && $this->writeType($fp, $tag["type"], $tag["value"]);
    }
    
    protected function readType($fp, $tagType) {
        switch($tagType) {
            case self::TAG_BYTE: // Signed byte (8 bit)
                list(,$unpacked) = unpack("C", fread($fp, 1));
                //return fread($fp, 1);
                return $unpacked;
            case self::TAG_SHORT: // Signed short (16 bit, big endian)
                list(,$unpacked) = unpack("n", fread($fp, 2));
                if($unpacked >= pow(2, 15)) $unpacked -= pow(2, 16); // Convert unsigned short to signed short.
                return $unpacked;
            case self::TAG_INT: // Signed integer (32 bit, big endian)
                list(,$unpacked) = unpack("N", fread($fp, 4));
                if($unpacked >= pow(2, 31)) $unpacked -= pow(2, 32); // Convert unsigned int to signed int
                return $unpacked;
            case self::TAG_LONG: // Signed long (64 bit, big endian)
                return($this->_signedlong2intstring(fread($fp, 8)));
            case self::TAG_FLOAT: // Floating point value (32 bit, big endian, IEEE 754-2008)
                list(,$value) = (pack('d', 1) == "\77\360\0\0\0\0\0\0")?unpack('f', fread($fp, 4)):unpack('f', strrev(fread($fp, 4)));
                return $value;
            case self::TAG_DOUBLE: // Double value (64 bit, big endian, IEEE 754-2008)
                list(,$value) = (pack('d', 1) == "\77\360\0\0\0\0\0\0")?unpack('d', fread($fp, 8)):unpack('d', strrev(fread($fp, 8)));
                return $value;
            case self::TAG_BYTE_ARRAY: // Byte array
                $arrayLength = $this->readType($fp, self::TAG_INT);
                $array = array();
                for($i = 0; $i < $arrayLength; $i++) $array[] = $this->readType($fp, self::TAG_BYTE);
                return $array;
            case self::TAG_STRING: // String
                if(!$stringLength = $this->readType($fp, self::TAG_SHORT)) return "";
                $string = utf8_decode(fread($fp, $stringLength)); // Read in number of bytes specified by string length, and decode from utf8.
                return $string;
            case self::TAG_LIST: // List
                $tagID = $this->readType($fp, self::TAG_BYTE);
                $listLength = $this->readType($fp, self::TAG_INT);
                if($this->verbose) echo "Reading in list of {$listLength} tags of type {$tagID}.".PHP_EOL;
                $list = array("type"=>$tagID, "value"=>array());
                for($i = 0; $i < $listLength; $i++) {
                    if(feof($fp)) break;
                    $list["value"][] = $this->readType($fp, $tagID);
                }
                return $list;
            case self::TAG_COMPOUND: // Compound
                $tree = array();
                while($this->traverseTag($fp, $tree));
                return $tree;
        }
    }
    
    protected function writeType($fp, $tagType, $value) {
        switch($tagType) {
            case self::TAG_BYTE: // Signed byte (8 bit)
                return fwrite($fp, pack("c", $value));
            case self::TAG_SHORT: // Signed short (16 bit, big endian)
                if($value < 0) $value += pow(2, 16); // Convert signed short to unsigned short
                return fwrite($fp, pack("n", $value));
            case self::TAG_INT: // Signed integer (32 bit, big endian)
                if($value < 0) $value += pow(2, 32); // Convert signed int to unsigned int
                return fwrite($fp, pack("N", $value));
            case self::TAG_LONG: // Signed long (64 bit, big endian)
                $data = $this->_intstring2signedlong($value);
                return fwrite($fp, $data);
            case self::TAG_FLOAT: // Floating point value (32 bit, big endian, IEEE 754-2008)
                return fwrite($fp, (pack('d', 1) == "\77\360\0\0\0\0\0\0")?pack('f', $value):strrev(pack('f', $value)));
            case self::TAG_DOUBLE: // Double value (64 bit, big endian, IEEE 754-2008)
                return fwrite($fp, (pack('d', 1) == "\77\360\0\0\0\0\0\0")?pack('d', $value):strrev(pack('d', $value)));
            case self::TAG_BYTE_ARRAY: // Byte array
                return $this->writeType($fp, self::TAG_INT, count($value)) && fwrite($fp, call_user_func_array("pack", array_merge(array("c".count($value)), $value)));
            case self::TAG_STRING: // String
                $value = utf8_encode($value);
                return $this->writeType($fp, self::TAG_SHORT, strlen($value)) && fwrite($fp, $value);
            case self::TAG_LIST: // List
                if($this->verbose) echo "Writing list of ".count($value["value"])." tags of type {$value["type"]}.".PHP_EOL;
                if(!($this->writeType($fp, self::TAG_BYTE, $value["type"]) && $this->writeType($fp, self::TAG_INT, count($value["value"])))) return false;
                foreach($value["value"] as $listItem) if(!$this->writeType($fp, $value["type"], $listItem)) return false;
                return true;
            case self::TAG_COMPOUND: // Compound
                foreach($value as $listItem) if(!$this->writeTag($fp, $listItem)) return false;
                if(!fwrite($fp, "\0")) return false;
                return true;
        }
    }
}
?>


You could use this to convert the world files (minus the entities), but it would take about 10 hours per 2000x2000 world to convert. I'm not even sure what happens if the file reads from an mcr that doesn't have 1024 chunks. The c++ program looks for that and works with it. The php program is dumb to it. There's also no organization of the chunk, it simple takes them from the mcr and puts them into the pak. I think FakeTruth's server reorders them when it reads the pak for the first time. I'm not sure though. There's definitely a small lag spike when the MCServer reads the created pak for the first time. Subsequent reads don't have the spike. I haven't even bothered to see if MCServer changes them after reading them. lol
Reply
Thanks given by:
#35
So I'm looking at your code, and I'm trying to understand what the hell is going on in the first couple of lines you're actually reading the file and I didn't get it. So I look up the mcr file definition on the wiki, and I see this table and I finally understand what's going on
[Image: 30119420283-orig.png]
But seriously... WHAT THE FUCK. Why the hell does he want to cripple the shit out of an integer (4 bytes) to save a single byte per chunk.. I mean.. come on..
Reply
Thanks given by:
#36
(10-30-2011, 09:47 AM)FakeTruth Wrote: So I'm looking at your code, and I'm trying to understand what the hell is going on in the first couple of lines you're actually reading the file and I didn't get it. So I look up the mcr file definition on the wiki, and I see this table and I finally understand what's going on
[Image: 30119420283-orig.png]
But seriously... WHAT THE FUCK. Why the hell does he want to cripple the shit out of an integer (4 bytes) to save a single byte per chunk.. I mean.. come on..

I'm pretty sure Notch is a huge fan of Ruth Goldberg.

The 4th byte isn't even needed. It's an estimate of how large the chunk is which doesn't even matter. There's a lot of junk and empty data in an MCR.

You have to go to the chunk's offset which is a calculation of (the big-endian value of the first three bytes * 4096). Then the first few bytes there give you the actual size of the chunk as well as the compress method employed. Right after that there's either junk data, empty data, or a mix of the two until you get to the next chunk's offset.

After decompression the data collected. The compressed chunks are stored in the exact same method he used in alpha, the nbt format.

It's a huge mess. Your way makes so much more sense. The program I created loads the uncompressed block data into the char array BlockData of DestSize size. That data needs to be parsed to pull out the NBT information. I'm in the process of working on my own parser, but if yours will work then that will save some time. Big Grin

I can understand and parse NBT data by hand (what a PITA), now I just need to turn that into C++ code.

At some point I'm going to have to go through and figure out all the possible entities his NBT data can store so I can convert them to your JSON format, right now the neither program I made does that. It just transfers block data, meta data, skylight, and block light.

I'm happy to explain any part of the program and why I did what I did. Some of what I did is because of my lack of C++ knowledge, some is because I couldn't think of other ways to do it. I usually go back and rewrite a working program to be "better" after I actually get it doing what I want. You're looking at a half finished mess of mine. lol. It's a work in progress, a very rough draft. I try things inside the code I'm working with, write down notes, whatever. That gets removed when the program gets finished. Though I usually save some of that old data for future reference on my own PC.
Reply
Thanks given by:
#37
Well good job getting it to work.

I see you're not exactly using the fread() function to its full potentialTongue
Code:
char temparr[compdlength]; //can't get fread to read more than one char at a time into a char array... so that's what I'll do.  :(    At least it works.
int re = 0;
char tempbyte = 0;
while (re < compdlength) { //loop through file and read contents into char array a byte at a time.
    if( fread( &tempbyte, sizeof(tempbyte), 1, f) != 1 ) { cout << "ERROR rf22 READING FROM FILE " << SourceFile; fclose(f); return false; }
    temparr[re] = tempbyte;
    re++;
    frloc++;
}

Allow me to explain how you might want to use it instead.

You created the array temparr with exactly the amount of bytes you want to read and store in it. In C++ this translates to a stream of bytes that are all placed after each other in memory, so if you know the beginning of that stream (memory address) you can fill all the bytes in one go with a single fread() call.
The first argument of fread() takes a memory address (the & sign gets the memory address of a variable) to read the data into, the second argument takes the amount of bytes you want to read (this should never exceed the amount of bytes you have reserved for storage: temparr), the third argument takes how many times you want to read this data (I don't really understand why, I just always use 1) and the last argument takes the file handle.

Now if you know this, you can change the above code into something compacter and much faster
Code:
char temparr[compdlength];
if( fread( chartemparr, compdlength, 1, f) != 1 ) { /*error out*/ }

You see I don't use the & sign, this is because the variable for an array IS a memory address, and any number between square brackets ( [ ] ) simply give an offset.

I hope this gives you a better understanding of how C++ worksTongue
Reply
Thanks given by:
#38
Thanks for the info, I must have spent 4 hours trying to get that to work.

You can see this is commented out because it didn't work:
//if( fread( comp_data, compdlength, sizeof(unsigned char), f) != 1 ) { cout << "ERROR 1234 READING FROM FILE " << SourceFile <<endl; fclose(f); return false; } //actual compressed chunk data


and variations I tried:

fread( comp_data, sizeof(unsigned char), compdlength, f)
fread( comp_data, compdlength, sizeof(unsigned char), f)
fread( &comp_data, sizeof(unsigned char), compdlength, f)
fread( &comp_data, compdlength, sizeof(unsigned char), f)
fread( *comp_data, sizeof(unsigned char), compdlength, f)
fread( *comp_data, compdlength, sizeof(unsigned char), f)
fread( comp_data, 1, compdlength, f)
fread( comp_data, compdlength, 1, f)
fread( &comp_data, 1, compdlength, f)
fread( &comp_data, compdlength, 1, f)
fread( *comp_data, s1, compdlength, f)
fread( *comp_data, compdlength, 1, f)

I also tried hard coding different value for compdlength. The only way I could get it to work was byte by byte. It was a nightmare and I don't understand why it wouldn't work. I tried unsigned char, signed car, strings, etc.

I kept getting segmentation errors, ERROR 1234 READING FROM FILE, or sometimes it would would just do nothing. I have no clue why I couldn't get it to work. The way I originally had it looked like what you had.


I have NO clue why it wasn't working before, but I just changed it to this and now it's working just fine. IT must have been something else in the code causing the problem. Sad (It was also sometime between 1:00 AM and 5:00 AM that I was working on it.)

Code:
char temparr[compdlength]; //can't get fread to read more than one char at a time into a char array... so that's what I'll do.  :(    At least it works.
                                if( fread( temparr, compdlength, 1, f) != 1 ) { cout << "ERROR rf22 READING FROM FILE " << SourceFile; fclose(f); return false; }
                                frloc = frloc + compdlength;


ehh, same sort of problems I faced while learning PHP. You spend hours beating your head against the table and pulling out your hair until you find the moment of retardation you placed into the code.
Reply
Thanks given by:
#39
At least you probably won't forget how it DOES work now ^^
Reply
Thanks given by:
#40
(10-30-2011, 10:44 AM)FakeTruth Wrote: At least you probably won't forget how it DOES work now ^^

:D Absolutely true.


What do you think about that NBT parser you created? Do you think it will work for this project or should I finish work on mine? The plan I had for the parser is to go byte per byte reading the information into different arrays based on what information the parser finds, then using those arrays to build the pak file. Pretty much the exact same thing that's happening in the file reading loop.

I could turn it into a class with separate functions to be more versatile, but I think that goes a bit beyond what information I need to gather from the mcr files. It's been my experience that procedural programming tends to be faster in PHP (sometimes orders of magnitude faster), so I tend to do that a lot. The shopping cart I programmed is VERY fast, but I don't use very many classes and only use functions when I need to use that bit of code more than once. Basically, I only used classes to keep track of the customer and shopping cart information since that's used on every page.

I'd imagine classes make much more sense in C++, the language is so much faster than PHP it's incredible. Being compiled, classes might actually be faster than procedural code. I don't really know.
Reply
Thanks given by:




Users browsing this thread: 2 Guest(s)