/** * WARNING: Do not use this, it's only for internal use. * Changes to this function won't be recorded on the version. * * @param int $currentTick * * @return bool */ public function doTick($currentTick) { $this->timings->doTick->startTiming(); $this->checkTime(); if ($currentTick % 200 === 0) { $this->sendTime(); } $this->unloadChunks(); $X = \null; $Z = \null; //Do block updates $this->timings->doTickPending->startTiming(); while ($this->updateQueue->count() > 0 and $this->updateQueue->current()["priority"] <= $currentTick) { $block = $this->getBlock($this->updateQueue->extract()["data"]); unset($this->updateQueueIndex[\PHP_INT_SIZE === 8 ? ($block->x & 0xfffffff) << 35 | ($block->y & 0x7f) << 28 | $block->z & 0xfffffff : $block->x . ":" . $block->y . ":" . $block->z]); $block->onUpdate(self::BLOCK_UPDATE_SCHEDULED); } $this->timings->doTickPending->stopTiming(); $this->timings->entityTick->startTiming(); //Update entities that need update Timings::$tickEntityTimer->startTiming(); foreach ($this->updateEntities as $id => $entity) { if ($entity->closed or !$entity->onUpdate($currentTick)) { unset($this->updateEntities[$id]); } } Timings::$tickEntityTimer->stopTiming(); $this->timings->entityTick->stopTiming(); $this->timings->tileEntityTick->startTiming(); //Update tiles that need update if (\count($this->updateTiles) > 0) { //Timings::$tickTileEntityTimer->startTiming(); foreach ($this->updateTiles as $id => $tile) { if ($tile->onUpdate() !== \true) { unset($this->updateTiles[$id]); } } //Timings::$tickTileEntityTimer->stopTiming(); } $this->timings->tileEntityTick->stopTiming(); $this->timings->doTickTiles->startTiming(); $this->tickChunks(); $this->timings->doTickTiles->stopTiming(); if (\count($this->changedCount) > 0) { if (\count($this->players) > 0) { foreach ($this->changedCount as $index => $mini) { for ($Y = 0; $Y < 8; ++$Y) { if (($mini & 1 << $Y) === 0) { continue; } if (\count($this->changedBlocks[$index][$Y]) < 256) { continue; } else { $X = \null; $Z = \null; if (\PHP_INT_SIZE === 8) { $X = $index >> 32 << 32 >> 32; $Z = ($index & 0xffffffff) << 32 >> 32; } else { list($X, $Z) = \explode(":", $index); $X = (int) $X; $Z = (int) $Z; } foreach ($this->getUsingChunk($X, $Z) as $p) { $p->unloadChunk($X, $Z); } unset($this->changedBlocks[$index][$Y]); } } } $this->changedCount = []; if (\count($this->changedBlocks) > 0) { foreach ($this->changedBlocks as $index => $mini) { foreach ($mini as $blocks) { /** @var Block $b */ foreach ($blocks as $b) { $pk = new UpdateBlockPacket(); $pk->x = $b->x; $pk->y = $b->y; $pk->z = $b->z; $pk->block = $b->getId(); $pk->meta = $b->getDamage(); Server::broadcastPacket($this->getUsingChunk($b->x >> 4, $b->z >> 4), $pk); } } } $this->changedBlocks = []; } } else { $this->changedCount = []; $this->changedBlocks = []; } } $this->processChunkRequest(); foreach ($this->moveToSend as $index => $entry) { Level::getXZ($index, $chunkX, $chunkZ); $pk = new MoveEntityPacket(); $pk->entities = $entry; Server::broadcastPacket($this->getChunkPlayers($chunkX, $chunkZ), $pk->setChannel(Network::CHANNEL_MOVEMENT)); } $this->moveToSend = []; foreach ($this->motionToSend as $index => $entry) { Level::getXZ($index, $chunkX, $chunkZ); $pk = new SetEntityMotionPacket(); $pk->entities = $entry; Server::broadcastPacket($this->getChunkPlayers($chunkX, $chunkZ), $pk->setChannel(Network::CHANNEL_MOVEMENT)); } $this->motionToSend = []; $this->timings->doTick->stopTiming(); }
/** * WARNING: Do not use this, it's only for internal use. * Changes to this function won't be recorded on the version. * * @param int $currentTick * * @return bool */ public function doTick($currentTick) { $this->timings->doTick->startTiming(); $this->checkTime(); if (++$this->sendTimeTicker === 200) { $this->sendTime(); $this->sendTimeTicker = 0; } $this->unloadChunks(); //Do block updates $this->timings->doTickPending->startTiming(); while ($this->updateQueue->count() > 0 and $this->updateQueue->current()["priority"] <= $currentTick) { $block = $this->getBlock($this->updateQueue->extract()["data"]); unset($this->updateQueueIndex[Level::blockHash($block->x, $block->y, $block->z)]); $block->onUpdate(self::BLOCK_UPDATE_SCHEDULED); } $this->timings->doTickPending->stopTiming(); $this->timings->entityTick->startTiming(); //Update entities that need update Timings::$tickEntityTimer->startTiming(); foreach ($this->updateEntities as $id => $entity) { if ($entity->closed or !$entity->onUpdate($currentTick)) { unset($this->updateEntities[$id]); } } Timings::$tickEntityTimer->stopTiming(); $this->timings->entityTick->stopTiming(); $this->timings->tileEntityTick->startTiming(); Timings::$tickTileEntityTimer->startTiming(); //Update tiles that need update if (count($this->updateTiles) > 0) { foreach ($this->updateTiles as $id => $tile) { if ($tile->onUpdate() !== true) { unset($this->updateTiles[$id]); } } } Timings::$tickTileEntityTimer->stopTiming(); $this->timings->tileEntityTick->stopTiming(); $this->timings->doTickTiles->startTiming(); $this->tickChunks(); $this->timings->doTickTiles->stopTiming(); if (count($this->changedBlocks) > 0) { if (count($this->players) > 0) { foreach ($this->changedBlocks as $index => $blocks) { unset($this->chunkCache[$index]); Level::getXZ($index, $chunkX, $chunkZ); if (count($blocks) > 512) { $chunk = $this->getChunk($chunkX, $chunkZ); foreach ($this->getChunkPlayers($chunkX, $chunkZ) as $p) { $p->onChunkChanged($chunk); } } else { $this->sendBlocks($this->getChunkPlayers($chunkX, $chunkZ), $blocks, UpdateBlockPacket::FLAG_ALL); } } } else { $this->chunkCache = []; } $this->changedBlocks = []; } $this->processChunkRequest(); if ($this->sleepTicks > 0 and --$this->sleepTicks <= 0) { $this->checkSleep(); } foreach ($this->moveToSend as $index => $entry) { Level::getXZ($index, $chunkX, $chunkZ); $pk = new MoveEntityPacket(); $pk->entities = $entry; $this->addChunkPacket($chunkX, $chunkZ, $pk->setChannel(Network::CHANNEL_MOVEMENT)); } $this->moveToSend = []; foreach ($this->motionToSend as $index => $entry) { Level::getXZ($index, $chunkX, $chunkZ); $pk = new SetEntityMotionPacket(); $pk->entities = $entry; $this->addChunkPacket($chunkX, $chunkZ, $pk->setChannel(Network::CHANNEL_MOVEMENT)); } $this->motionToSend = []; foreach ($this->chunkPackets as $index => $entries) { Level::getXZ($index, $chunkX, $chunkZ); $chunkPlayers = $this->getChunkPlayers($chunkX, $chunkZ); if (count($chunkPlayers) > 0) { foreach ($entries as $pk) { Server::broadcastPacket($chunkPlayers, $pk); } } } $this->chunkPackets = []; $this->timings->doTick->stopTiming(); }
public function onUpdate($currentTick) { if (!$this->loggedIn) { return \false; } if ($this->dead === \true and $this->spawned) { ++$this->deadTicks; if ($this->deadTicks >= 10) { $this->despawnFromAll(); } return $this->deadTicks < 10; } $this->timings->startTiming(); if ($this->spawned) { $this->processMovement($currentTick); $this->entityBaseTick(1); if ($this->onGround) { $this->inAirTicks = 0; } else { if ($this->inAirTicks > 20 and $this->isSurvival() and !$this->isSleeping() and $this->spawned and !$this->server->getAllowFlight()) { $expectedVelocity = -$this->gravity / $this->drag - -$this->gravity / $this->drag * \exp(-$this->drag * ($this->inAirTicks - 2)); $diff = ($this->speed->y - $expectedVelocity) ** 2; if ($diff > 0.6 and $expectedVelocity < $this->speed->y) { $this->kick("Disable fly mods."); } return \false; } else { ++$this->inAirTicks; } } foreach ($this->level->getNearbyEntities($this->boundingBox->grow(1, 0.5, 1), $this) as $entity) { if ($currentTick - $entity->lastUpdate > 1) { $entity->scheduleUpdate(); } if ($entity instanceof Arrow and $entity->hadCollision) { if ($entity->dead !== \true) { $item = Item::get(Item::ARROW, 0, 1); if ($this->isSurvival() and !$this->inventory->canAddItem($item)) { continue; } $this->server->getPluginManager()->callEvent($ev = new InventoryPickupArrowEvent($this->inventory, $entity)); if ($ev->isCancelled()) { continue; } $pk = new TakeItemEntityPacket(); $pk->eid = $this->getId(); $pk->target = $entity->getId(); Server::broadcastPacket($entity->getViewers(), $pk->setChannel(Network::CHANNEL_ENTITY_SPAWNING)); $this->inventory->addItem(clone $item); $entity->kill(); } } elseif ($entity instanceof DroppedItem) { if ($entity->dead !== \true and $entity->getPickupDelay() <= 0) { $item = $entity->getItem(); if ($item instanceof Item) { if ($this->isSurvival() and !$this->inventory->canAddItem($item)) { continue; } $this->server->getPluginManager()->callEvent($ev = new InventoryPickupItemEvent($this->inventory, $entity)); if ($ev->isCancelled()) { continue; } switch ($item->getId()) { case Item::WOOD: $this->awardAchievement("mineWood"); break; case Item::DIAMOND: $this->awardAchievement("diamond"); break; } $pk = new TakeItemEntityPacket(); $pk->eid = $this->getId(); $pk->target = $entity->getId(); Server::broadcastPacket($entity->getViewers(), $pk->setChannel(Network::CHANNEL_ENTITY_SPAWNING)); $this->inventory->addItem(clone $item); $entity->kill(); } } } } } if ($this->nextChunkOrderRun-- <= 0 or $this->chunk === \null) { $this->orderChunks(); } if (\count($this->loadQueue) > 0 or !$this->spawned) { $this->sendNextChunk(); } if (\count($this->moveToSend) > 0) { $pk = new MoveEntityPacket(); $pk->entities = $this->moveToSend; $this->batchDataPacket($pk->setChannel(Network::CHANNEL_MOVEMENT)); $this->moveToSend = []; } if (\count($this->motionToSend) > 0) { $pk = new SetEntityMotionPacket(); $pk->entities = $this->motionToSend; $this->batchDataPacket($pk->setChannel(Network::CHANNEL_MOVEMENT)); $this->motionToSend = []; } if (\count($this->batchedPackets) > 0) { foreach ($this->batchedPackets as $channel => $list) { $this->server->batchPackets([$this], $list, \false, $channel); } $this->batchedPackets = []; } $this->lastUpdate = $currentTick; $this->timings->stopTiming(); return \true; }
public function onUpdate($currentTick) { if (!$this->loggedIn) { return false; } $tickDiff = $currentTick - $this->lastUpdate; if ($tickDiff <= 0) { return true; } if ($this->dead === true and $this->spawned) { ++$this->deadTicks; if ($this->deadTicks >= 10) { $this->despawnFromAll(); } return true; } $this->timings->startTiming(); if ($this->spawned) { $this->processMovement($tickDiff); $this->entityBaseTick($tickDiff); if ($this->onGround) { $this->inAirTicks = 0; } else { if ($this->inAirTicks > 10 and $this->isSurvival() and !$this->isSleeping() and $this->getDataProperty(self::DATA_NO_AI) === 0) { $expectedVelocity = -$this->gravity / $this->drag - -$this->gravity / $this->drag * exp(-$this->drag * ($this->inAirTicks - 5)); $diff = sqrt(abs($this->speed->y - $expectedVelocity)); if (!$this->hasEffect(Effect::JUMP) and $diff > 0.6 and $expectedVelocity < $this->speed->y and !$this->server->getAllowFlight()) { if ($this->inAirTicks < 100) { $this->setMotion(new Vector3(0, $expectedVelocity, 0)); } elseif ($this->kick("Flying is not enabled on this server")) { return false; } } } ++$this->inAirTicks; } } if ($this->nextChunkOrderRun-- <= 0 or $this->chunk === null) { $this->orderChunks(); } if (count($this->loadQueue) > 0 or !$this->spawned) { $this->sendNextChunk(); } $this->checkTeleportPosition(); if (count($this->moveToSend) > 0) { $pk = new MoveEntityPacket(); $pk->entities = $this->moveToSend; $this->batchDataPacket($pk->setChannel(Network::CHANNEL_MOVEMENT)); $this->moveToSend = []; } if (count($this->motionToSend) > 0) { $pk = new SetEntityMotionPacket(); $pk->entities = $this->motionToSend; $this->batchDataPacket($pk->setChannel(Network::CHANNEL_MOVEMENT)); $this->motionToSend = []; } if (count($this->batchedPackets) > 0) { foreach ($this->batchedPackets as $channel => $list) { $this->server->batchPackets([$this], $list, false, $channel); } $this->batchedPackets = []; } $this->lastUpdate = $currentTick; $this->timings->stopTiming(); return true; }
public static function spawnCaseItem($pos, $eid, $itemId) { $pk = new AddItemEntityPacket(); $pk->eid = $eid; $pk->x = $pos->x + 0.5; $pk->y = $pos->y + 1; $pk->z = $pos->z + 0.5; $pk->speedX = 0; $pk->speedY = 0; $pk->speedZ = 0; $pk->item = Item::get($itemId); Server::broadcastPacket(Server::getInstance()->getOnlinePlayers(), $pk); $px = $pos->x; if ($px < 0) { $px = $px - 0.5 - 0.15; } else { $px = $px + 0.5 + 0.15; } $pk = new MoveEntityPacket(); $pk->entities = [[$eid, $px, $pos->y + 1 + 0.25, $pos->z + 0.5, 0, 0, 0]]; $pk->encode(); Server::broadcastPacket(Server::getInstance()->getOnlinePlayers(), $pk); }