From 244fde8143925257c9ceabe22878cb2ec932f6a0 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Pueyo Date: Wed, 15 May 2013 22:43:12 +0200 Subject: [PATCH] Chunk unloading --- src/API/BlockAPI.php | 4 +-- src/Player.php | 18 ++++++++-- src/world/Level.php | 35 +++++++++++++++++-- .../generator/object/tree/SmallTreeObject.php | 2 +- 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/API/BlockAPI.php b/src/API/BlockAPI.php index b7b482a9c..dc778a36e 100644 --- a/src/API/BlockAPI.php +++ b/src/API/BlockAPI.php @@ -716,7 +716,6 @@ class BlockAPI{ public function blockUpdateAround(Position $pos, $type = BLOCK_UPDATE_NORMAL){ if(!($pos instanceof Block)){ - $pos = $pos->floor(); $block = $pos->level->getBlock($pos); }else{ $block = $pos; @@ -731,7 +730,6 @@ class BlockAPI{ public function blockUpdate(Position $pos, $type = BLOCK_UPDATE_NORMAL){ if(!($pos instanceof Block)){ - $pos = $pos->floor(); $block = $pos->level->getBlock($pos); }else{ $block = $pos; @@ -748,7 +746,7 @@ class BlockAPI{ if($delay < 0){ return false; } - $pos = $pos->floor(); + $index = $pos->x.".".$pos->y.".".$pos->z.".".$pos->level->getName(); $delay = microtime(true) + $delay * 0.05; if(!isset($this->scheduledUpdates[$index])){ diff --git a/src/Player.php b/src/Player.php index 3699df666..40995ecc8 100644 --- a/src/Player.php +++ b/src/Player.php @@ -62,6 +62,7 @@ class Player{ private $chunksOrder = array(); private $lag = array(0, 0); private $spawnPosition; + private $freedChunks = true; public $itemEnforcement; public $lastCorrect; @@ -118,7 +119,7 @@ class Player{ for($z = 0; $z < 16; ++$z){ for($y = 0; $y < 8; ++$y){ $d = $x.":".$y.":".$z; - if(!isset($this->chunksLoaded[$d])){ + if(!isset($this->chunksLoaded[$d])){ $this->chunksOrder[$d] = $v->distance(new Vector3($x + 0.5, $y / 4, $z + 0.5)); } } @@ -134,9 +135,19 @@ class Player{ $c = key($this->chunksOrder); $d = $this->chunksOrder[$c]; if($c === null or $d > $this->server->api->getProperty("view-distance")){ + if($this->freedChunks === false){ + foreach($this->chunksOrder as $c => $d){ + $id = explode(":", $c); + $X = $id[0]; + $Z = $id[2]; + $this->level->freeChunk($X, $Z, $this); + } + $this->freedChunks = true; + } $this->server->schedule(50, array($this, "getNextChunk")); return false; } + $this->freedChunks = false; array_shift($this->chunksOrder); $this->chunksLoaded[$c] = true; $id = explode(":", $c); @@ -147,6 +158,7 @@ class Player{ $z = $Z << 4; $y = $Y << 4; $MTU = $this->MTU - 16; + $this->level->useChunk($X, $Z, $this); $chunk = $this->level->getOrderedMiniChunk($X, $Z, $Y, $MTU); foreach($chunk as $d){ $this->dataPacket(MC_CHUNK_DATA, array( @@ -233,6 +245,7 @@ class Player{ $this->eventHandler(new Container("You have been kicked. Reason: ".$reason), "server.chat"); $this->directDataPacket(MC_DISCONNECT); $this->sendBuffer(); + $this->level->freeAllChunks($this); $this->buffer = null; unset($this->buffer); $this->recovery = null; @@ -589,7 +602,7 @@ class Player{ $this->entity->setPosition($pos, $yaw, $pitch); $this->entity->resetSpeed(); $this->entity->updateLast(); - $this->entity->calculateVelocity(); + $this->entity->calculateVelocity(); if($pos instanceof Position and $pos->level !== $this->level){ foreach($this->server->api->entity->getAll($this->level) as $e){ if($e !== $this->entity){ @@ -603,6 +616,7 @@ class Player{ )); } } + $this->level->freeAllChunks($this); $this->level = $pos->level; $this->chunksLoaded = array(); $this->server->api->entity->spawnToAll($this->level, $this->eid); diff --git a/src/world/Level.php b/src/world/Level.php index 64fb44366..331438cfc 100644 --- a/src/world/Level.php +++ b/src/world/Level.php @@ -39,6 +39,24 @@ class Level{ $this->server->schedule(15, array($this, "checkThings"), array(), true); $this->server->event("server.close", array($this, "save")); $this->name = $name; + $this->usedChunks = array(); + } + + public function useChunk($X, $Z, Player $player){ + if(!isset($this->usedChunks[$X.".".$Z])){ + $this->usedChunks[$X.".".$Z] = array(); + } + $this->usedChunks[$X.".".$Z][$player->CID] = true; + $this->level->loadChunk($X, $Z); + } + + public function freeAllChunks(Player $player){ + foreach($this->usedChunks as $i => $c){ + unset($this->usedChunks[$i][$player->CID]); + } + } + public function freeChunk($X, $Z, Player $player){ + unset($this->usedChunks[$X.".".$Z][$player->CID]); } public function checkThings(){ @@ -47,6 +65,15 @@ class Level{ if($this->server->api->dhandle("time.change", array("level" => $this, "time" => $time)) !== false){ $this->time = $time; } + + foreach($this->usedChunks as $i => $c){ + if(count($c) === 0){ + unset($this->usedChunks[$i]); + $X = explode(".", $i); + $Z = array_pop($X); + $this->level->unloadChunk((int) $X, (int) $Z); + } + } } public function __destruct(){ @@ -68,10 +95,14 @@ class Level{ return BlockAPI::get($b[0], $b[1], new Position($pos->x, $pos->y, $pos->z, $this)); } - public function setBlock(Position $pos, Block $block, $update = true, $tiles = false){ + public function setBlock(Vector3 $pos, Block $block, $update = true, $tiles = false){ if((($pos instanceof Position) and $pos->level !== $this) or $pos->x < 0 or $pos->y < 0 or $pos->z < 0){ return false; - }elseif($this->server->api->dhandle("block.change", array( + }elseif(!($pos instanceof Position)){ + $pos = new Position($pos->x, $pos->y, $pos->z, $this); + } + + if($this->server->api->dhandle("block.change", array( "position" => $pos, "block" => $block, )) !== false){ diff --git a/src/world/generator/object/tree/SmallTreeObject.php b/src/world/generator/object/tree/SmallTreeObject.php index 08020f5f6..ed3eb6ab3 100644 --- a/src/world/generator/object/tree/SmallTreeObject.php +++ b/src/world/generator/object/tree/SmallTreeObject.php @@ -66,7 +66,7 @@ class SmallTreeObject extends TreeObject{ for($xx = -$xzRadius; $xx < ($xzRadius + 1); ++$xx){ for($zz = -$xzRadius; $zz < ($xzRadius + 1); ++$zz){ if((abs($xx) != $xzRadius or abs($zz) != $xzRadius) and $yRadius != 0){ - $level->setBlock(new Vector3($x + $xx, $y + $yy, $z + $zz), new LeavesBlck($this->type)); + $level->setBlock(new Vector3($x + $xx, $y + $yy, $z + $zz), new LeavesBlock($this->type)); } } }