Updated Position to use Weak / strong references for Level objects

This commit is contained in:
Shoghi Cervantes
2014-05-22 04:14:06 +02:00
parent 6328834681
commit c1546aac9c
60 changed files with 584 additions and 291 deletions

View File

@ -56,6 +56,20 @@ class Chunk extends BaseChunk{
$this->nbt->TileTicks->setTagType(NBT::TAG_Compound);
}
if($this->nbt->Sections instanceof Enum){
$this->nbt->Sections->setTagType(NBT::TAG_Compound);
}else{
$this->nbt->Sections = new Enum("Sections", array());
$this->nbt->Sections->setTagType(NBT::TAG_Compound);
}
$sections = array();
foreach($this->nbt->Sections as $section){
if($section instanceof Compound){
$sections[(int) $section["Y"]] = new ChunkSection($section);
}
}
parent::__construct($level, $this->nbt["xPos"], $this->nbt["zPos"], $sections);
}
}

View File

@ -0,0 +1,153 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\level\format\anvil;
use pocketmine\nbt\tag\Compound;
class ChunkSection implements \pocketmine\level\format\ChunkSection{
private $y;
private $blocks;
private $data;
private $blockLight;
private $skyLight;
public function __construct(Compound $nbt){
$this->y = (int) $nbt["Y"];
$this->blocks = (string) $nbt["Blocks"];
$this->data = (string) $nbt["Data"];
$this->blockLight = (string) $nbt["BlockLight"];
$this->skyLight = (string) $nbt["SkyLight"];
}
public function getBlockId($x, $y, $z){
return ord($this->blocks{($y << 8) + ($z << 4) + $x});
}
public function setBlockId($x, $y, $z, $id){
$this->blocks{($y << 8) + ($z << 4) + $x} = chr($id);
}
public function getBlockData($x, $y, $z){
$m = ord($this->data{($y << 7) + ($z << 3) + ($x >> 1)});
if(($y & 1) === 0){
return $m & 0x0F;
}else{
return $m >> 4;
}
}
public function setBlockData($x, $y, $z, $data){
$i = ($y << 7) + ($z << 3) + ($x >> 1);
$old_m = ord($this->data{$i});
if(($y & 1) === 0){
$this->data{$i} = chr(($old_m & 0xf0) | ($data & 0x0f));
}else{
$this->data{$i} = chr((($data & 0x0f) << 4) | ($old_m & 0x0f));
}
}
public function getBlock($x, $y, $z, &$blockId, &$meta = null){
$i = ($y << 8) + ($z << 4) + $x;
$blockId = ord($this->blocks{$i});
$m = ord($this->data{$i >> 1});
if(($y & 1) === 0){
$meta = $m & 0x0F;
}else{
$meta = $m >> 4;
}
}
public function setBlock($x, $y, $z, $blockId = null, $meta = null){
$i = ($y << 8) + ($z << 4) + $x;
if($blockId !== null){
$this->blocks{$i} = chr($blockId);
}
if($meta !== null){
$i >>= 1;
$old_m = ord($this->data{$i});
if(($y & 1) === 0){
$this->data{$i} = chr(($old_m & 0xf0) | ($meta & 0x0f));
}else{
$this->data{$i} = chr((($meta & 0x0f) << 4) | ($old_m & 0x0f));
}
}
}
public function getBlockSkyLight($x, $y, $z){
$sl = ord($this->skyLight{($y << 7) + ($z << 3) + ($x >> 1)});
if(($y & 1) === 0){
return $sl & 0x0F;
}else{
return $sl >> 4;
}
}
public function setBlockSkyLight($x, $y, $z, $level){
$i = ($y << 7) + ($z << 3) + ($x >> 1);
$old_sl = ord($this->skyLight{$i});
if(($y & 1) === 0){
$this->skyLight{$i} = chr(($old_sl & 0xf0) | ($level & 0x0f));
}else{
$this->skyLight{$i} = chr((($level & 0x0f) << 4) | ($old_sl & 0x0f));
}
}
public function getBlockLight($x, $y, $z){
$l = ord($this->blockLight{($y << 7) + ($z << 3) + ($x >> 1)});
if(($y & 1) === 0){
return $l & 0x0F;
}else{
return $l >> 4;
}
}
public function setBlockLight($x, $y, $z, $level){
$i = ($y << 7) + ($z << 3) + ($x >> 1);
$old_l = ord($this->blockLight{$i});
if(($y & 1) === 0){
$this->blockLight{$i} = chr(($old_l & 0xf0) | ($level & 0x0f));
}else{
$this->blockLight{$i} = chr((($level & 0x0f) << 4) | ($old_l & 0x0f));
}
}
public function getBlockIdColumn($x, $z){
$i = ($z << 4) + $x;
$column = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
for($y = 15; $y >= 0; --$y){
$column{15 - $y} = $this->blocks{($y << 8) + $i};
}
return $column;
}
public function getBlockDataColumn($x, $z){
$i = ($z << 3) + ($x >> 1);
$column = "\x00\x00\x00\x00\x00\x00\x00\x00";
for($y = 7; $y >= 0; --$y){
$column{7 - $y} = $this->data{($y << 7) + $i};
}
return $column;
}
}

