diff --git a/src/Player.php b/src/Player.php index 50ea5e1a06..1f4a11193b 100644 --- a/src/Player.php +++ b/src/Player.php @@ -365,16 +365,36 @@ class Player{ public function eventHandler($data, $event){ switch($event){ + case "tile.update": + if($data->level === $this->level and $data->class === TILE_FURNACE){ + foreach($this->windows as $id => $w){ + if($w === $data){ + $this->dataPacket(MC_CONTAINER_SET_DATA, array( + "windowid" => $id, + "property" => 0, //Smelting + "value" => floor($data->data["CookTime"]), + )); + $this->dataPacket(MC_CONTAINER_SET_DATA, array( + "windowid" => $id, + "property" => 1, //Fire icon + "value" => $data->data["BurnTicks"], + )); + } + } + } + break; case "tile.container.slot": - foreach($this->windows as $id => $w){ - if($w === $data["tile"]){ - $this->dataPacket(MC_CONTAINER_SET_SLOT, array( - "windowid" => $id, - "slot" => $data["slot"], - "block" => $data["slotdata"]->getID(), - "stack" => $data["slotdata"]->count, - "meta" => $data["slotdata"]->getMetadata(), - )); + if($data["tile"]->level === $this->level){ + foreach($this->windows as $id => $w){ + if($w === $data["tile"]){ + $this->dataPacket(MC_CONTAINER_SET_SLOT, array( + "windowid" => $id, + "slot" => $data["slot"], + "block" => $data["slotdata"]->getID(), + "stack" => $data["slotdata"]->count, + "meta" => $data["slotdata"]->getMetadata(), + )); + } } } break; @@ -924,6 +944,7 @@ class Player{ $this->evid[] = $this->server->event("player.armor", array($this, "eventHandler")); $this->evid[] = $this->server->event("player.pickup", array($this, "eventHandler")); $this->evid[] = $this->server->event("tile.container.slot", array($this, "eventHandler")); + $this->evid[] = $this->server->event("tile.update", array($this, "eventHandler")); $this->server->schedule(40, array($this, "measureLag"), array(), true); console("[INFO] \x1b[33m".$this->username."\x1b[0m[/".$this->ip.":".$this->port."] logged in with entity id ".$this->eid." at (".$this->entity->level->getName().", ".round($this->entity->x, 2).", ".round($this->entity->y, 2).", ".round($this->entity->z, 2).")"); break; diff --git a/src/constants/ProtocolInfo.php b/src/constants/ProtocolInfo.php index c4a5c7db35..d13f94a34a 100644 --- a/src/constants/ProtocolInfo.php +++ b/src/constants/ProtocolInfo.php @@ -87,7 +87,7 @@ define("MC_DROP_ITEM", 0xad); define("MC_CONTAINER_OPEN", 0xae); define("MC_CONTAINER_CLOSE", 0xaf); define("MC_CONTAINER_SET_SLOT", 0xb0); -//define("MC_CONTAINER_SET_DATA", 0xb1); +define("MC_CONTAINER_SET_DATA", 0xb1); define("MC_CONTAINER_SET_CONTENT", 0xb2); //define("MC_CONTAINER_ACK", 0xb3); define("MC_CLIENT_MESSAGE", 0xb4); diff --git a/src/material/Item.php b/src/material/Item.php index 2b70618ac1..aebc685627 100644 --- a/src/material/Item.php +++ b/src/material/Item.php @@ -105,6 +105,30 @@ class Item{ return $this->maxStackSize; } + final public function getFuelTime(){ + if(!isset(FuelData::$duration[$this->id])){ + return false; + } + return FuelData::$duration[$this->id]; + } + + final public function getSmeltItem(){ + if(!isset(SmeltingData::$product[$this->id])){ + return false; + } + + if(isset(SmeltingData::$product[$this->id][0]) and !is_array(SmeltingData::$product[$this->id][0])){ + return BlockAPI::getItem(SmeltingData::$product[$this->id][0], SmeltingData::$product[$this->id][1]); + } + + if(!isset(SmeltingData::$product[$this->id][$this->meta])){ + return false; + } + + return BlockAPI::getItem(SmeltingData::$product[$this->id][$this->meta][0], SmeltingData::$product[$this->id][$this->meta][1]); + + } + final public function isPickaxe(){ //Returns false or level of the pickaxe switch($this->id){ case IRON_PICKAXE: diff --git a/src/material/block/solid/BurningFurnace.php b/src/material/block/solid/BurningFurnace.php index 03e8ab0aad..1e10a5fa14 100644 --- a/src/material/block/solid/BurningFurnace.php +++ b/src/material/block/solid/BurningFurnace.php @@ -96,10 +96,12 @@ class BurningFurnaceBlock extends SolidBlock{ "title" => "Furnace", )); $slots = array(); - for($s = 0; $s < FURNACE_SLOTS; ++$s){ + for($s = 0; $s <= FURNACE_SLOTS; ++$s){ $slot = $furnace->getSlot($s); if($slot->getID() > 0 and $slot->count > 0){ $slots[] = $slot; + }else{ + $slots[] = BlockAPI::getItem(AIR, 0, 0); } } $player->dataPacket(MC_CONTAINER_SET_CONTENT, array( diff --git a/src/material/block/solid/Chest.php b/src/material/block/solid/Chest.php index df034d32ca..15e3bfe628 100644 --- a/src/material/block/solid/Chest.php +++ b/src/material/block/solid/Chest.php @@ -113,10 +113,12 @@ class ChestBlock extends TransparentBlock{ "title" => "Chest", )); $slots = array(); - for($s = 0; $s < CHEST_SLOTS; ++$s){ + for($s = 0; $s <= CHEST_SLOTS; ++$s){ $slot = $chest->getSlot($s); if($slot->getID() > 0 and $slot->count > 0){ $slots[] = $slot; + }else{ + $slots[] = BlockAPI::getItem(AIR, 0, 0); } } $player->dataPacket(MC_CONTAINER_SET_CONTENT, array( diff --git a/src/material/item/generic/Coal.php b/src/material/item/generic/Coal.php index 8548e045b4..dfbe5c9dc1 100644 --- a/src/material/item/generic/Coal.php +++ b/src/material/item/generic/Coal.php @@ -27,7 +27,7 @@ the Free Software Foundation, either version 3 of the License, or class CoalItem extends Item{ public function __construct($meta = 0, $count = 1){ - parent::__construct(COAL, 0, $count, "Coal"); + parent::__construct(COAL, $meta & 0x01, $count, "Coal"); } } \ No newline at end of file diff --git a/src/network/CustomPacketHandler.php b/src/network/CustomPacketHandler.php index ccbcc860a3..49d5a19b2d 100644 --- a/src/network/CustomPacketHandler.php +++ b/src/network/CustomPacketHandler.php @@ -718,6 +718,17 @@ class CustomPacketHandler{ } } break; + case MC_CONTAINER_SET_DATA: + if($this->c === false){ + $this->data["windowid"] = ord($this->get(1)); + $this->data["property"] = Utils::readShort($this->get(2)); + $this->data["value"] = Utils::readShort($this->get(2)); + }else{ + $this->raw .= chr($this->data["windowid"]); + $this->raw .= Utils::writeShort($this->data["property"]); + $this->raw .= Utils::writeShort($this->data["value"]); + } + break; case MC_CLIENT_MESSAGE: if($this->c === false){ $this->data["message"] = $this->get(Utils::readShort($this->get(2), false)); diff --git a/src/recipes/FuelData.php b/src/recipes/FuelData.php new file mode 100644 index 0000000000..8b403d63e0 --- /dev/null +++ b/src/recipes/FuelData.php @@ -0,0 +1,52 @@ + 80, + TRUNK => 15, + WOODEN_PLANKS => 15, + SAPLING => 5, + WOODEN_AXE => 10, + WOODEN_PICKAXE => 10, + WOODEN_SWORD => 10, + WOODEN_SHOVEL => 10, + WOODEN_HOE => 10, + STICK => 5, + FENCE => 15, + FENCE_GATE => 15, + WOODEN_STAIRS => 15, + TRAPDOOR => 15, + WORKBENCH => 15, + BOOKSHELF => 15, + CHEST => 15, + LAVA_BUCKET => 1000, + + ); + +} \ No newline at end of file diff --git a/src/recipes/SmeltingData.php b/src/recipes/SmeltingData.php new file mode 100644 index 0000000000..0198f6e962 --- /dev/null +++ b/src/recipes/SmeltingData.php @@ -0,0 +1,46 @@ + array(STONE, 0), + SAND => array(GLASS, 0), + TRUNK => array(COAL, 1), //Charcoal + GOLD_ORE => array(GOLD_INGOT, 0), + IRON_ORE => array(IRON_INGOT, 0), + NETHERRACK => array(NETHER_BRICK, 0), + RAW_PORKCHOP => array(COOKED_PORKCHOP, 0), + CLAY => array(BRICK, 0), + RAW_FISH => array(COOKED_FISH, 0), + CACTUS => array(DYE, 2), + RED_MUSHROOM => array(DYE, 1), + RAW_BEEF => array(STEAK, 0), + RAW_CHICKEN => array(COOKED_CHICKEN, 0), + ); + +} \ No newline at end of file diff --git a/src/world/TileEntity.php b/src/world/TileEntity.php index 353c22d72d..b46be2aa6f 100644 --- a/src/world/TileEntity.php +++ b/src/world/TileEntity.php @@ -49,6 +49,8 @@ class TileEntity extends Position{ $this->closed = true; } $this->name = ""; + $this->lastUpdate = microtime(true); + $this->scheduledUpdate = false; $this->id = (int) $id; $this->x = (int) $x; $this->y = (int) $y; @@ -57,7 +59,21 @@ class TileEntity extends Position{ switch($this->class){ case TILE_SIGN: $this->server->query("UPDATE tileentities SET spawnable = 1 WHERE ID = ".$this->id.";"); - + break; + case TILE_FURNACE: + if(!isset($this->data["BurnTime"]) or $this->data["BurnTime"] < 0){ + $this->data["BurnTime"] = 0; + } + if(!isset($this->data["CookTime"]) or $this->data["CookTime"] < 0 or ($this->data["BurnTime"] === 0 and $this->data["CookTime"] > 0)){ + $this->data["CookTime"] = 0; + } + if(!isset($this->data["MaxTime"])){ + $this->data["MaxTime"] = $this->data["BurnTime"]; + $this->data["BurnTicks"] = 0; + } + if($this->data["BurnTime"] > 0){ + $this->update(); + } break; } } @@ -65,7 +81,67 @@ class TileEntity extends Position{ public function update(){ if($this->closed === true){ return false; + } + + if($this->class === TILE_FURNACE){ + $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->data["BurnTime"] <= 0 and $canSmelt and $fuel->getFuelTime() !== false and $fuel->count > 0){ + $this->lastUpdate = microtime(true); + $this->data["MaxTime"] = $this->data["BurnTime"] = floor($fuel->getFuelTime() * 20); + $this->data["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())); + } + } + if($this->data["BurnTime"] > 0){ + $ticks = (microtime(true) - $this->lastUpdate) * 20; + $this->data["BurnTime"] -= $ticks; + $this->data["BurnTicks"] = ceil(($this->data["BurnTime"] / $this->data["MaxTime"]) * 200); + if($smelt !== false and $canSmelt){ + $this->data["CookTime"] += $ticks; + if($this->data["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->data["CookTime"] -= 200; + } + }elseif($this->data["BurnTime"] <= 0){ + $this->data["BurnTime"] = 0; + $this->data["CookTime"] = 0; + $this->data["BurnTicks"] = 0; + }else{ + $this->data["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())); + } + $this->data["CookTime"] = 0; + $this->data["BurnTime"] = 0; + $this->data["BurnTicks"] = 0; + $this->scheduledUpdate = false; + } } + $this->server->handle("tile.update", $this); + $this->lastUpdate = microtime(true); } public function getSlotIndex($s){ @@ -89,7 +165,7 @@ class TileEntity extends Position{ } } - public function setSlot($s, Item $item){ + public function setSlot($s, Item $item, $update = true){ $i = $this->getSlotIndex($s); $d = array( "Count" => $item->count, @@ -113,7 +189,10 @@ class TileEntity extends Position{ "slot" => $s, "slotdata" => $item, )); - $this->server->handle("tile.update", $this); + + if($update === true and $this->scheduledUpdate === false){ + $this->update(); + } return true; }