mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-19 04:05:31 +00:00
New player chunk load queues with ACK notification
This commit is contained in:
parent
be0a31697a
commit
e381313747
@ -119,7 +119,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
|||||||
|
|
||||||
public $blocked = true;
|
public $blocked = true;
|
||||||
public $achievements = [];
|
public $achievements = [];
|
||||||
public $chunksLoaded = [];
|
|
||||||
public $lastCorrect;
|
public $lastCorrect;
|
||||||
/** @var SimpleTransactionGroup */
|
/** @var SimpleTransactionGroup */
|
||||||
protected $currentTransaction = null;
|
protected $currentTransaction = null;
|
||||||
@ -139,17 +138,22 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
|||||||
protected $displayName;
|
protected $displayName;
|
||||||
protected $startAction = false;
|
protected $startAction = false;
|
||||||
protected $sleeping = false;
|
protected $sleeping = false;
|
||||||
protected $chunksOrder = [];
|
|
||||||
|
protected $usedChunks = [];
|
||||||
|
protected $loadQueue = [];
|
||||||
|
protected $chunkACK = [];
|
||||||
|
/** @var \pocketmine\scheduler\TaskHandler */
|
||||||
|
protected $chunkLoadTask;
|
||||||
|
|
||||||
/** @var Player[] */
|
/** @var Player[] */
|
||||||
protected $hiddenPlayers = [];
|
protected $hiddenPlayers = [];
|
||||||
|
|
||||||
private $viewDistance;
|
private $viewDistance;
|
||||||
private $spawnPosition;
|
private $spawnPosition;
|
||||||
|
|
||||||
private $lastChunk = false;
|
|
||||||
private $chunkScheduled = 0;
|
|
||||||
private $inAction = false;
|
private $inAction = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private $needACK = [];
|
private $needACK = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -480,19 +484,22 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
|||||||
return $this->sleeping instanceof Vector3;
|
return $this->sleeping instanceof Vector3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function unloadChunk($x, $z){
|
||||||
* Sets the chunk send flags for a specific index
|
$index = Level::chunkHash($x, $z);
|
||||||
*
|
if(isset($this->usedChunks[$index])){
|
||||||
* WARNING: Do not use this, it's only for internal use.
|
foreach($this->getLevel()->getChunkEntities($x, $z) as $entity){
|
||||||
* Changes to this function won't be recorded on the version.
|
if($entity !== $this){
|
||||||
*
|
$entity->despawnFrom($this);
|
||||||
* @param int $index
|
}
|
||||||
* @param int $flags
|
}
|
||||||
*/
|
$pk = new UnloadChunkPacket();
|
||||||
public function setChunkIndex($index, $flags){
|
$pk->chunkX = $x;
|
||||||
if(isset($this->chunksLoaded[$index])){
|
$pk->chunkZ = $z;
|
||||||
$this->chunksLoaded[$index] |= $flags;
|
$this->dataPacket($pk);
|
||||||
|
unset($this->usedChunks[$index]);
|
||||||
}
|
}
|
||||||
|
unset($this->loadQueue[$index]);
|
||||||
|
$this->orderChunks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -513,6 +520,28 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
|||||||
|
|
||||||
public function handleACK($identifier){
|
public function handleACK($identifier){
|
||||||
unset($this->needACK[$identifier]);
|
unset($this->needACK[$identifier]);
|
||||||
|
if(isset($this->chunkACK[$identifier])){
|
||||||
|
$index = $this->chunkACK[$identifier];
|
||||||
|
unset($this->chunkACK[$identifier]);
|
||||||
|
if(isset($this->usedChunks[$index])){
|
||||||
|
$this->usedChunks[$index][0] = true;
|
||||||
|
if($this->spawned === true){
|
||||||
|
$X = null;
|
||||||
|
$Z = null;
|
||||||
|
Level::getXZ($index, $X, $Z);
|
||||||
|
foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){
|
||||||
|
if($entity !== $this){
|
||||||
|
$entity->spawnTo($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach($this->getLevel()->getChunkTiles($X, $Z) as $tile){
|
||||||
|
if($tile instanceof Spawnable){
|
||||||
|
$tile->spawnTo($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -521,89 +550,72 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
|||||||
* WARNING: Do not use this, it's only for internal use.
|
* WARNING: Do not use this, it's only for internal use.
|
||||||
* Changes to this function won't be recorded on the version.
|
* Changes to this function won't be recorded on the version.
|
||||||
*
|
*
|
||||||
* @param bool $force
|
|
||||||
* @param bool $ev
|
|
||||||
*
|
|
||||||
* @return void|bool
|
|
||||||
*/
|
*/
|
||||||
public function getNextChunk($force = false, $ev = null){
|
|
||||||
if($this->connected === false){
|
public function sendNextChunk(){
|
||||||
|
if($this->connected === false or !isset($this->chunkLoadTask)){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($ev === true){
|
$index = key($this->loadQueue);
|
||||||
--$this->chunkScheduled;
|
$distance = @$this->loadQueue[$index];
|
||||||
if($this->chunkScheduled < 0){
|
|
||||||
$this->chunkScheduled = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_array($this->lastChunk)){
|
|
||||||
/*$identifier = $this->lastChunk[2];
|
|
||||||
if(!$this->checkACK($identifier)){
|
|
||||||
if((microtime(true) - $this->lastChunk[3]) < 1.5){
|
|
||||||
$this->server->getScheduler()->scheduleDelayedTask(new CallbackTask(array($this, "getNextChunk"), array(false, true)), MAX_CHUNK_RATE);
|
|
||||||
return false;
|
|
||||||
}else{
|
|
||||||
$index = null;
|
|
||||||
Level::getXZ($index, $this->lastChunk[0], $this->lastChunk[1]);
|
|
||||||
unset($this->chunksLoaded[$index]);
|
|
||||||
}
|
|
||||||
}else{*/
|
|
||||||
foreach($this->getLevel()->getChunkEntities($this->lastChunk[0], $this->lastChunk[1]) as $entity){
|
|
||||||
if($entity !== $this){
|
|
||||||
$entity->spawnTo($this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach($this->getLevel()->getChunkTiles($this->lastChunk[0], $this->lastChunk[1]) as $tile){
|
|
||||||
if($tile instanceof Spawnable){
|
|
||||||
$tile->spawnTo($this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//}
|
|
||||||
$this->lastChunk = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$index = key($this->chunksOrder);
|
|
||||||
$distance = @$this->chunksOrder[$index];
|
|
||||||
|
|
||||||
if($index === null or $distance === null){
|
if($index === null or $distance === null){
|
||||||
$this->orderChunks();
|
$this->chunkLoadTask->setNextRun($this->chunkLoadTask->getNextRun() + 30);
|
||||||
if($this->chunkScheduled === 0){
|
return;
|
||||||
$this->server->getScheduler()->scheduleDelayedTask(new CallbackTask(array($this, "getNextChunk"), array(false, true)), 60);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
$X = null;
|
$X = null;
|
||||||
$Z = null;
|
$Z = null;
|
||||||
Level::getXZ($index, $X, $Z);
|
Level::getXZ($index, $X, $Z);
|
||||||
if(!$this->getLevel()->isChunkPopulated($X, $Z)){
|
if(!$this->getLevel()->isChunkPopulated($X, $Z)){
|
||||||
$this->orderChunks();
|
return;
|
||||||
if($this->chunkScheduled === 0 or $force === true){
|
}
|
||||||
$this->server->getScheduler()->scheduleDelayedTask(new CallbackTask(array($this, "getNextChunk"), array(false, true)), MAX_CHUNK_RATE);
|
unset($this->loadQueue[$index]);
|
||||||
++$this->chunkScheduled;
|
$this->usedChunks[$index] = [false, 0];
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
unset($this->chunksOrder[$index]);
|
|
||||||
if(!isset($this->chunksLoaded[$index])){
|
|
||||||
$this->chunksLoaded[$index] = 0xff;
|
|
||||||
}
|
|
||||||
$Yndex = $this->chunksLoaded[$index];
|
|
||||||
$this->chunksLoaded[$index] = 0; //Load them all
|
|
||||||
$this->getLevel()->useChunk($X, $Z, $this);
|
$this->getLevel()->useChunk($X, $Z, $this);
|
||||||
$pk = new FullChunkDataPacket;
|
$pk = new FullChunkDataPacket;
|
||||||
$pk->chunkX = $X;
|
$pk->chunkX = $X;
|
||||||
$pk->chunkZ = $Z;
|
$pk->chunkZ = $Z;
|
||||||
$pk->data = $this->getLevel()->getNetworkChunk($X, $Z, $Yndex);
|
$pk->data = $this->getLevel()->getNetworkChunk($X, $Z, 0xff);
|
||||||
$cnt = $this->dataPacket($pk, true);
|
$cnt = $this->dataPacket($pk, true);
|
||||||
|
|
||||||
if($cnt === false){
|
if($cnt === false or $cnt === true){
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
$this->chunkACK[$cnt] = $index;
|
||||||
|
|
||||||
|
if(count($this->usedChunks) >= 56 and $this->spawned === false){
|
||||||
|
$spawned = 0;
|
||||||
|
foreach($this->usedChunks as $d){
|
||||||
|
if($d[0] === true){
|
||||||
|
$spawned++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($spawned < 56){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($this->usedChunks as $index => $d){
|
||||||
|
if($d[0] === false){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$X = null;
|
||||||
|
$Z = null;
|
||||||
|
Level::getXZ($index, $X, $Z);
|
||||||
|
foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){
|
||||||
|
if($entity !== $this){
|
||||||
|
$entity->spawnTo($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach($this->getLevel()->getChunkTiles($X, $Z) as $tile){
|
||||||
|
if($tile instanceof Spawnable){
|
||||||
|
$tile->spawnTo($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(count($this->chunksLoaded) >= 56 and $this->spawned === false){
|
|
||||||
//TODO
|
//TODO
|
||||||
//$this->heal($this->data->get("health"), "spawn", true);
|
//$this->heal($this->data->get("health"), "spawn", true);
|
||||||
$this->spawned = true;
|
$this->spawned = true;
|
||||||
@ -635,13 +647,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
|||||||
$this->server->getUpdater()->showPlayerUpdate($this);
|
$this->server->getUpdater()->showPlayerUpdate($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->lastChunk = array($X, $Z, $cnt, microtime(true));
|
|
||||||
|
|
||||||
if($this->chunkScheduled === 0 or $force === true){
|
|
||||||
$this->server->getScheduler()->scheduleDelayedTask(new CallbackTask(array($this, "getNextChunk"), array(false, true)), MAX_CHUNK_RATE);
|
|
||||||
++$this->chunkScheduled;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -657,7 +662,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$newOrder = [];
|
$newOrder = [];
|
||||||
$lastChunk = $this->chunksLoaded;
|
$lastChunk = $this->usedChunks;
|
||||||
$centerX = $this->x >> 4;
|
$centerX = $this->x >> 4;
|
||||||
$centerZ = $this->z >> 4;
|
$centerZ = $this->z >> 4;
|
||||||
$startX = $centerX - $this->viewDistance;
|
$startX = $centerX - $this->viewDistance;
|
||||||
@ -669,7 +674,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
|||||||
for($Z = $startZ; $Z <= $finalZ; ++$Z){
|
for($Z = $startZ; $Z <= $finalZ; ++$Z){
|
||||||
$distance = abs($X - $centerX) + abs($Z - $centerZ);
|
$distance = abs($X - $centerX) + abs($Z - $centerZ);
|
||||||
$index = Level::chunkHash($X, $Z);
|
$index = Level::chunkHash($X, $Z);
|
||||||
if(!isset($this->chunksLoaded[$index]) or $this->chunksLoaded[$index] !== 0){
|
if(!isset($this->usedChunks[$index])){
|
||||||
if($this->getLevel()->isChunkPopulated($X, $Z)){
|
if($this->getLevel()->isChunkPopulated($X, $Z)){
|
||||||
$newOrder[$index] = $distance;
|
$newOrder[$index] = $distance;
|
||||||
}else{
|
}else{
|
||||||
@ -681,10 +686,10 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
|||||||
}
|
}
|
||||||
|
|
||||||
asort($newOrder);
|
asort($newOrder);
|
||||||
$this->chunksOrder = $newOrder;
|
$this->loadQueue = $newOrder;
|
||||||
|
|
||||||
$i = 0;
|
$i = 0;
|
||||||
while(count($this->chunksOrder) < 3 and $generateQueue->count() > 0 and $i < 16){
|
while(count($this->loadQueue) < 3 and $generateQueue->count() > 0 and $i < 16){
|
||||||
$d = $generateQueue->extract();
|
$d = $generateQueue->extract();
|
||||||
$this->getLevel()->generateChunk($d[0], $d[1]);
|
$this->getLevel()->generateChunk($d[0], $d[1]);
|
||||||
++$i;
|
++$i;
|
||||||
@ -692,21 +697,19 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
|||||||
|
|
||||||
|
|
||||||
foreach($lastChunk as $index => $Yndex){
|
foreach($lastChunk as $index => $Yndex){
|
||||||
if($Yndex === 0){
|
$X = null;
|
||||||
$X = null;
|
$Z = null;
|
||||||
$Z = null;
|
Level::getXZ($index, $X, $Z);
|
||||||
Level::getXZ($index, $X, $Z);
|
foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){
|
||||||
foreach($this->getLevel()->getChunkEntities($X, $Z) as $entity){
|
if($entity !== $this){
|
||||||
if($entity !== $this){
|
$entity->despawnFrom($this);
|
||||||
$entity->despawnFrom($this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$pk = new UnloadChunkPacket();
|
|
||||||
$pk->chunkX = $X;
|
|
||||||
$pk->chunkZ = $Z;
|
|
||||||
$this->dataPacket($pk);
|
|
||||||
}
|
}
|
||||||
unset($this->chunksLoaded[$index]);
|
$pk = new UnloadChunkPacket();
|
||||||
|
$pk->chunkX = $X;
|
||||||
|
$pk->chunkZ = $Z;
|
||||||
|
$this->dataPacket($pk);
|
||||||
|
unset($this->usedChunks[$index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1230,8 +1233,9 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
|||||||
|
|
||||||
|
|
||||||
$this->orderChunks();
|
$this->orderChunks();
|
||||||
$this->tasks[] = $this->server->getScheduler()->scheduleDelayedTask(new CallbackTask(array($this, "orderChunks")), 30);
|
$this->tasks[] = $this->server->getScheduler()->scheduleDelayedRepeatingTask(new CallbackTask(array($this, "orderChunks")), 10, 40);
|
||||||
$this->getNextChunk();
|
$this->sendNextChunk();
|
||||||
|
$this->tasks[] = $this->chunkLoadTask = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "sendNextChunk")), MAX_CHUNK_RATE);
|
||||||
|
|
||||||
$pk = new ReadyPacket();
|
$pk = new ReadyPacket();
|
||||||
$pk->x = $this->x;
|
$pk->x = $this->x;
|
||||||
@ -2039,8 +2043,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
|||||||
$this->server->getLogger()->info(TextFormat::AQUA . $this->username . TextFormat::WHITE . "[/" . $this->ip . ":" . $this->port . "] logged out due to " . $reason);
|
$this->server->getLogger()->info(TextFormat::AQUA . $this->username . TextFormat::WHITE . "[/" . $this->ip . ":" . $this->port . "] logged out due to " . $reason);
|
||||||
$this->windows = new \SplObjectStorage();
|
$this->windows = new \SplObjectStorage();
|
||||||
$this->windowIndex = [];
|
$this->windowIndex = [];
|
||||||
$this->chunksLoaded = [];
|
$this->usedChunks = [];
|
||||||
$this->chunksOrder = [];
|
$this->loadQueue = [];
|
||||||
unset($this->buffer);
|
unset($this->buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1387,7 +1387,7 @@ class Server{
|
|||||||
$this->logger->setLogDebug(\pocketmine\DEBUG > 1);
|
$this->logger->setLogDebug(\pocketmine\DEBUG > 1);
|
||||||
}
|
}
|
||||||
define("ADVANCED_CACHE", $this->getProperty("settings.advanced-cache", false));
|
define("ADVANCED_CACHE", $this->getProperty("settings.advanced-cache", false));
|
||||||
define("MAX_CHUNK_RATE", 20 / $this->getProperty("chunk-sending.per-second", 20));
|
define("MAX_CHUNK_RATE", ceil(20 / $this->getProperty("chunk-sending.per-second", 20)));
|
||||||
if(ADVANCED_CACHE == true){
|
if(ADVANCED_CACHE == true){
|
||||||
$this->logger->info("Advanced cache enabled");
|
$this->logger->info("Advanced cache enabled");
|
||||||
}
|
}
|
||||||
|
@ -931,7 +931,7 @@ abstract class Entity extends Position implements Metadatable{
|
|||||||
$this->airTicks = 300;
|
$this->airTicks = 300;
|
||||||
$this->fallDistance = 0;
|
$this->fallDistance = 0;
|
||||||
$this->orderChunks();
|
$this->orderChunks();
|
||||||
$this->getNextChunk(true);
|
$this->sendNextChunk();
|
||||||
$this->forceMovement = $pos;
|
$this->forceMovement = $pos;
|
||||||
|
|
||||||
$pk = new MovePlayerPacket;
|
$pk = new MovePlayerPacket;
|
||||||
|
@ -345,8 +345,11 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
if(count($this->changedBlocks[$index][$Y]) < 582){ //Optimal value, calculated using the relation between minichunks and single packets
|
if(count($this->changedBlocks[$index][$Y]) < 582){ //Optimal value, calculated using the relation between minichunks and single packets
|
||||||
continue;
|
continue;
|
||||||
}else{
|
}else{
|
||||||
|
$X = null;
|
||||||
|
$Z = null;
|
||||||
|
Level::getXZ($index, $X, $Z);
|
||||||
foreach($this->players as $p){
|
foreach($this->players as $p){
|
||||||
$p->setChunkIndex($index, $mini);
|
$p->unloadChunk($X, $Z);
|
||||||
}
|
}
|
||||||
unset($this->changedBlocks[$index][$Y]);
|
unset($this->changedBlocks[$index][$Y]);
|
||||||
}
|
}
|
||||||
@ -1147,7 +1150,7 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
public function setChunk($x, $z, SimpleChunk $chunk){
|
public function setChunk($x, $z, SimpleChunk $chunk){
|
||||||
$index = Level::chunkHash($x, $z);
|
$index = Level::chunkHash($x, $z);
|
||||||
foreach($this->getUsingChunk($x, $z) as $player){
|
foreach($this->getUsingChunk($x, $z) as $player){
|
||||||
$player->setChunkIndex($index, 0xff);
|
$player->unloadChunk($x, $z);
|
||||||
}
|
}
|
||||||
$this->provider->setChunk($x, $z, $chunk);
|
$this->provider->setChunk($x, $z, $chunk);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user