From b7ca8aac5c6362b94a8f8916b0e6dee2d502a8a2 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Thu, 27 Feb 2014 00:02:28 +0100 Subject: [PATCH] New Tile structure --- src/Tile.php | 105 +++++++++++++++++++ src/tile/ChestTile.php | 111 ++++++++++++++++++++ src/tile/ContainerTileTrait.php | 178 ++++++++++++++++++++++++++++++++ src/tile/FurnaceTile.php | 112 ++++++++++++++++++++ src/tile/SignTile.php | 74 +++++++++++++ src/tile/SpawnableTile.php | 32 ++++++ 6 files changed, 612 insertions(+) create mode 100644 src/Tile.php create mode 100644 src/tile/ChestTile.php create mode 100644 src/tile/ContainerTileTrait.php create mode 100644 src/tile/FurnaceTile.php create mode 100644 src/tile/SignTile.php create mode 100644 src/tile/SpawnableTile.php diff --git a/src/Tile.php b/src/Tile.php new file mode 100644 index 000000000..8d4b3b18e --- /dev/null +++ b/src/Tile.php @@ -0,0 +1,105 @@ +id; + } + + + public function __construct(Level $level, NBTTag_Compound $nbt){ + $this->server = ServerAPI::request(); + $this->level = $level; + $this->namedtag = $nbt; + $this->normal = true; + $this->closed = false; + $this->name = ""; + $this->lastUpdate = microtime(true); + $this->scheduledUpdate = false; + $this->id = Tile::$tileCount++; + Tile::$list[$this->id] = $this; + $this->class = $this->namedtag->id; + $this->x = (int) $this->namedtag->x; + $this->y = (int) $this->namedtag->y; + $this->z = (int) $this->namedtag->z; + + $index = PMFLevel::getIndex($this->x >> 4, $this->z >> 4); + $this->level->tiles[$this->id] = $this; + $this->chunkIndex = $index; + $this->level->chunkTiles[$index][$this->id] = $this; + } + + public function update(){ + return false; + } + + public function close(){ + if($this->closed === false){ + $this->closed = true; + unset(Tile::$list[$this->id]); + $index = PMFLevel::getIndex($this->x >> 4, $this->z >> 4); + unset($this->level->tiles[$this->id]); + unset($this->level->chunkTiles[$index][$this->id]); + $this->server->api->dhandle("tile.remove", $t); + } + } + + public function __destruct(){ + $this->close(); + } + + public function getName(){ + return $this->name; + } + +} diff --git a/src/tile/ChestTile.php b/src/tile/ChestTile.php new file mode 100644 index 000000000..d69dbc6ad --- /dev/null +++ b/src/tile/ChestTile.php @@ -0,0 +1,111 @@ +namedtag->pairx) or !isset($this->namedtag->pairz)){ + return false; + } + return true; + } + + public function getPair(){ + if($this->isPaired()){ + return $this->server->api->tile->get(new Position((int) $this->namedtag->pairx, $this->y, (int) $this->namedtag->pairz, $this->level)); + } + return false; + } + + public function pairWith(Tile $tile){ + if($this->isPaired()or $tile->isPaired()){ + return false; + } + + $this->namedtag->pairx = $tile->x; + $this->namedtag->pairz = $tile->z; + + $tile->namedtag->pairx = $this->x; + $tile->namedtag->pairz = $this->z; + + $this->server->api->tile->spawnToAll($this); + $this->server->api->tile->spawnToAll($tile); + $this->server->handle("tile.update", $this); + $this->server->handle("tile.update", $tile); + } + + public function unpair(){ + if(!$this->isPaired()){ + return false; + } + + $tile = $this->getPair(); + unset($this->namedtag->pairx, $this->namedtag->pairz, $tile->namedtag->pairx, $tile->namedtag->pairz); + + $this->server->api->tile->spawnToAll($this); + $this->server->handle("tile.update", $this); + if($tile instanceof Tile){ + $this->server->api->tile->spawnToAll($tile); + $this->server->handle("tile.update", $tile); + } + } + + public function spawn(Player $player){ + if($this->closed){ + return false; + } + + $nbt = new NBT(NBT::LITTLE_ENDIAN); + if($this->isPaired()){ + $nbt->setData(new NBTTag_Compound("", array( + new NBTTag_String("id", $this->class), + new NBTTag_Int("x", (int) $this->x), + new NBTTag_Int("y", (int) $this->y), + new NBTTag_Int("z", (int) $this->z), + new NBTTag_Int("pairx", (int) $this->namedtag->pairx), + new NBTTag_Int("pairz", (int) $this->namedtag->pairz) + ))); + }else{ + $nbt->setData(new NBTTag_Compound("", array( + new NBTTag_String("id", $this->class), + new NBTTag_Int("x", (int) $this->x), + new NBTTag_Int("y", (int) $this->y), + new NBTTag_Int("z", (int) $this->z) + ))); + } + + $pk = new EntityDataPacket; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->namedtag = $nbt->write(); + $player->dataPacket($pk); + + } +} \ No newline at end of file diff --git a/src/tile/ContainerTileTrait.php b/src/tile/ContainerTileTrait.php new file mode 100644 index 000000000..7c0a0c066 --- /dev/null +++ b/src/tile/ContainerTileTrait.php @@ -0,0 +1,178 @@ +class === Tile::CHEST){ + $player->windowCnt++; + $player->windowCnt = $id = max(2, $player->windowCnt % 99); + if(($pair = $this->getPair()) !== false){ + if(($pair->x + ($pair->z << 13)) > ($this->x + ($this->z << 13))){ //Order them correctly + $player->windows[$id] = array( + $pair, + $this + ); + }else{ + $player->windows[$id] = array( + $this, + $pair + ); + } + }else{ + $player->windows[$id] = $this; + } + + $pk = new ContainerOpenPacket; + $pk->windowid = $id; + $pk->type = WINDOW_CHEST; + $pk->slots = is_array($player->windows[$id]) ? ChestTile::SLOTS << 1:ChestTile::SLOTS; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $player->dataPacket($pk); + $slots = array(); + + if(is_array($player->windows[$id])){ + $all = $this->server->api->player->getAll($this->level); + foreach($player->windows[$id] as $ob){ + $pk = new TileEventPacket; + $pk->x = $ob->x; + $pk->y = $ob->y; + $pk->z = $ob->z; + $pk->case1 = 1; + $pk->case2 = 2; + $this->server->api->player->broadcastPacket($all, $pk); + for($s = 0; $s < ChestTile::SLOTS; ++$s){ + $slot = $ob->getSlot($s); + if($slot->getID() > AIR and $slot->count > 0){ + $slots[] = $slot; + }else{ + $slots[] = BlockAPI::getItem(AIR, 0, 0); + } + } + } + }else{ + $pk = new TileEventPacket; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->case1 = 1; + $pk->case2 = 2; + $this->server->api->player->broadcastPacket($this->server->api->player->getAll($this->level), $pk); + for($s = 0; $s < ChestTile::SLOTS; ++$s){ + $slot = $this->getSlot($s); + if($slot->getID() > AIR and $slot->count > 0){ + $slots[] = $slot; + }else{ + $slots[] = BlockAPI::getItem(AIR, 0, 0); + } + } + } + + $pk = new ContainerSetContentPacket; + $pk->windowid = $id; + $pk->slots = $slots; + $player->dataPacket($pk); + return true; + }elseif($this->class === Tile::FURNACE){ + $player->windowCnt++; + $player->windowCnt = $id = max(2, $player->windowCnt % 99); + $player->windows[$id] = $this; + + $pk = new ContainerOpenPacket; + $pk->windowid = $id; + $pk->type = WINDOW_FURNACE; + $pk->slots = FurnaceTile::SLOTS; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $player->dataPacket($pk); + + $slots = array(); + for($s = 0; $s < FurnaceTile::SLOTS; ++$s){ + $slot = $this->getSlot($s); + if($slot->getID() > AIR and $slot->count > 0){ + $slots[] = $slot; + }else{ + $slots[] = BlockAPI::getItem(AIR, 0, 0); + } + } + $pk = new ContainerSetContentPacket; + $pk->windowid = $id; + $pk->slots = $slots; + $player->dataPacket($pk); + return true; + } + } + + public function getSlotIndex($s){ + if($this->class !== Tile::CHEST and $this->class !== Tile::FURNACE){ + return false; + } + foreach($this->namedtag->Items as $i => $slot){ + if($slot->Slot === $s){ + return $i; + } + } + return -1; + } + + public function getSlot($s){ + $i = $this->getSlotIndex($s); + if($i === false or $i < 0){ + return BlockAPI::getItem(AIR, 0, 0); + }else{ + return BlockAPI::getItem($this->namedtag->Items[$i]->id, $this->namedtag->Items[$i]->Damage, $this->namedtag->Items[$i]->Count); + } + } + + public function setSlot($s, Item $item, $update = true, $offset = 0){ + $i = $this->getSlotIndex($s); + $d = new NBTTag_Compound(false, array( + "Count" => new NBTTag_Byte("Count", $item->count), + "Slot" => new NBTTag_Byte("Slot", $s), + "id" => new NBTTag_Short("id", $item->getID()), + "Damage" => new NBTTag_Short("Damage", $item->getMetadata()), + )); + if($i === false){ + return false; + }elseif($item->getID() === AIR or $item->count <= 0){ + if($i >= 0){ + unset($this->namedtag->Items[$i]); + } + }elseif($i < 0){ + $this->namedtag->Items[] = $d; + }else{ + $this->namedtag->Items[$i] = $d; + } + $this->server->api->dhandle("tile.container.slot", array( + "tile" => $this, + "slot" => $s, + "offset" => $offset, + "slotdata" => $item, + )); + + if($update === true and $this->scheduledUpdate === false){ + $this->update(); + } + return true; + } +} \ No newline at end of file diff --git a/src/tile/FurnaceTile.php b/src/tile/FurnaceTile.php new file mode 100644 index 000000000..ad264d69d --- /dev/null +++ b/src/tile/FurnaceTile.php @@ -0,0 +1,112 @@ +namedtag->BurnTime) or $this->namedtag->BurnTime < 0){ + $this->namedtag->BurnTime = 0; + } + if(!isset($this->namedtag->CookTime) or $this->namedtag->CookTime < 0 or ($this->namedtag->BurnTime === 0 and $this->namedtag->CookTime > 0)){ + $this->namedtag->CookTime = 0; + } + if(!isset($this->namedtag->MaxTime)){ + $this->namedtag->MaxTime = $this->namedtag->BurnTime; + $this->namedtag->BurnTicks = 0; + } + if($this->namedtag->BurnTime > 0){ + $this->update(); + } + } + + public function update(){ + if($this->closed === true){ + return false; + } + + $fuel = $this->getSlot(1); + $raw = $this->getSlot(0); + $product = $this->getSlot(2); + $smelt = $raw->getSmeltItem(); + $canSmelt = ($smelt !== false and $raw->count > 0 and (($product->getID() === $smelt->getID() and $product->getMetadata() === $smelt->getMetadata() and $product->count < $product->getMaxStackSize()) or $product->getID() === AIR)); + if($this->namedtag->BurnTime <= 0 and $canSmelt and $fuel->getFuelTime() !== false and $fuel->count > 0){ + $this->lastUpdate = microtime(true); + $this->namedtag->MaxTime = $this->namedtag->BurnTime = floor($fuel->getFuelTime() * 20); + $this->namedtag->BurnTicks = 0; + --$fuel->count; + if($fuel->count === 0){ + $fuel = BlockAPI::getItem(AIR, 0, 0); + } + $this->setSlot(1, $fuel, false); + $current = $this->level->getBlock($this); + if($current->getID() === FURNACE){ + $this->level->setBlock($this, BlockAPI::get(BURNING_FURNACE, $current->getMetadata()), true, false, true); + } + } + if($this->namedtag->BurnTime > 0){ + $ticks = (microtime(true) - $this->lastUpdate) * 20; + $this->namedtag->BurnTime -= $ticks; + $this->namedtag->BurnTicks = ceil(($this->namedtag->BurnTime / $this->namedtag->MaxTime) * 200); + if($smelt !== false and $canSmelt){ + $this->namedtag->CookTime += $ticks; + if($this->namedtag->CookTime >= 200){ //10 seconds + $product = BlockAPI::getItem($smelt->getID(), $smelt->getMetadata(), $product->count + 1); + $this->setSlot(2, $product, false); + --$raw->count; + if($raw->count === 0){ + $raw = BlockAPI::getItem(AIR, 0, 0); + } + $this->setSlot(0, $raw, false); + $this->namedtag->CookTime -= 200; + } + }elseif($this->namedtag->BurnTime <= 0){ + $this->namedtag->BurnTime = 0; + $this->namedtag->CookTime = 0; + $this->namedtag->BurnTicks = 0; + }else{ + $this->namedtag->CookTime = 0; + } + $this->server->schedule(2, array($this, "update")); + $this->scheduledUpdate = true; + }else{ + $current = $this->level->getBlock($this); + if($current->getID() === BURNING_FURNACE){ + $this->level->setBlock($this, BlockAPI::get(FURNACE, $current->getMetadata()), true, false, true); + } + $this->namedtag->CookTime = 0; + $this->namedtag->BurnTime = 0; + $this->namedtag->BurnTicks = 0; + $this->scheduledUpdate = false; + } + + + $this->server->handle("tile.update", $this); + $this->lastUpdate = microtime(true); + } +} \ No newline at end of file diff --git a/src/tile/SignTile.php b/src/tile/SignTile.php new file mode 100644 index 000000000..b842c047e --- /dev/null +++ b/src/tile/SignTile.php @@ -0,0 +1,74 @@ +class !== Tile::SIGN){ + return false; + } + $this->namedtag->Text1 = $line1; + $this->namedtag->Text2 = $line2; + $this->namedtag->Text3 = $line3; + $this->namedtag->Text4 = $line4; + $this->server->api->tile->spawnToAll($this); + $this->server->handle("tile.update", $this); + return true; + } + + public function getText(){ + return array( + $this->namedtag->Text1, + $this->namedtag->Text2, + $this->namedtag->Text3, + $this->namedtag->Text4 + ); + } + + public function spawn(Player $player){ + if($this->closed){ + return false; + } + + $nbt = new NBT(NBT::LITTLE_ENDIAN); + $nbt->setData(new NBTTag_Compound("", array( + new NBTTag_String("Text1", $this->namedtag->Text1), + new NBTTag_String("Text2", $this->namedtag->Text2), + new NBTTag_String("Text3", $this->namedtag->Text3), + new NBTTag_String("Text4", $this->namedtag->Text4), + new NBTTag_String("id", $this->class), + new NBTTag_Int("x", (int) $this->x), + new NBTTag_Int("y", (int) $this->y), + new NBTTag_Int("z", (int) $this->z) + ))); + $pk = new EntityDataPacket; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->namedtag = $nbt->write(); + $player->dataPacket($pk); + } + +} diff --git a/src/tile/SpawnableTile.php b/src/tile/SpawnableTile.php new file mode 100644 index 000000000..813651f31 --- /dev/null +++ b/src/tile/SpawnableTile.php @@ -0,0 +1,32 @@ +level->getPlayers() as $player){ + if($player->eid !== false or $player->spawned !== true){ + $this->spawn($player); + } + } + } +} \ No newline at end of file