diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 3b241b45d..4fece9d80 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -35,7 +35,6 @@ use pocketmine\event\block\SignChangeEvent; use pocketmine\event\entity\EntityDamageByBlockEvent; use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\entity\EntityDamageEvent; -use pocketmine\event\entity\EntityRegainHealthEvent; use pocketmine\event\entity\EntityShootBowEvent; use pocketmine\event\entity\ProjectileLaunchEvent; use pocketmine\event\inventory\CraftItemEvent; @@ -50,6 +49,7 @@ use pocketmine\event\player\PlayerChatEvent; use pocketmine\event\player\PlayerCommandPreprocessEvent; use pocketmine\event\player\PlayerDeathEvent; use pocketmine\event\player\PlayerDropItemEvent; +use pocketmine\event\player\PlayerExhaustEvent; use pocketmine\event\player\PlayerGameModeChangeEvent; use pocketmine\event\player\PlayerInteractEvent; use pocketmine\event\player\PlayerItemConsumeEvent; @@ -123,6 +123,7 @@ use pocketmine\network\protocol\SetTimePacket; use pocketmine\network\protocol\StartGamePacket; use pocketmine\network\protocol\TakeItemEntityPacket; use pocketmine\network\protocol\TextPacket; +use pocketmine\network\protocol\UpdateAttributesPacket; use pocketmine\network\protocol\UpdateBlockPacket; use pocketmine\network\SourceInterface; use pocketmine\permission\PermissibleBase; @@ -245,7 +246,8 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade /** * This might disappear in the future. - * Please use getUniqueId() instead (IP + clientId + name combo, in the future it'll change to real UUID for online auth) + * Please use getUniqueId() instead (IP + clientId + name combo, in the future it'll change to real UUID for online + * auth) * * @deprecated * @@ -484,7 +486,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade return $this->perm->getEffectivePermissions(); } - /** * @param SourceInterface $interface * @param null $clientID @@ -600,7 +601,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade public function isSleeping(){ return $this->sleeping !== null; } - + public function getInAirTicks(){ return $this->inAirTicks; } @@ -855,7 +856,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->loadQueue = $newOrder; - Timings::$playerChunkOrderTimer->stopTiming(); return true; @@ -986,12 +986,12 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->level->sleepTicks = 60; - return true; } /** - * Sets the spawnpoint of the player (and the compass direction) to a Vector3, or set it on another world with a Position object + * Sets the spawnpoint of the player (and the compass direction) to a Vector3, or set it on another world with a + * Position object * * @param Vector3|Position $pos */ @@ -1017,7 +1017,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->setDataProperty(self::DATA_PLAYER_BED_POSITION, self::DATA_TYPE_POS, [0, 0, 0]); $this->setDataFlag(self::DATA_PLAYER_FLAGS, self::DATA_PLAYER_FLAG_SLEEP, false); - $this->level->sleepTicks = 0; $pk = new AnimatePacket(); @@ -1025,7 +1024,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $pk->action = 3; //Wake up $this->dataPacket($pk); } - } /** @@ -1213,6 +1211,23 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade return false; } + public function entityBaseTick($tickDiff = 1){ + $hasUpdate = parent::entityBaseTick($tickDiff); + + $entries = $this->attributeMap->needSend(); + if(count($entries) > 0){ + $pk = new UpdateAttributesPacket(); + $pk->entityId = 0; + $pk->entries = $entries; + $this->dataPacket($pk); + foreach($entries as $entry){ + $entry->markSynchronized(); + } + } + + return $hasUpdate; + } + protected function checkGroundState($movX, $movY, $movZ, $dx, $dy, $dz){ if(!$this->onGround or $movY != 0){ $bb = clone $this->boundingBox; @@ -1448,7 +1463,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade } protected function updateMovement(){ - } public function onUpdate($currentTick){ @@ -1531,7 +1545,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->server->batchPackets([$this], $this->batchedPackets, false); $this->batchedPackets = []; } - } public function canInteract(Vector3 $pos, $maxDistance, $maxDiff = 0.5){ @@ -1612,7 +1625,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->allowFlight = $this->isCreative(); - if(($level = $this->server->getLevelByName($nbt["Level"])) === null){ $this->setLevel($this->server->getDefaultLevel()); $nbt["Level"] = $this->level->getName(); @@ -1631,7 +1643,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->achievements = []; - /** @var Byte $achievement */ + /** @var ByteTag $achievement */ foreach($nbt->Achievements as $achievement){ $this->achievements[$achievement->getName()] = $achievement->getValue() > 0 ? true : false; } @@ -1752,7 +1764,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade return; } - $timings = Timings::getReceiveDataPacketTimings($packet); $timings->startTiming(); @@ -1950,7 +1961,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); if(!$this->canInteract($blockVector->add(0.5, 0.5, 0.5), 13) or $this->isSpectator()){ - }elseif($this->isCreative()){ $item = $this->inventory->getItemInHand(); if($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this) === true){ @@ -2082,7 +2092,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade break; } - $nbt = new CompoundTag("", [ "Pos" => new ListTag("Pos", [ new DoubleTag("", $this->x), @@ -2255,7 +2264,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $vector = new Vector3($packet->x, $packet->y, $packet->z); - if($this->isCreative()){ $item = $this->inventory->getItemInHand(); }else{ @@ -2270,6 +2278,8 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->inventory->setItemInHand($item); $this->inventory->sendHeldItem($this->hasSpawned); } + + $this->exhaust(0.025, PlayerExhaustEvent::CAUSE_MINING); } break; } @@ -2309,7 +2319,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade if( $target instanceof Player and $this->server->getConfigBoolean("pvp", true) === false - ){ $cancelled = true; } @@ -2407,16 +2416,19 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade break; } - if($item->isTool() and $this->isSurvival()){ - if($item->useOn($target) and $item->getDamage() >= $item->getMaxDurability()){ - $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1)); - }else{ - $this->inventory->setItemInHand($item); + if($this->isSurvival()){ + if($item->isTool()){ + if($item->useOn($target) and $item->getDamage() >= $item->getMaxDurability()){ + $this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1)); + }else{ + $this->inventory->setItemInHand($item); + } } + + $this->exhaust(0.3, PlayerExhaustEvent::CAUSE_ATTACK); } } - break; case ProtocolInfo::ANIMATE_PACKET: if($this->spawned === false or !$this->isAlive()){ @@ -2444,65 +2456,19 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false); //TODO: check if this should be true switch($packet->event){ - case 9: //Eating - $items = [ //TODO: move this to item classes - Item::APPLE => 4, - Item::MUSHROOM_STEW => 10, - Item::BEETROOT_SOUP => 10, - Item::BREAD => 5, - Item::RAW_PORKCHOP => 3, - Item::COOKED_PORKCHOP => 8, - Item::RAW_BEEF => 3, - Item::STEAK => 8, - Item::COOKED_CHICKEN => 6, - Item::RAW_CHICKEN => 2, - Item::MELON_SLICE => 2, - Item::GOLDEN_APPLE => 10, - Item::PUMPKIN_PIE => 8, - Item::CARROT => 4, - Item::POTATO => 1, - Item::BAKED_POTATO => 6, - Item::COOKIE => 2, - Item::COOKED_FISH => [ - 0 => 5, - 1 => 6 - ], - Item::RAW_FISH => [ - 0 => 2, - 1 => 2, - 2 => 1, - 3 => 1 - ], - ]; + case EntityEventPacket::USE_ITEM: //Eating $slot = $this->inventory->getItemInHand(); - if($this->getHealth() < $this->getMaxHealth() and isset($items[$slot->getId()])){ - $this->server->getPluginManager()->callEvent($ev = new PlayerItemConsumeEvent($this, $slot)); - if($ev->isCancelled()){ + + if($slot->canBeConsumed()){ + $ev = new PlayerItemConsumeEvent($this, $slot); + if(!$slot->canBeConsumedBy($this)){ + $ev->setCancelled(); + } + $this->server->getPluginManager()->callEvent($ev); + if(!$ev->isCancelled()){ + $slot->onConsume($this); + }else{ $this->inventory->sendContents($this); - break; - } - - $pk = new EntityEventPacket(); - $pk->eid = $this->getId(); - $pk->event = EntityEventPacket::USE_ITEM; - $this->dataPacket($pk); - Server::broadcastPacket($this->getViewers(), $pk); - - $amount = $items[$slot->getId()]; - if(is_array($amount)){ - $amount = isset($amount[$slot->getDamage()]) ? $amount[$slot->getDamage()] : 0; - } - $ev = new EntityRegainHealthEvent($this, $amount, EntityRegainHealthEvent::CAUSE_EATING); - $this->heal($ev->getAmount(), $ev); - - --$slot->count; - $this->inventory->setItemInHand($slot); - if($slot->getId() === Item::MUSHROOM_STEW or $slot->getId() === Item::BEETROOT_SOUP){ - $this->inventory->addItem(Item::get(Item::BOWL, 0, 1)); - }elseif($slot->getId() === Item::RAW_FISH and $slot->getDamage() === 3){ //Pufferfish - //$this->addEffect(Effect::getEffect(Effect::HUNGER)->setAmplifier(2)->setDuration(15 * 20)); - $this->addEffect(Effect::getEffect(Effect::NAUSEA)->setAmplifier(1)->setDuration(15 * 20)); - $this->addEffect(Effect::getEffect(Effect::POISON)->setAmplifier(3)->setDuration(60 * 20)); } } break; @@ -2604,7 +2570,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $canCraft = true; - if($recipe instanceof ShapedRecipe){ for($x = 0; $x < 3 and $canCraft; ++$x){ for($y = 0; $y < 3; ++$y){ @@ -2792,7 +2757,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade break; } - if($this->currentTransaction === null or $this->currentTransaction->getCreationTime() < (microtime(true) - 8)){ if($this->currentTransaction !== null){ foreach($this->currentTransaction->getInventories() as $inventory){ @@ -2934,7 +2898,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade return; } $message = $message->getText(); - } $mes = explode("\n", $this->server->getLanguage()->translateString($message)); @@ -3225,7 +3188,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade break; default: - } Entity::kill(); @@ -3246,7 +3208,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->server->broadcast($ev->getDeathMessage(), Server::BROADCAST_CHANNEL_USERS); } - $pk = new RespawnPacket(); $pos = $this->getSpawn(); $pk->x = $pos->x; @@ -3288,6 +3249,10 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $pk->eid = 0; $pk->event = EntityEventPacket::HURT_ANIMATION; $this->dataPacket($pk); + + if($this->isSurvival()){ + $this->exhaust(0.3, PlayerExhaustEvent::CAUSE_DAMAGE); + } } } @@ -3431,7 +3396,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->forceMovement = new Vector3($this->x, $this->y, $this->z); $this->sendPosition($this, $this->yaw, $this->pitch, 1); - $this->resetFallDistance(); $this->orderChunks(); $this->nextChunkOrderRun = 0; @@ -3439,7 +3403,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade } } - /** * @param Inventory $inventory * @@ -3507,25 +3470,20 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade $this->server->getPlayerMetadata()->removeMetadata($this, $metadataKey, $plugin); } - public function onChunkChanged(FullChunk $chunk){ $this->loadQueue[Level::chunkHash($chunk->getX(), $chunk->getZ())] = abs(($this->x >> 4) - $chunk->getX()) + abs(($this->z >> 4) - $chunk->getZ()); } public function onChunkLoaded(FullChunk $chunk){ - } public function onChunkPopulated(FullChunk $chunk){ - } public function onChunkUnloaded(FullChunk $chunk){ - } public function onBlockChanged(Vector3 $block){ - } public function getLoaderId(){ @@ -3537,9 +3495,10 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade } /** - * @param $chunkX - * @param $chunkZ - * @param $payload + * @param int $chunkX + * @param int $chunkZ + * @param string $payload + * @param int $ordering * * @return DataPacket */ diff --git a/src/pocketmine/block/Cake.php b/src/pocketmine/block/Cake.php index d95b64a7c..e9c9a3880 100644 --- a/src/pocketmine/block/Cake.php +++ b/src/pocketmine/block/Cake.php @@ -21,14 +21,15 @@ namespace pocketmine\block; -use pocketmine\event\entity\EntityRegainHealthEvent; +use pocketmine\entity\Effect; +use pocketmine\event\entity\EntityEatBlockEvent; +use pocketmine\item\FoodSource; use pocketmine\item\Item; use pocketmine\level\Level; use pocketmine\math\AxisAlignedBB; use pocketmine\Player; - -class Cake extends Transparent{ +class Cake extends Transparent implements FoodSource{ protected $id = self::CAKE_BLOCK; @@ -91,18 +92,10 @@ class Cake extends Transparent{ public function onActivate(Item $item, Player $player = null){ if($player instanceof Player and $player->getHealth() < $player->getMaxHealth()){ - ++$this->meta; - - $ev = new EntityRegainHealthEvent($player, 3, EntityRegainHealthEvent::CAUSE_EATING); - $player->heal($ev->getAmount(), $ev); + $ev = new EntityEatBlockEvent($player, $this); if(!$ev->isCancelled()){ - if($this->meta >= 0x06){ - $this->getLevel()->setBlock($this, new Air(), true); - }else{ - $this->getLevel()->setBlock($this, $this, true); - } - + $this->getLevel()->setBlock($this, $ev->getResidue()); return true; } } @@ -110,4 +103,27 @@ class Cake extends Transparent{ return false; } + public function getFoodRestore() : int{ + return 2; + } + + public function getSaturationRestore() : float{ + return 0.4; + } + + public function getResidue(){ + $clone = clone $this; + $clone->meta++; + if($clone->meta >= 0x06){ + $clone = new Air(); + } + return $clone; + } + + /** + * @return Effect[] + */ + public function getAdditionalEffects() : array{ + return []; + } } diff --git a/src/pocketmine/entity/Attribute.php b/src/pocketmine/entity/Attribute.php index a312ed3a7..f6fb4b238 100644 --- a/src/pocketmine/entity/Attribute.php +++ b/src/pocketmine/entity/Attribute.php @@ -21,20 +21,20 @@ namespace pocketmine\entity; -use pocketmine\event\entity\EntityDamageEvent; -use pocketmine\event\entity\EntityRegainHealthEvent; -use pocketmine\network\Network; -use pocketmine\network\protocol\MobEffectPacket; -use pocketmine\Player; - - class Attribute{ - const MAX_HEALTH = 0; - - - const EXPERIENCE = 1; - const EXPERIENCE_LEVEL = 2; + const ABSORPTION = 0; + const SATURATION = 1; + const EXHAUSTION = 2; + const KNOCKBACK_RESISTANCE = 3; + const HEALTH = 4; + const MOVEMENT_SPEED = 5; + const FOLLOW_RANGE = 6; + const HUNGER = 7; + const FOOD = 7; + const ATTACK_DAMAGE = 8; + const EXPERIENCE_LEVEL = 9; + const EXPERIENCE = 10; private $id; protected $minValue; @@ -44,13 +44,23 @@ class Attribute{ protected $name; protected $shouldSend; + protected $desynchronized = true; + /** @var Attribute[] */ protected static $attributes = []; public static function init(){ - self::addAttribute(self::MAX_HEALTH, "generic.health", 0, 0x7fffffff, 20, true); - self::addAttribute(self::EXPERIENCE, "player.experience", 0, 1, 0, true); - self::addAttribute(self::EXPERIENCE_LEVEL, "player.level", 0, 24791, 0, true); + self::addAttribute(self::ABSORPTION, "generic.absorption", 0.00, 340282346638528859811704183484516925440.00, 0.00); + self::addAttribute(self::SATURATION, "player.saturation", 0.00, 20.00, 5.00); + self::addAttribute(self::EXHAUSTION, "player.exhaustion", 0.00, 5.00, 0.41); + self::addAttribute(self::KNOCKBACK_RESISTANCE, "generic.knockbackResistance", 0.00, 1.00, 0.00); + self::addAttribute(self::HEALTH, "generic.health", 0.00, 20.00, 20.00); + self::addAttribute(self::MOVEMENT_SPEED, "generic.movementSpeed", 0.00, 340282346638528859811704183484516925440.00, 0.10); + self::addAttribute(self::FOLLOW_RANGE, "generic.followRange", 0.00, 2048.00, 16.00, false); + self::addAttribute(self::HUNGER, "player.hunger", 0.00, 20.00, 20.00); + self::addAttribute(self::ATTACK_DAMAGE, "generic.attackDamage", 0.00, 340282346638528859811704183484516925440.00, 1.00, false); + self::addAttribute(self::EXPERIENCE_LEVEL, "player.level", 0.00, 24791.00, 0.00); + self::addAttribute(self::EXPERIENCE, "player.experience", 0.00, 1.00, 0.00); } /** @@ -60,9 +70,10 @@ class Attribute{ * @param float $maxValue * @param float $defaultValue * @param bool $shouldSend + * * @return Attribute */ - public static function addAttribute($id, $name, $minValue, $maxValue, $defaultValue, $shouldSend = false){ + public static function addAttribute($id, $name, $minValue, $maxValue, $defaultValue, $shouldSend = true){ if($minValue > $maxValue or $defaultValue > $maxValue or $defaultValue < $minValue){ throw new \InvalidArgumentException("Invalid ranges: min value: $minValue, max value: $maxValue, $defaultValue: $defaultValue"); } @@ -72,6 +83,7 @@ class Attribute{ /** * @param $id + * * @return null|Attribute */ public static function getAttribute($id){ @@ -80,6 +92,7 @@ class Attribute{ /** * @param $name + * * @return null|Attribute */ public static function getAttributeByName($name){ @@ -88,17 +101,17 @@ class Attribute{ return clone $a; } } - + return null; } - private function __construct($id, $name, $minValue, $maxValue, $defaultValue, $shouldSend = false){ + private function __construct($id, $name, $minValue, $maxValue, $defaultValue, $shouldSend = true){ $this->id = (int) $id; $this->name = (string) $name; $this->minValue = (float) $minValue; $this->maxValue = (float) $maxValue; $this->defaultValue = (float) $defaultValue; - $this->shouldSend = (float) $shouldSend; + $this->shouldSend = (bool) $shouldSend; $this->currentValue = $this->defaultValue; } @@ -106,13 +119,16 @@ class Attribute{ public function getMinValue(){ return $this->minValue; } - + public function setMinValue($minValue){ if($minValue > $this->getMaxValue()){ throw new \InvalidArgumentException("Value $minValue is bigger than the maxValue!"); } - $this->minValue = $minValue; + if($this->minValue != $minValue){ + $this->desynchronized = true; + $this->minValue = $minValue; + } return $this; } @@ -125,7 +141,10 @@ class Attribute{ throw new \InvalidArgumentException("Value $maxValue is bigger than the minValue!"); } - $this->maxValue = $maxValue; + if($this->maxValue != $maxValue){ + $this->desynchronized = true; + $this->maxValue = $maxValue; + } return $this; } @@ -138,7 +157,10 @@ class Attribute{ throw new \InvalidArgumentException("Value $defaultValue exceeds the range!"); } - $this->defaultValue = $defaultValue; + if($this->defaultValue !== $defaultValue){ + $this->desynchronized = true; + $this->defaultValue = $defaultValue; + } return $this; } @@ -146,13 +168,18 @@ class Attribute{ return $this->currentValue; } - public function setValue($value){ + public function setValue($value, $fit = false){ if($value > $this->getMaxValue() or $value < $this->getMinValue()){ - throw new \InvalidArgumentException("Value $value exceeds the range!"); + if(!$fit){ + throw new \InvalidArgumentException("Value $value exceeds the range!"); + } + $value = min(max($value, $this->getMinValue()), $this->getMaxValue()); } - $this->currentValue = $value; - + if($this->currentValue != $value){ + $this->desynchronized = true; + $this->currentValue = $value; + } return $this; } @@ -168,4 +195,11 @@ class Attribute{ return $this->shouldSend; } + public function isDesynchronized() : bool{ + return $this->shouldSend and $this->desynchronized; + } + + public function markSynchronized(bool $synced = true){ + $this->desynchronized = !$synced; + } } diff --git a/src/pocketmine/entity/AttributeMap.php b/src/pocketmine/entity/AttributeMap.php new file mode 100644 index 000000000..0c1960211 --- /dev/null +++ b/src/pocketmine/entity/AttributeMap.php @@ -0,0 +1,65 @@ +attributes[$attribute->getId()] = $attribute; + } + + /** + * @param int $id + * + * @return Attribute|null + */ + public function getAttribute(int $id){ + return $this->attributes[$id] ?? null; + } + + /** + * @return Attribute[] + */ + public function needSend() : array{ + return array_filter($this->attributes, function (Attribute $attribute){ + return $attribute->isSyncable() and $attribute->isDesynchronized(); + }); + } + + public function offsetExists($offset){ + return isset($this->attributes[$offset]); + } + + public function offsetGet($offset){ + return $this->attributes[$offset]->getValue(); + } + + public function offsetSet($offset, $value){ + $this->attributes[$offset]->setValue($value); + } + + public function offsetUnset($offset){ + throw new \RuntimeException("Could not unset an attribute from an attribute map"); + } +} diff --git a/src/pocketmine/entity/Effect.php b/src/pocketmine/entity/Effect.php index b10dc0d30..c6f2e17d3 100644 --- a/src/pocketmine/entity/Effect.php +++ b/src/pocketmine/entity/Effect.php @@ -23,11 +23,10 @@ namespace pocketmine\entity; use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityRegainHealthEvent; -use pocketmine\network\Network; +use pocketmine\event\player\PlayerExhaustEvent; use pocketmine\network\protocol\MobEffectPacket; use pocketmine\Player; - class Effect{ const SPEED = 1; const SLOWNESS = 2; @@ -36,8 +35,8 @@ class Effect{ const FATIGUE = 4; const MINING_FATIGUE = 4; const STRENGTH = 5; - //TODO: const HEALING = 6; - //TODO: const HARMING = 7; +// TODO: const HEALING = 6; +// TODO: const HARMING = 7; const JUMP = 8; const NAUSEA = 9; const CONFUSION = 9; @@ -46,15 +45,15 @@ class Effect{ const FIRE_RESISTANCE = 12; const WATER_BREATHING = 13; const INVISIBILITY = 14; - //const BLINDNESS = 15; - //const NIGHT_VISION = 16; - //const HUNGER = 17; + const BLINDNESS = 15; + const NIGHT_VISION = 16; + const HUNGER = 17; const WEAKNESS = 18; const POISON = 19; const WITHER = 20; const HEALTH_BOOST = 21; - //const ABSORPTION = 22; - //const SATURATION = 23; + const ABSORPTION = 22; // TODO implement + const SATURATION = 23; /** @var Effect[] */ protected static $effects; @@ -76,17 +75,20 @@ class Effect{ self::$effects[Effect::FIRE_RESISTANCE] = new Effect(Effect::FIRE_RESISTANCE, "%potion.fireResistance", 228, 154, 58); self::$effects[Effect::WATER_BREATHING] = new Effect(Effect::WATER_BREATHING, "%potion.waterBreathing", 46, 82, 153); self::$effects[Effect::INVISIBILITY] = new Effect(Effect::INVISIBILITY, "%potion.invisibility", 127, 131, 146); - //Hunger - self::$effects[Effect::WEAKNESS] = new Effect(Effect::WEAKNESS, "%potion.weakness", 72, 77, 72 , true); + self::$effects[Effect::BLINDNESS] = new Effect(Effect::BLINDNESS, "%potion.blindness", 191, 192, 192); + self::$effects[Effect::NIGHT_VISION] = new Effect(Effect::NIGHT_VISION, "%potion.nightVision", 0, 0, 139); + self::$effects[Effect::HUNGER] = new Effect(Effect::HUNGER, "%potion.hunger", 46, 139, 87); + self::$effects[Effect::WEAKNESS] = new Effect(Effect::WEAKNESS, "%potion.weakness", 72, 77, 72, true); self::$effects[Effect::POISON] = new Effect(Effect::POISON, "%potion.poison", 78, 147, 49, true); self::$effects[Effect::WITHER] = new Effect(Effect::WITHER, "%potion.wither", 53, 42, 39, true); self::$effects[Effect::HEALTH_BOOST] = new Effect(Effect::HEALTH_BOOST, "%potion.healthBoost", 248, 125, 35); - //Absorption - //Saturation + self::$effects[Effect::ABSORPTION] = new Effect(Effect::ABSORPTION, "%potion.absorption", 36, 107, 251); + self::$effects[Effect::SATURATION] = new Effect(Effect::SATURATION, "%potion.saturation", 255, 0, 255); } /** * @param int $id + * * @return $this */ public static function getEffect($id){ @@ -200,6 +202,14 @@ class Effect{ return ($this->duration % $interval) === 0; } return true; + case Effect::HUNGER: + if($this->amplifier < 0){ // prevents hacking with amplifier -1 + return false; + } + if(($interval = 20) > 0){ + return ($this->duration % $interval) === 0; + } + return true; } return false; } @@ -224,6 +234,11 @@ class Effect{ $entity->heal($ev->getAmount(), $ev); } break; + + case Effect::HUNGER: + if($entity instanceof Human){ + $entity->exhaust(0.5 * $this->amplifier, PlayerExhaustEvent::CAUSE_POTION); + } } } @@ -235,7 +250,7 @@ class Effect{ $this->color = (($r & 0xff) << 16) + (($g & 0xff) << 8) + ($b & 0xff); } - public function add(Entity $entity, $modify = false){ + public function add(Entity $entity, $modify = false, Effect $oldEffect = null){ if($entity instanceof Player){ $pk = new MobEffectPacket(); $pk->eid = 0; @@ -255,6 +270,24 @@ class Effect{ if($this->id === Effect::INVISIBILITY){ $entity->setDataFlag(Entity::DATA_FLAGS, Entity::DATA_FLAG_INVISIBLE, true); $entity->setDataProperty(Entity::DATA_SHOW_NAMETAG, Entity::DATA_TYPE_BYTE, 0); + }elseif($this->id === Effect::SPEED){ + $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); + if($modify and $oldEffect !== null){ + $speed = $attr->getValue() / (1 + 0.2 * $oldEffect->getAmplifier()); + }else{ + $speed = $attr->getValue(); + } + $speed *= (1 + 0.2 * $this->amplifier); + $attr->setValue($speed); + }elseif($this->id === Effect::SLOWNESS){ + $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); + if($modify and $oldEffect !== null){ + $speed = $attr->getValue() / (1 - 0.15 * $oldEffect->getAmplifier()); + }else{ + $speed = $attr->getValue(); + } + $speed *= (1 - 0.15 * $this->amplifier); + $attr->setValue($speed); } } @@ -271,6 +304,12 @@ class Effect{ if($this->id === Effect::INVISIBILITY){ $entity->setDataFlag(Entity::DATA_FLAGS, Entity::DATA_FLAG_INVISIBLE, false); $entity->setDataProperty(Entity::DATA_SHOW_NAMETAG, Entity::DATA_TYPE_BYTE, 1); + }elseif($this->id === Effect::SPEED){ + $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); + $attr->setValue($attr->getValue() / (1 + 0.2 * $this->amplifier)); + }elseif($this->id === Effect::SLOWNESS){ + $attr = $entity->getAttributeMap()->getAttribute(Attribute::MOVEMENT_SPEED); + $attr->setValue($attr->getValue() / (1 - 0.15 * $this->amplifier)); } } } diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index eabb01077..e386379e6 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -48,19 +48,17 @@ use pocketmine\metadata\MetadataValue; use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\DoubleTag; -use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\FloatTag; use pocketmine\nbt\tag\IntTag; +use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ShortTag; use pocketmine\nbt\tag\StringTag; -use pocketmine\network\Network; use pocketmine\network\protocol\MobEffectPacket; use pocketmine\network\protocol\RemoveEntityPacket; use pocketmine\network\protocol\SetEntityDataPacket; use pocketmine\Player; use pocketmine\plugin\Plugin; use pocketmine\Server; -use pocketmine\utils\ChunkException; abstract class Entity extends Location implements Metadatable{ @@ -191,6 +189,9 @@ abstract class Entity extends Location implements Metadatable{ protected $fireProof; private $invulnerable; + /** @var AttributeMap */ + protected $attributeMap; + protected $gravity; protected $drag; @@ -265,6 +266,8 @@ abstract class Entity extends Location implements Metadatable{ } $this->invulnerable = $this->namedtag["Invulnerable"] > 0 ? true : false; + $this->attributeMap = new AttributeMap(); + $this->chunk->addEntity($this); $this->level->addEntity($this); $this->initEntity(); @@ -316,7 +319,11 @@ abstract class Entity extends Location implements Metadatable{ } public function setSprinting($value = true){ - $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_SPRINTING, (bool) $value); + if($value !== $this->isSprinting()){ + $this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_SPRINTING, (bool) $value); + $attr = $this->attributeMap->getAttribute(Attribute::MOVEMENT_SPEED); + $attr->setValue($value ? ($attr->getValue() * 1.3) : ($attr->getValue() / 1.3)); + } } /** @@ -360,7 +367,7 @@ abstract class Entity extends Location implements Metadatable{ ){ return; } - $effect->add($this, true); + $effect->add($this, true, $oldEffect); }else{ $effect->add($this, false); } @@ -405,10 +412,10 @@ abstract class Entity extends Location implements Metadatable{ } /** - * @param int|string $type - * @param FullChunk $chunk - * @param CompoundTag $nbt - * @param $args + * @param int|string $type + * @param FullChunk $chunk + * @param CompoundTag $nbt + * @param $args * * @return Entity */ @@ -503,6 +510,17 @@ abstract class Entity extends Location implements Metadatable{ protected function initEntity(){ assert($this->namedtag instanceof CompoundTag); + if(isset($this->namedtag->CustomName)){ + $this->setNameTag($this->namedtag["CustomName"]); + if(isset($this->namedtag->CustomNameVisible)){ + $this->setNameTagVisible($this->namedtag["CustomNameVisible"] > 0); + } + } + + $this->scheduleUpdate(); + + $this->addAttributes(); + if(isset($this->namedtag->ActiveEffects)){ foreach($this->namedtag->ActiveEffects->getValue() as $e){ $effect = Effect::getEffect($e["Id"]); @@ -515,16 +533,9 @@ abstract class Entity extends Location implements Metadatable{ $this->addEffect($effect); } } + } - - if(isset($this->namedtag->CustomName)){ - $this->setNameTag($this->namedtag["CustomName"]); - if(isset($this->namedtag->CustomNameVisible)){ - $this->setNameTagVisible($this->namedtag["CustomNameVisible"] > 0); - } - } - - $this->scheduleUpdate(); + protected function addAttributes(){ } /** @@ -670,6 +681,10 @@ abstract class Entity extends Location implements Metadatable{ return $this->lastDamageCause; } + public function getAttributeMap(){ + return $this->attributeMap; + } + /** * @return int */ @@ -1547,6 +1562,7 @@ abstract class Entity extends Location implements Metadatable{ * @param int $propertyId * @param int $id * @param bool $value + * @param int $type */ public function setDataFlag($propertyId, $id, $value = true, $type = self::DATA_TYPE_BYTE){ if($this->getDataFlag($propertyId, $id) !== $value){ diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 170e8f0d6..7c7b1ab64 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,26 +15,30 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ namespace pocketmine\entity; +use pocketmine\event\entity\EntityDamageEvent; +use pocketmine\event\entity\EntityRegainHealthEvent; +use pocketmine\event\player\PlayerExhaustEvent; use pocketmine\inventory\InventoryHolder; use pocketmine\inventory\PlayerInventory; use pocketmine\item\Item as ItemItem; -use pocketmine\utils\UUID; use pocketmine\nbt\NBT; use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; +use pocketmine\nbt\tag\FloatTag; +use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ShortTag; use pocketmine\nbt\tag\StringTag; -use pocketmine\network\Network; use pocketmine\network\protocol\AddPlayerPacket; use pocketmine\network\protocol\RemovePlayerPacket; use pocketmine\Player; +use pocketmine\utils\UUID; class Human extends Creature implements ProjectileSource, InventoryHolder{ @@ -47,7 +51,6 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ /** @var PlayerInventory */ protected $inventory; - /** @var UUID */ protected $uuid; protected $rawUUID; @@ -60,6 +63,11 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ protected $skinName; protected $skin; + protected $foodTickTimer = 0; + + protected $totalXp = 0; + protected $xpSeed; + public function getSkinData(){ return $this->skin; } @@ -91,6 +99,153 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ $this->skinName = $skinName; } + public function getFood() : float{ + return $this->attributeMap->getAttribute(Attribute::HUNGER)->getValue(); + } + + /** + * WARNING: This method does not check if full and may throw an exception if out of bounds. + * Use {@link Human::addFood()} for this purpose + * + * @param float $new + * + * @throws \InvalidArgumentException + */ + public function setFood(float $new){ + $attr = $this->attributeMap->getAttribute(Attribute::HUNGER); + $old = $attr->getValue(); + $attr->setValue($new); + // ranges: 18-20 (regen), 7-17 (none), 1-6 (no sprint), 0 (health depletion) + foreach([17, 6, 0] as $bound){ + if(($old > $bound) !== ($new > $bound)){ + $reset = true; + } + } + if(isset($reset)){ + $this->foodTickTimer = 0; + } + } + + public function getMaxFood() : float{ + return $this->attributeMap->getAttribute(Attribute::HUNGER)->getMaxValue(); + } + + public function addFood(float $amount){ + $attr = $this->attributeMap->getAttribute(Attribute::HUNGER); + $amount += $attr->getValue(); + $amount = max(min($amount, $attr->getMaxValue()), $attr->getMinValue()); + $this->setFood($amount); + } + + public function getSaturation() : float{ + return $this->attributeMap->getAttribute(Attribute::HUNGER)->getValue(); + } + + /** + * WARNING: This method does not check if saturated and may throw an exception if out of bounds. + * Use {@link Human::addSaturation()} for this purpose + * + * @param float $saturation + * + * @throws \InvalidArgumentException + */ + public function setSaturation(float $saturation){ + $this->attributeMap->getAttribute(Attribute::HUNGER)->setValue($saturation); + } + + public function addSaturation(float $amount){ + $attr = $this->attributeMap->getAttribute(Attribute::SATURATION); + $attr->setValue($attr->getValue() + $amount, true); + } + + public function getExhaustion() : float{ + return $this->attributeMap->getAttribute(Attribute::EXHAUSTION)->getValue(); + } + + /** + * WARNING: This method does not check if exhausted and does not consume saturation/food. + * Use {@link Human::exhaust()} for this purpose. + * + * @param float $exhaustion + */ + public function setExhaustion(float $exhaustion){ + $this->attributeMap->getAttribute(Attribute::EXHAUSTION)->setValue($exhaustion); + } + + /** + * Increases a human's exhaustion level. + * + * @param float $amount + * @param int $cause + * + * @return float the amount of exhaustion level increased + */ + public function exhaust(float $amount, int $cause = PlayerExhaustEvent::CAUSE_CUSTOM) : float{ + $this->server->getPluginManager()->callEvent($ev = new PlayerExhaustEvent($this, $amount, $cause)); + if($ev->isCancelled()){ + return 0.0; + } + + $exhaustion = $this->getExhaustion(); + $exhaustion += $ev->getAmount(); + + while($exhaustion >= 4.0){ + $exhaustion -= 4.0; + + $saturation = $this->getSaturation(); + if($saturation > 0){ + $saturation = max(0, $saturation - 1.0); + $this->setSaturation($saturation); + }else{ + $food = $this->getFood(); + if($food > 0){ + $food--; + $this->setFood($food); + } + } + } + $this->setExhaustion($exhaustion); + + return $ev->getAmount(); + } + + public function getXpLevel() : int{ + return (int) $this->attributeMap->getAttribute(Attribute::EXPERIENCE_LEVEL)->getValue(); + } + + public function setXpLevel(int $level){ + $this->attributeMap->getAttribute(Attribute::EXPERIENCE_LEVEL)->setValue($level); + } + + public function getXpProgress() : float{ + return $this->attributeMap->getAttribute(Attribute::EXPERIENCE)->getValue(); + } + + public function setXpProgress(float $progress){ + $this->attributeMap->getAttribute(Attribute::EXPERIENCE)->setValue($progress); + } + + public function getTotalXp() : float{ + return $this->totalXp; + } + + public function getRemainderXp() : int{ + return $this->getTotalXp() - self::getTotalXpForLevel($this->getXpLevel()); + } + + public function recalculateXpProgress() : float{ + $this->setXpProgress($this->getRemainderXp() / self::getTotalXpForLevel($this->getXpLevel())); + } + + public static function getTotalXpForLevel(int $level) : int{ + if($level <= 16){ + return $level ** 2 + $level * 6; + }elseif($level < 32){ + return $level ** 2 * 2.5 - 40.5 * $level + 360; + } + return $level ** 2 * 4.5 - 162.5 * $level + 2220; + } + public function getInventory(){ return $this->inventory; } @@ -103,10 +258,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ $this->inventory = new PlayerInventory($this); if($this instanceof Player){ $this->addWindow($this->inventory, 0); - } - - - if(!($this instanceof Player)){ + }else{ if(isset($this->namedtag->NameTag)){ $this->setNameTag($this->namedtag["NameTag"]); } @@ -131,6 +283,101 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ } parent::initEntity(); + + if(!isset($this->namedtag->foodLevel) or !($this->namedtag->foodLevel instanceof IntTag)){ + $this->namedtag->foodLevel = new IntTag("foodLevel", $this->getFood()); + }else{ + $this->setFood($this->namedtag["foodLevel"]); + } + + if(!isset($this->namedtag->foodExhaustionLevel) or !($this->namedtag->foodExhaustionLevel instanceof IntTag)){ + $this->namedtag->foodExhaustionLevel = new FloatTag("foodExhaustionLevel", $this->getExhaustion()); + }else{ + $this->setExhaustion($this->namedtag["foodExhaustionLevel"]); + } + + if(!isset($this->namedtag->foodSaturationLevel) or !($this->namedtag->foodSaturationLevel instanceof IntTag)){ + $this->namedtag->foodSaturationLevel = new FloatTag("foodSaturationLevel", $this->getSaturation()); + }else{ + $this->setSaturation($this->namedtag["foodSaturationLevel"]); + } + + if(!isset($this->namedtag->foodTickTimer) or !($this->namedtag->foodTickTimer instanceof IntTag)){ + $this->namedtag->foodTickTimer = new IntTag("foodTickTimer", $this->foodTickTimer); + }else{ + $this->foodTickTimer = $this->namedtag["foodTickTimer"]; + } + + if(!isset($this->namedtag->XpLevel) or !($this->namedtag->XpLevel instanceof IntTag)){ + $this->namedtag->XpLevel = new IntTag("XpLevel", $this->getXpLevel()); + }else{ + $this->setXpLevel($this->namedtag["XpLevel"]); + } + + if(!isset($this->namedtag->XpP) or !($this->namedtag->XpP instanceof FloatTag)){ + $this->namedtag->XpP = new FloatTag("XpP", $this->getXpProgress()); + } + + if(!isset($this->namedtag->XpTotal) or !($this->namedtag->XpTotal instanceof IntTag)){ + $this->namedtag->XpTotal = new IntTag("XpTotal", $this->totalXp); + }else{ + $this->totalXp = $this->namedtag["XpTotal"]; + } + + if(!isset($this->namedtag->XpSeed) or !($this->namedtag->XpSeed instanceof IntTag)){ + $this->namedtag->XpSeed = new IntTag("XpSeed", $this->xpSeed ?? ($this->xpSeed = mt_rand(PHP_INT_MIN, PHP_INT_MAX))); + }else{ + $this->xpSeed = $this->namedtag["XpSeed"]; + } + } + + protected function addAttributes(){ + parent::addAttributes(); + + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::SATURATION)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::EXHAUSTION)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::HUNGER)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::EXPERIENCE_LEVEL)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::EXPERIENCE)); + } + + public function entityBaseTick($tickDiff = 1){ + $hasUpdate = parent::entityBaseTick($tickDiff); + + $food = $this->getFood(); + $health = $this->getHealth(); + if($food >= 18){ + $this->foodTickTimer++; + if($this->foodTickTimer >= 80 and $health < $this->getMaxHealth()){ + $this->heal(1, new EntityRegainHealthEvent($this, 1, EntityRegainHealthEvent::CAUSE_SATURATION)); + $this->exhaust(3.0, PlayerExhaustEvent::CAUSE_HEALTH_REGEN); + $this->foodTickTimer = 0; + + } + }elseif($food === 0){ + $this->foodTickTimer++; + if($this->foodTickTimer >= 80){ + $diff = $this->server->getDifficulty(); + $can = false; + if($diff === 1){ + $can = $health > 10; + }elseif($diff === 2){ + $can = $health > 1; + }elseif($diff === 3){ + $can = true; + } + if($can){ + $this->attack(1, new EntityDamageEvent($this, EntityDamageEvent::CAUSE_STARVATION, 1)); + } + } + } + if($food <= 6){ + if($this->isSprinting()){ + $this->setSprinting(false); + } + } + + return $hasUpdate; } public function getName(){ @@ -208,7 +455,6 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set"); } - if(!($this instanceof Player)){ $this->server->updatePlayerListData($this->getUniqueId(), $this->getId(), $this->getName(), $this->skinName, $this->skin, [$player]); } @@ -258,5 +504,4 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ parent::close(); } } - } diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index c65d0bfa8..e768ab37d 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,13 +15,12 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ namespace pocketmine\entity; - use pocketmine\block\Block; use pocketmine\event\entity\EntityDamageByChildEntityEvent; use pocketmine\event\entity\EntityDamageByEntityEvent; @@ -32,9 +31,7 @@ use pocketmine\event\Timings; use pocketmine\item\Item as ItemItem; use pocketmine\math\Vector3; use pocketmine\nbt\tag\ShortTag; -use pocketmine\network\Network; use pocketmine\network\protocol\EntityEventPacket; - use pocketmine\Server; use pocketmine\utils\BlockIterator; @@ -44,7 +41,7 @@ abstract class Living extends Entity implements Damageable{ protected $drag = 0.02; protected $attackTime = 0; - + protected $invisible = false; protected function initEntity(){ @@ -53,18 +50,26 @@ abstract class Living extends Entity implements Damageable{ if(isset($this->namedtag->HealF)){ $this->namedtag->Health = new ShortTag("Health", (int) $this->namedtag["HealF"]); unset($this->namedtag->HealF); - } - - if(!isset($this->namedtag->Health) or !($this->namedtag->Health instanceof ShortTag)){ + }elseif(!isset($this->namedtag->Health) or !($this->namedtag->Health instanceof ShortTag)){ $this->namedtag->Health = new ShortTag("Health", $this->getMaxHealth()); } $this->setHealth($this->namedtag["Health"]); } + protected function addAttributes(){ + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::HEALTH)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::FOLLOW_RANGE)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::KNOCKBACK_RESISTANCE)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::MOVEMENT_SPEED)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::ATTACK_DAMAGE)); + $this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::ABSORPTION)); + } + public function setHealth($amount){ $wasAlive = $this->isAlive(); parent::setHealth($amount); + $this->attributeMap->getAttribute(Attribute::HEALTH)->setValue($this->getHealth()); if($this->isAlive() and !$wasAlive){ $pk = new EntityEventPacket(); $pk->eid = $this->getId(); @@ -73,6 +78,10 @@ abstract class Living extends Entity implements Damageable{ } } + public function setMaxHealth($amount){ + $this->attributeMap->getAttribute(Attribute::HEALTH)->setMaxValue($amount); + } + public function saveNBT(){ parent::saveNBT(); $this->namedtag->Health = new ShortTag("Health", $this->getHealth()); @@ -99,15 +108,15 @@ abstract class Living extends Entity implements Damageable{ if($this->attackTime > 0 or $this->noDamageTicks > 0){ $lastCause = $this->getLastDamageCause(); if($lastCause !== null and $lastCause->getDamage() >= $damage){ - $source->setCancelled(); + $source->setCancelled(); } } - parent::attack($damage, $source); + parent::attack($damage, $source); - if($source->isCancelled()){ - return; - } + if($source->isCancelled()){ + return; + } if($source instanceof EntityDamageByEntityEvent){ $e = $source->getDamager(); @@ -285,8 +294,7 @@ abstract class Living extends Entity implements Damageable{ if($block instanceof Block){ return $block; } - }catch (\ArrayOutOfBoundsException $e){ - + }catch(\ArrayOutOfBoundsException $e){ } return null; diff --git a/src/pocketmine/event/entity/EntityDamageEvent.php b/src/pocketmine/event/entity/EntityDamageEvent.php index f792f6bda..0b681a7c2 100644 --- a/src/pocketmine/event/entity/EntityDamageEvent.php +++ b/src/pocketmine/event/entity/EntityDamageEvent.php @@ -49,6 +49,7 @@ class EntityDamageEvent extends EntityEvent implements Cancellable{ const CAUSE_SUICIDE = 12; const CAUSE_MAGIC = 13; const CAUSE_CUSTOM = 14; + const CAUSE_STARVATION = 15; private $cause; diff --git a/src/pocketmine/event/entity/EntityEatBlockEvent.php b/src/pocketmine/event/entity/EntityEatBlockEvent.php new file mode 100644 index 000000000..969dc9a1b --- /dev/null +++ b/src/pocketmine/event/entity/EntityEatBlockEvent.php @@ -0,0 +1,49 @@ +entity = $entity; + $this->foodSource = $foodSource; + $this->foodRestore = $foodSource->getFoodRestore(); + $this->saturationRestore = $foodSource->getSaturationRestore(); + $this->residue = $foodSource->getResidue(); + $this->additionalEffects = $foodSource->getAdditionalEffects(); + } + + public function getFoodSource(){ + return $this->foodSource; + } + + public function getFoodRestore() : int{ + return $this->foodRestore; + } + + public function setFoodRestore(int $foodRestore){ + $this->foodRestore = $foodRestore; + } + + public function getSaturationRestore() : float{ + return $this->saturationRestore; + } + + public function setSaturationRestore(float $saturationRestore){ + $this->saturationRestore = $saturationRestore; + } + + public function getResidue(){ + return $this->residue; + } + + public function setResidue($residue){ + $this->residue = $residue; + } + + /** + * @return Effect[] + */ + public function getAdditionalEffects(){ + return $this->additionalEffects; + } + + /** + * @param Effect[] $additionalEffects + * + * @throws \TypeError + */ + public function setAdditionalEffects(array $additionalEffects){ + foreach($additionalEffects as $effect){ + if(!($effect instanceof Effect)){ + throw new \TypeError("Argument 1 passed to EntityEatEvent::setAdditionalEffects() must be an Effect array"); + } + } + $this->additionalEffects = $additionalEffects; + } +} diff --git a/src/pocketmine/event/entity/EntityEatItemEvent.php b/src/pocketmine/event/entity/EntityEatItemEvent.php new file mode 100644 index 000000000..fe57ac6c0 --- /dev/null +++ b/src/pocketmine/event/entity/EntityEatItemEvent.php @@ -0,0 +1,46 @@ +player = $human; + $this->amount = $amount; + } + + /** + * @return Human|Player + */ + public function getPlayer(){ + return $this->player; + } + + public function getAmount() : float{ + return $this->amount; + } + + public function setAmount(float $amount){ + $this->amount = $amount; + } +} diff --git a/src/pocketmine/item/Apple.php b/src/pocketmine/item/Apple.php index d54b34b83..13e6d1785 100644 --- a/src/pocketmine/item/Apple.php +++ b/src/pocketmine/item/Apple.php @@ -22,9 +22,16 @@ namespace pocketmine\item; -class Apple extends Item{ +class Apple extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::APPLE, 0, $count, "Apple"); } + public function getFoodRestore() : int{ + return 4; + } + + public function getSaturationRestore() : float{ + return 2.4; + } } \ No newline at end of file diff --git a/src/pocketmine/item/BakedPotato.php b/src/pocketmine/item/BakedPotato.php index 34792d715..92d261d96 100644 --- a/src/pocketmine/item/BakedPotato.php +++ b/src/pocketmine/item/BakedPotato.php @@ -21,10 +21,17 @@ namespace pocketmine\item; -class BakedPotato extends Item{ +class BakedPotato extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::BAKED_POTATO, $meta, $count, "Baked Potato"); } + public function getFoodRestore() : int{ + return 5; + } + + public function getSaturationRestore() : float{ + return 7.2; + } } diff --git a/src/pocketmine/item/Beetroot.php b/src/pocketmine/item/Beetroot.php index 917c989a1..432e0c08d 100644 --- a/src/pocketmine/item/Beetroot.php +++ b/src/pocketmine/item/Beetroot.php @@ -21,10 +21,17 @@ namespace pocketmine\item; -class Beetroot extends Item{ +class Beetroot extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::BEETROOT, $meta, $count, "Beetroot"); } + public function getFoodRestore() : int{ + return 1; + } + + public function getSaturationRestore() : float{ + return 1.2; + } } diff --git a/src/pocketmine/item/BeetrootSoup.php b/src/pocketmine/item/BeetrootSoup.php index 8a7a2425c..9f221f1ae 100644 --- a/src/pocketmine/item/BeetrootSoup.php +++ b/src/pocketmine/item/BeetrootSoup.php @@ -22,7 +22,7 @@ namespace pocketmine\item; -class BeetrootSoup extends Item{ +class BeetrootSoup extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::BEETROOT_SOUP, 0, $count, "Beetroot Soup"); } @@ -30,4 +30,16 @@ class BeetrootSoup extends Item{ public function getMaxStackSize(){ return 1; } + + public function getFoodRestore() : int{ + return 6; + } + + public function getSaturationRestore() : float{ + return 7.2; + } + + public function getResidue(){ + return Item::get(Item::BOWL); + } } \ No newline at end of file diff --git a/src/pocketmine/item/BlazePowder.php b/src/pocketmine/item/BlazePowder.php index ce4d771cd..ca9276cd0 100644 --- a/src/pocketmine/item/BlazePowder.php +++ b/src/pocketmine/item/BlazePowder.php @@ -21,8 +21,8 @@ namespace pocketmine\item; -class BlazePowder extends Item { - public function __construct($meta = 0, $count =1){ - parent::__construct(self::BLAZE_POWDER, $meta, $count, "Blaze Powder"); - } +class BlazePowder extends Item{ + public function __construct($meta = 0, $count = 1){ + parent::__construct(self::BLAZE_POWDER, $meta, $count, "Blaze Powder"); + } } diff --git a/src/pocketmine/item/Boat.php b/src/pocketmine/item/Boat.php index e2c36b632..9c695c465 100644 --- a/src/pocketmine/item/Boat.php +++ b/src/pocketmine/item/Boat.php @@ -21,8 +21,8 @@ namespace pocketmine\item; -class Boat extends Item { - public function __construct($meta = 0, $count =1){ - parent::__construct(self::BOAT, $meta, $count, "Boat"); - } +class Boat extends Item{ + public function __construct($meta = 0, $count = 1){ + parent::__construct(self::BOAT, $meta, $count, "Boat"); + } } diff --git a/src/pocketmine/item/Bowl.php b/src/pocketmine/item/Bowl.php index 76f7feb6e..54f74cf2c 100644 --- a/src/pocketmine/item/Bowl.php +++ b/src/pocketmine/item/Bowl.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,7 +15,7 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ diff --git a/src/pocketmine/item/Bread.php b/src/pocketmine/item/Bread.php index ffadc7fc1..a50d5a0f7 100644 --- a/src/pocketmine/item/Bread.php +++ b/src/pocketmine/item/Bread.php @@ -21,10 +21,17 @@ namespace pocketmine\item; -class Bread extends Item{ +class Bread extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::BREAD, $meta, $count, "Bread"); } + public function getFoodRestore() : int{ + return 5; + } + + public function getSaturationRestore() : float{ + return 6; + } } diff --git a/src/pocketmine/item/BrewingStand.php b/src/pocketmine/item/BrewingStand.php index 52dc68134..414b8d74e 100644 --- a/src/pocketmine/item/BrewingStand.php +++ b/src/pocketmine/item/BrewingStand.php @@ -21,8 +21,8 @@ namespace pocketmine\item; -class BrewingStand extends Item { - public function __construct($meta = 0, $count =1){ - parent::__construct(self::BREWING_STAND, $meta, $count, "Brewing Stand"); - } +class BrewingStand extends Item{ + public function __construct($meta = 0, $count = 1){ + parent::__construct(self::BREWING_STAND, $meta, $count, "Brewing Stand"); + } } diff --git a/src/pocketmine/item/Carrot.php b/src/pocketmine/item/Carrot.php index 719f3a58c..fa00814a7 100644 --- a/src/pocketmine/item/Carrot.php +++ b/src/pocketmine/item/Carrot.php @@ -23,9 +23,17 @@ namespace pocketmine\item; use pocketmine\block\Block; -class Carrot extends Item{ +class Carrot extends Food{ public function __construct($meta = 0, $count = 1){ $this->block = Block::get(Item::CARROT_BLOCK); parent::__construct(self::CARROT, 0, $count, "Carrot"); } -} \ No newline at end of file + + public function getFoodRestore() : int{ + return 3; + } + + public function getSaturationRestore() : float{ + return 4.8; + } +} diff --git a/src/pocketmine/item/CookedChicken.php b/src/pocketmine/item/CookedChicken.php index 872e92003..f5828e609 100644 --- a/src/pocketmine/item/CookedChicken.php +++ b/src/pocketmine/item/CookedChicken.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,16 +15,23 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ namespace pocketmine\item; -class CookedChicken extends Item{ +class CookedChicken extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::COOKED_CHICKEN, $meta, $count, "Cooked Chicken"); } + public function getFoodRestore() : int{ + return 6; + } + + public function getSaturationRestore() : float{ + return 7.2; + } } diff --git a/src/pocketmine/item/CookedFish.php b/src/pocketmine/item/CookedFish.php index 9c7441ea4..bc8dceb4c 100644 --- a/src/pocketmine/item/CookedFish.php +++ b/src/pocketmine/item/CookedFish.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,19 +15,22 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ namespace pocketmine\item; - -class CookedFish extends Item{ +class CookedFish extends Fish{ public function __construct($meta = 0, $count = 1){ - parent::__construct(self::COOKED_FISH, $meta, $count, "Cooked Fish"); - if($this->meta === 1){ - $this->name = "Cooked Salmon"; - } + Food::__construct(self::COOKED_FISH, $meta, $count, $meta === self::FISH_SALMON ? "Cooked Salmon" : "Cooked Fish"); } + public function getFoodRestore() : int{ + return $this->meta === self::FISH_SALMON ? 6 : 5; + } + + public function getSaturationRestore() : float{ + return $this->meta === self::FISH_SALMON ? 9.6 : 6; + } } diff --git a/src/pocketmine/item/CookedPorkchop.php b/src/pocketmine/item/CookedPorkchop.php index 24ecb5e11..0f41f4a84 100644 --- a/src/pocketmine/item/CookedPorkchop.php +++ b/src/pocketmine/item/CookedPorkchop.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,16 +15,23 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ namespace pocketmine\item; -class CookedPorkchop extends Item{ +class CookedPorkchop extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::COOKED_PORKCHOP, $meta, $count, "Cooked Porkchop"); } + public function getFoodRestore() : int{ + return 8; + } + + public function getSaturationRestore() : float{ + return 12.8; + } } diff --git a/src/pocketmine/item/CookedRabbit.php b/src/pocketmine/item/CookedRabbit.php index b39f1e745..5544f5bb3 100644 --- a/src/pocketmine/item/CookedRabbit.php +++ b/src/pocketmine/item/CookedRabbit.php @@ -21,8 +21,16 @@ namespace pocketmine\item; -class CookedRabbit extends Item { - public function __construct($meta = 0, $count =1){ - parent::__construct(self::COOKED_RABBIT, $meta, $count, "Cooked Rabbit"); - } +class CookedRabbit extends Food{ + public function __construct($meta = 0, $count = 1){ + parent::__construct(self::COOKED_RABBIT, $meta, $count, "Cooked Rabbit"); + } + + public function getFoodRestore() : int{ + return 5; + } + + public function getSaturationRestore() : float{ + return 6; + } } diff --git a/src/pocketmine/item/Cookie.php b/src/pocketmine/item/Cookie.php index 3ca0a7132..dc7e35ba2 100644 --- a/src/pocketmine/item/Cookie.php +++ b/src/pocketmine/item/Cookie.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,16 +15,23 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ namespace pocketmine\item; -class Cookie extends Item{ +class Cookie extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::COOKIE, $meta, $count, "Cookie"); } + public function getFoodRestore() : int{ + return 2; + } + + public function getSaturationRestore() : float{ + return 0.4; + } } diff --git a/src/pocketmine/item/FermentedSpiderEye.php b/src/pocketmine/item/FermentedSpiderEye.php index 7fb9b2950..d00230a1a 100644 --- a/src/pocketmine/item/FermentedSpiderEye.php +++ b/src/pocketmine/item/FermentedSpiderEye.php @@ -21,8 +21,8 @@ namespace pocketmine\item; -class FermentedSpiderEye extends Item { - public function __construct($meta = 0, $count =1){ +class FermentedSpiderEye extends Item{ + public function __construct($meta = 0, $count = 1){ parent::__construct(self::FERMENTED_SPIDER_EYE, $meta, $count, "Fermented Spider Eye"); - } + } } diff --git a/src/pocketmine/item/Fish.php b/src/pocketmine/item/Fish.php index e56df941c..58e5da42f 100644 --- a/src/pocketmine/item/Fish.php +++ b/src/pocketmine/item/Fish.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,23 +15,63 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ namespace pocketmine\item; +use pocketmine\entity\Effect; + +class Fish extends Food{ + const FISH_FISH = 0; + const FISH_SALMON = 1; + const FISH_CLOWNFISH = 2; + const FISH_PUFFERFISH = 3; -class Fish extends Item{ public function __construct($meta = 0, $count = 1){ - parent::__construct(self::RAW_FISH, $meta, $count, "Raw Fish"); - if($this->meta === 1){ - $this->name = "Raw Salmon"; - }elseif($this->meta === 2){ - $this->name = "Clownfish"; - }elseif($this->meta === 3){ - $this->name = "Pufferfish"; + $name = "Raw Fish"; + if($this->meta === self::FISH_SALMON){ + $name = "Raw Salmon"; + }elseif($this->meta === self::FISH_CLOWNFISH){ + $name = "Clownfish"; + }elseif($this->meta === self::FISH_PUFFERFISH){ + $name = "Pufferfish"; } + parent::__construct(self::RAW_FISH, $meta, $count, $name); } -} \ No newline at end of file + public function getFoodRestore() : int{ + if($this->meta === self::FISH_FISH){ + return 2; + }elseif($this->meta === self::FISH_SALMON){ + return 2; + }elseif($this->meta === self::FISH_CLOWNFISH){ + return 1; + }elseif($this->meta === self::FISH_PUFFERFISH){ + return 1.2; + } + return 0; + } + + public function getSaturationRestore() : float{ + if($this->meta === self::FISH_FISH){ + return 0.4; + }elseif($this->meta === self::FISH_SALMON){ + return 0.4; + }elseif($this->meta === self::FISH_CLOWNFISH){ + return 0.2; + }elseif($this->meta === self::FISH_PUFFERFISH){ + return 0.2; + } + return 0; + } + + public function getAdditionalEffects() : array{ + return $this->meta === self::FISH_PUFFERFISH ? [ + Effect::getEffect(Effect::HUNGER)->setDuration(300)->setAmplifier(2), + Effect::getEffect(Effect::NAUSEA)->setDuration(300)->setAmplifier(1), + Effect::getEffect(Effect::POISON)->setDuration(1200)->setAmplifier(3), + ] : []; + } +} diff --git a/src/pocketmine/item/FishingRod.php b/src/pocketmine/item/FishingRod.php index 26df171fc..9f5794f56 100644 --- a/src/pocketmine/item/FishingRod.php +++ b/src/pocketmine/item/FishingRod.php @@ -21,8 +21,6 @@ namespace pocketmine\item; -use pocketmine\block\Block; - class FishingRod extends Item{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::FISHING_ROD, 0, $count, "Fishing Rod"); diff --git a/src/pocketmine/item/Food.php b/src/pocketmine/item/Food.php new file mode 100644 index 000000000..ffc196b63 --- /dev/null +++ b/src/pocketmine/item/Food.php @@ -0,0 +1,73 @@ +getFood() < $entity->getMaxFood(); + } + + public function getResidue(){ + if($this->getCount() === 1){ + return Item::get(0); + }else{ + $new = clone $this; + $new->count--; + return $new; + } + } + + public function getAdditionalEffects() : array{ + return []; + } + + public function onConsume(Entity $human){ + $pk = new EntityEventPacket(); + $pk->eid = $human->getId(); + $pk->event = EntityEventPacket::USE_ITEM; + if($human instanceof Player){ + $human->dataPacket($pk); + } + Server::broadcastPacket($human->getViewers(), $pk); + + $ev = new EntityEatItemEvent($human, $this); + + $human->addSaturation($ev->getSaturationRestore()); + $human->addFood($ev->getFoodRestore()); + foreach($ev->getAdditionalEffects() as $effect){ + $human->addEffect($effect); + } + + $human->getInventory()->setItemInHand($ev->getResidue()); + } +} diff --git a/src/pocketmine/item/FoodSource.php b/src/pocketmine/item/FoodSource.php new file mode 100644 index 000000000..ed3834361 --- /dev/null +++ b/src/pocketmine/item/FoodSource.php @@ -0,0 +1,37 @@ +meta === 1 ? [ + Effect::getEffect(Effect::REGENERATION)->setDuration(600)->setAmplifier(4), + Effect::getEffect(Effect::ABSORPTION)->setDuration(2400), + Effect::getEffect(Effect::DAMAGE_RESISTANCE)->setDuration(6000), + Effect::getEffect(Effect::FIRE_RESISTANCE)->setDuration(6000), + ] : [ + Effect::getEffect(Effect::REGENERATION)->setDuration(100)->setAmplifier(1), + Effect::getEffect(Effect::ABSORPTION)->setDuration(2400) + ]; + } } diff --git a/src/pocketmine/item/GoldenCarrot.php b/src/pocketmine/item/GoldenCarrot.php index 7a0eec3cf..6cf07b960 100644 --- a/src/pocketmine/item/GoldenCarrot.php +++ b/src/pocketmine/item/GoldenCarrot.php @@ -21,8 +21,16 @@ namespace pocketmine\item; -class GoldenCarrot extends Item { - public function __construct($meta = 0, $count =1){ - parent::__construct(self::GOLDEN_CARROT, $meta, $count, "Golden Carrot"); - } +class GoldenCarrot extends Food{ + public function __construct($meta = 0, $count = 1){ + parent::__construct(self::GOLDEN_CARROT, $meta, $count, "Golden Carrot"); + } + + public function getFoodRestore() : int{ + return 6; + } + + public function getSaturationRestore() : float{ + return 14.4; + } } diff --git a/src/pocketmine/item/Item.php b/src/pocketmine/item/Item.php index 55e453483..bb8b1e32f 100644 --- a/src/pocketmine/item/Item.php +++ b/src/pocketmine/item/Item.php @@ -296,7 +296,6 @@ class Item{ const STONECUTTER = 245; const GLOWING_OBSIDIAN = 246; - //Normal Item IDs const IRON_SHOVEL = 256; const IRON_PICKAXE = 257; @@ -408,7 +407,6 @@ class Item{ const CAKE = 354; const BED = 355; - const COOKIE = 357; const SHEARS = 359; @@ -472,7 +470,6 @@ class Item{ const BEETROOT_SEED = 458; const BEETROOT_SOUP = 459; - /** @var \SplFixedArray */ public static $list = null; protected $block; @@ -1049,6 +1046,17 @@ class Item{ return $this->block !== null and $this->block->canBePlaced(); } + public function canBeConsumed() : bool{ + return false; + } + + public function canBeConsumedBy(Entity $entity) : bool{ + return $this->canBeConsumed(); + } + + public function onConsume(Entity $entity){ + } + public function getBlock() : Block{ if($this->block instanceof Block){ return clone $this->block; diff --git a/src/pocketmine/item/MagmaCream.php b/src/pocketmine/item/MagmaCream.php index 37e97be92..43c13a918 100644 --- a/src/pocketmine/item/MagmaCream.php +++ b/src/pocketmine/item/MagmaCream.php @@ -21,8 +21,8 @@ namespace pocketmine\item; -class MagmaCream extends Item { - public function __construct($meta = 0, $count =1){ - parent::__construct(self::MAGMA_CREAM, $meta, $count, "Magma Cream"); - } +class MagmaCream extends Item{ + public function __construct($meta = 0, $count = 1){ + parent::__construct(self::MAGMA_CREAM, $meta, $count, "Magma Cream"); + } } diff --git a/src/pocketmine/item/Melon.php b/src/pocketmine/item/Melon.php index 086338915..75cefe875 100644 --- a/src/pocketmine/item/Melon.php +++ b/src/pocketmine/item/Melon.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,16 +15,23 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ namespace pocketmine\item; -class Melon extends Item{ +class Melon extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::MELON, $meta, $count, "Melon"); } + public function getFoodRestore() : int{ + return 2; + } + + public function getSaturationRestore() : float{ + return 1.2; + } } diff --git a/src/pocketmine/item/MushroomStew.php b/src/pocketmine/item/MushroomStew.php index 172852c65..4c315ab9a 100644 --- a/src/pocketmine/item/MushroomStew.php +++ b/src/pocketmine/item/MushroomStew.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,14 +15,13 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ namespace pocketmine\item; - -class MushroomStew extends Item{ +class MushroomStew extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::MUSHROOM_STEW, 0, $count, "Mushroom Stew"); } @@ -30,4 +29,16 @@ class MushroomStew extends Item{ public function getMaxStackSize(){ return 1; } -} \ No newline at end of file + + public function getFoodRestore() : int{ + return 6; + } + + public function getSaturationRestore() : float{ + return 7.2; + } + + public function getResidue(){ + return Item::get(Item::BOWL); + } +} diff --git a/src/pocketmine/item/NetherWart.php b/src/pocketmine/item/NetherWart.php index 733fc64af..951b5456d 100644 --- a/src/pocketmine/item/NetherWart.php +++ b/src/pocketmine/item/NetherWart.php @@ -21,8 +21,8 @@ namespace pocketmine\item; -class NetherWart extends Item { - public function __construct($meta = 0, $count =1){ - parent::__construct(self::NETHER_WART, $meta, $count, "Nether Wart"); - } +class NetherWart extends Item{ + public function __construct($meta = 0, $count = 1){ + parent::__construct(self::NETHER_WART, $meta, $count, "Nether Wart"); + } } diff --git a/src/pocketmine/item/Potato.php b/src/pocketmine/item/Potato.php index d68f86f9e..f9cea5a27 100644 --- a/src/pocketmine/item/Potato.php +++ b/src/pocketmine/item/Potato.php @@ -23,9 +23,17 @@ namespace pocketmine\item; use pocketmine\block\Block; -class Potato extends Item{ +class Potato extends Food{ public function __construct($meta = 0, $count = 1){ $this->block = Block::get(Item::POTATO_BLOCK); parent::__construct(self::POTATO, 0, $count, "Potato"); } + + public function getFoodRestore() : int{ + return 1; + } + + public function getSaturationRestore() : float{ + return 0.6; + } } \ No newline at end of file diff --git a/src/pocketmine/item/Potion.php b/src/pocketmine/item/Potion.php index ec08fed47..af879be24 100644 --- a/src/pocketmine/item/Potion.php +++ b/src/pocketmine/item/Potion.php @@ -21,8 +21,18 @@ namespace pocketmine\item; -class Potion extends Item { - public function __construct($meta = 0, $count =1){ - parent::__construct(self::POTION, $meta, $count, "Potion"); - } +use pocketmine\entity\Entity; + +class Potion extends Item{ + public function __construct($meta = 0, $count = 1){ + parent::__construct(self::POTION, $meta, $count, "Potion"); + } + + public function canBeConsumed() : bool{ + return true; + } + + public function onConsume(Entity $entity){ + // TODO: Implement potions + } } diff --git a/src/pocketmine/item/PumpkinPie.php b/src/pocketmine/item/PumpkinPie.php index 6d2a24d51..1805a298b 100644 --- a/src/pocketmine/item/PumpkinPie.php +++ b/src/pocketmine/item/PumpkinPie.php @@ -21,10 +21,17 @@ namespace pocketmine\item; -class PumpkinPie extends Item{ +class PumpkinPie extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::PUMPKIN_PIE, $meta, $count, "Pumpkin Pie"); } + public function getFoodRestore() : int{ + return 8; + } + + public function getSaturationRestore() : float{ + return 4.8; + } } diff --git a/src/pocketmine/item/RawBeef.php b/src/pocketmine/item/RawBeef.php index 612ef9ff9..dde1bd3c3 100644 --- a/src/pocketmine/item/RawBeef.php +++ b/src/pocketmine/item/RawBeef.php @@ -21,10 +21,17 @@ namespace pocketmine\item; -class RawBeef extends Item{ +class RawBeef extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::RAW_BEEF, $meta, $count, "Raw Beef"); } + public function getFoodRestore() : int{ + return 3; + } + + public function getSaturationRestore() : float{ + return 1.8; + } } diff --git a/src/pocketmine/item/RawChicken.php b/src/pocketmine/item/RawChicken.php index 25121cb26..244191287 100644 --- a/src/pocketmine/item/RawChicken.php +++ b/src/pocketmine/item/RawChicken.php @@ -21,10 +21,25 @@ namespace pocketmine\item; -class RawChicken extends Item{ +use pocketmine\entity\Effect; + +class RawChicken extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::RAW_CHICKEN, $meta, $count, "Raw Chicken"); } + public function getFoodRestore() : int{ + return 2; + } + + public function getSaturationRestore() : float{ + return 1.2; + } + + public function getAdditionalEffects() : array{ + if(mt_rand(0, 9) < 3){ + return Effect::getEffect(Effect::HUNGER)->setDuration(600); + } + } } diff --git a/src/pocketmine/item/SpawnEgg.php b/src/pocketmine/item/SpawnEgg.php index 8512d43dd..a8e56b8fb 100644 --- a/src/pocketmine/item/SpawnEgg.php +++ b/src/pocketmine/item/SpawnEgg.php @@ -2,11 +2,12 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,7 +16,7 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ @@ -27,8 +28,8 @@ use pocketmine\level\format\FullChunk; use pocketmine\level\Level; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\DoubleTag; -use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\FloatTag; +use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\StringTag; use pocketmine\Player; @@ -82,4 +83,4 @@ class SpawnEgg extends Item{ return false; } -} \ No newline at end of file +} diff --git a/src/pocketmine/item/SpiderEye.php b/src/pocketmine/item/SpiderEye.php index b33d7c72a..049e4c6f9 100644 --- a/src/pocketmine/item/SpiderEye.php +++ b/src/pocketmine/item/SpiderEye.php @@ -21,8 +21,22 @@ namespace pocketmine\item; -class SpiderEye extends Item { - public function __construct($meta = 0, $count =1){ +use pocketmine\entity\Effect; + +class SpiderEye extends Food{ + public function __construct($meta = 0, $count = 1){ parent::__construct(self::SPIDER_EYE, $meta, $count, "Spider Eye"); - } + } + + public function getFoodRestore() : int{ + return 2; + } + + public function getSaturationRestore() : float{ + return 3.2; + } + + public function getAdditionalEffects() : array{ + return [Effect::getEffect(Effect::POISON)->setDuration(80)]; + } } diff --git a/src/pocketmine/item/Steak.php b/src/pocketmine/item/Steak.php index bc18b0a1a..126795ab4 100644 --- a/src/pocketmine/item/Steak.php +++ b/src/pocketmine/item/Steak.php @@ -2,11 +2,11 @@ /* * - * ____ _ _ __ __ _ __ __ ____ - * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ + * ____ _ _ __ __ _ __ __ ____ + * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \ * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) | - * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ - * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| + * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/ + * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_| * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -15,16 +15,23 @@ * * @author PocketMine Team * @link http://www.pocketmine.net/ - * + * * */ namespace pocketmine\item; -class Steak extends Item{ +class Steak extends Food{ public function __construct($meta = 0, $count = 1){ parent::__construct(self::STEAK, $meta, $count, "Steak"); } + public function getFoodRestore() : int{ + return 8; + } + + public function getSaturationRestore() : float{ + return 12.8; + } } diff --git a/src/pocketmine/item/Tool.php b/src/pocketmine/item/Tool.php index 7f3c0b833..31d7e840c 100644 --- a/src/pocketmine/item/Tool.php +++ b/src/pocketmine/item/Tool.php @@ -19,12 +19,10 @@ * */ - namespace pocketmine\item; use pocketmine\block\Block; use pocketmine\entity\Entity; -use pocketmine\nbt\tag\ByteTag; abstract class Tool extends Item{ const TIER_WOODEN = 1; diff --git a/src/pocketmine/item/enchantment/EnchantmentEntry.php b/src/pocketmine/item/enchantment/EnchantmentEntry.php index e1a40d37c..d6d109f47 100644 --- a/src/pocketmine/item/enchantment/EnchantmentEntry.php +++ b/src/pocketmine/item/enchantment/EnchantmentEntry.php @@ -31,8 +31,8 @@ class EnchantmentEntry{ /** * @param Enchantment[] $enchantments - * @param $cost - * @param $randomName + * @param number $cost + * @param string $randomName */ public function __construct(array $enchantments, $cost, $randomName){ $this->enchantments = $enchantments; diff --git a/src/pocketmine/item/enchantment/EnchantmentList.php b/src/pocketmine/item/enchantment/EnchantmentList.php index a4fbd09cc..6a8af365a 100644 --- a/src/pocketmine/item/enchantment/EnchantmentList.php +++ b/src/pocketmine/item/enchantment/EnchantmentList.php @@ -32,7 +32,7 @@ class EnchantmentList{ } /** - * @param $slot + * @param $slot * @param EnchantmentEntry $entry */ public function setSlot($slot, EnchantmentEntry $entry){