View File

@ -45,10 +45,10 @@ class RegionLoader{
protected $lastSector;
protected $locationTable = array();
public function __construct($path, $regionX, $regionZ){
public function __construct($path,/*Level $level, */$regionX, $regionZ){
$this->x = $regionX;
$this->z = $regionZ;
$this->filePath = $path . "region/r.$regionX.$regionZ.mca";
$this->filePath = /*$level->getPath()*/$path . "region/r.$regionX.$regionZ.mca";
touch($this->filePath);
$this->filePointer = fopen($this->filePath, "r+b");
flock($this->filePointer, LOCK_EX);
@ -113,6 +113,8 @@ class RegionLoader{
if(!$chunk instanceof Compound){
return false;
}
return $chunk;
//$chunk = new Chunk($level, $chunk);
}
public function generateChunk($x, $z){
@ -138,7 +140,7 @@ class RegionLoader{
$writer->setData(new Compound("", array($nbt)));
$chunkData = $writer->writeCompressed(self::COMPRESSION_ZLIB, self::$COMPRESSION_LEVEL);
$length = strlen($chunkData) + 1;
$sectors = ($length + 4) >> 12;
$sectors = (int) ceil(($length + 4) / 4096);
$index = self::getChunkOffset($x, $z);
if($this->locationTable[$index][1] < $sectors){
$this->locationTable[$index][0] = $this->lastSector += $sectors; //The GC will clean this shift later
@ -153,11 +155,42 @@ class RegionLoader{
return $x + ($z << 5);
}
public function doSlowCleanUp(){
for($i = 0; $i < 1024; ++$i){
if($this->locationTable[$i][0] === 0 or $this->locationTable[$i][1] === 0){
continue;
}
fseek($this->filePointer, $this->locationTable[$i][0] << 12);
$chunk = fread($this->filePointer, $this->locationTable[$i][1] << 12);
$length = Binary::readInt(substr($chunk, 0, 4));
if($length <= 1){
$this->locationTable[$i] = array(0, 0, 0); //Non-generated chunk, remove it from index
}
$chunk = zlib_decode(substr($chunk, 5));
if(strlen($chunk) <= 1){
$this->locationTable[$i] = array(0, 0, 0); //Corrupted chunk, remove it
continue;
}
$chunk = chr(self::COMPRESSION_ZLIB) . zlib_encode($chunk, 15, 9);
$chunk = Binary::writeInt(strlen($chunk)) . $chunk;
$sectors = (int) ceil(strlen($chunk) / 4096);
if($sectors > $this->locationTable[$i][1]){
$this->locationTable[$i][0] = $this->lastSector += $sectors;
}
fseek($this->filePointer, $this->locationTable[$i][0] << 12);
fwrite($this->filePointer, str_pad($chunk, $sectors << 12, "\x00", STR_PAD_RIGHT));
}
$this->writeLocationTable();
$n = $this->cleanGarbage();
$this->writeLocationTable();
return $n;
}
private function cleanGarbage(){
$sectors = array();
foreach($this->locationTable as $index => $data){ //Calculate file usage
if($data[0] === 0 or $data[1] === 0){
$this->locationTable[$index] = array(0, 0);
$this->locationTable[$index] = array(0, 0, 0);
continue;
}
for($i = 0; $i < $data[1]; ++$i){
@ -186,9 +219,9 @@ class RegionLoader{
fwrite($this->filePointer, $old, 4096);
}
$this->locationTable[$index][0] -= $shift;
$lastSector = $sector;
}
ftruncate($this->filePointer, ($sector + 1) << 12); //Truncate to the end of file written
return $shift;
}
@ -198,20 +231,16 @@ class RegionLoader{
$table = fread($this->filePointer, 4 * 1024 * 2);
for($i = 0; $i < 1024; ++$i){
$index = Binary::readInt(substr($table, $i << 2, 4));
$this->locationTable[$i] = array(($index & ~0xff) >> 8, $index & 0xff);
$this->locationTable[$i] = array(($index & ~0xff) >> 8, $index & 0xff, Binary::readInt(substr($table, 4096 + ($i << 2), 4)));
if(($this->locationTable[$i][0] + $this->locationTable[$i][1] - 1) > $this->lastSector){
$this->lastSector = $this->locationTable[$i][0] + $this->locationTable[$i][1] - 1;
}
}
//Time of modification
for($i = 0; $i < 1024; ++$i){
$this->locationTable[$i][2] = Binary::readInt(substr($table, 4096 + ($i << 2), 4));
}
}
private function writeLocationTable(){
$table = "";
for($i = 0; $i < 1024; ++$i){
$table .= Binary::writeInt(($this->locationTable[$i][0] << 8) | $this->locationTable[$i][1]);
}
@ -241,6 +270,7 @@ class RegionLoader{
$time = time();
for($i = 0; $i < 1024; ++$i){
$this->locationTable[$i][2] = $time;
$table .= Binary::writeInt($time);
}