Implemented Jukebox & Records (#3742)

Co-authored-by: Dylan K. Taylor <odigiman@gmail.com>
This commit is contained in:
Jack Honour 2020-08-07 21:07:58 +01:00 committed by GitHub
parent 2545897fc2
commit ff2a3baa8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 461 additions and 13 deletions

View File

@ -39,6 +39,7 @@ use pocketmine\block\tile\FlowerPot as TileFlowerPot;
use pocketmine\block\tile\Furnace as TileFurnace;
use pocketmine\block\tile\Hopper as TileHopper;
use pocketmine\block\tile\ItemFrame as TileItemFrame;
use pocketmine\block\tile\Jukebox as TileJukebox;
use pocketmine\block\tile\MonsterSpawner as TileMonsterSpawner;
use pocketmine\block\tile\Note as TileNote;
use pocketmine\block\tile\Skull as TileSkull;
@ -230,6 +231,7 @@ class BlockFactory{
$this->register(new Opaque(new BID(Ids::IRON_ORE), "Iron Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
$this->register(new Trapdoor(new BID(Ids::IRON_TRAPDOOR), "Iron Trapdoor", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 25.0)));
$this->register(new ItemFrame(new BID(Ids::FRAME_BLOCK, 0, ItemIds::FRAME, TileItemFrame::class), "Item Frame"));
$this->register(new Jukebox(new BID(Ids::JUKEBOX, 0, ItemIds::JUKEBOX, TileJukebox::class), "Jukebox"));
$this->register(new Ladder(new BID(Ids::LADDER), "Ladder"));
$this->register(new Lantern(new BID(Ids::LANTERN), "Lantern", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
$this->register(new Opaque(new BID(Ids::LAPIS_BLOCK), "Lapis Lazuli Block", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));

121
src/block/Jukebox.php Normal file
View File

@ -0,0 +1,121 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Jukebox as JukeboxTile;
use pocketmine\item\Item;
use pocketmine\item\Record;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\sound\RecordSound;
use pocketmine\world\sound\RecordStopSound;
class Jukebox extends Opaque{
/** @var Record|null */
private $record = null;
public function __construct(BlockIdentifier $idInfo, string $name, ?BlockBreakInfo $breakInfo = null){
//TODO: in PC the hardness is 2.0, not 0.8, unsure if this is a MCPE bug or not
parent::__construct($idInfo, $name, $breakInfo ?? new BlockBreakInfo(0.8, BlockToolType::AXE));
}
public function getFuelTime() : int{
return 300;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){
if($this->record !== null){
$this->ejectRecord();
}elseif($item instanceof Record){
$player->sendJukeboxPopup("record.nowPlaying", ["%" . $item->getRecordType()->getTranslationKey()]);
$this->insertRecord($item->pop());
}
}
$this->pos->getWorld()->setBlock($this->pos, $this);
return true;
}
public function getRecord() : ?Record{
return $this->record;
}
public function ejectRecord() : void{
if($this->record !== null){
$this->getPos()->getWorld()->dropItem($this->getPos()->add(0.5, 1, 0.5), $this->record);
$this->record = null;
$this->stopSound();
}
}
public function insertRecord(Record $record) : void{
if($this->record === null){
$this->record = $record;
$this->startSound();
}
}
public function startSound() : void{
if($this->record !== null){
$this->getPos()->getWorld()->addSound($this->getPos(), new RecordSound($this->record->getRecordType()));
}
}
public function stopSound() : void{
$this->getPos()->getWorld()->addSound($this->getPos(), new RecordStopSound());
}
public function onBreak(Item $item, ?Player $player = null) : bool{
$this->stopSound();
return parent::onBreak($item, $player);
}
public function getDropsForCompatibleTool(Item $item) : array{
$drops = parent::getDropsForCompatibleTool($item);
if($this->record !== null){
$drops[] = $this->record;
}
return $drops;
}
public function readStateFromWorld() : void{
parent::readStateFromWorld();
$jukebox = $this->pos->getWorld()->getTile($this->pos);
if($jukebox instanceof JukeboxTile){
$this->record = $jukebox->getRecord();
}
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$jukebox = $this->pos->getWorld()->getTile($this->pos);
if($jukebox instanceof JukeboxTile){
$jukebox->setRecord($this->record);
}
}
//TODO: Jukebox has redstone effects, they are not implemented.
}

View File

@ -397,6 +397,7 @@ use function assert;
* @method static Opaque IRON_ORE()
* @method static Trapdoor IRON_TRAPDOOR()
* @method static ItemFrame ITEM_FRAME()
* @method static Jukebox JUKEBOX()
* @method static WoodenButton JUNGLE_BUTTON()
* @method static WoodenDoor JUNGLE_DOOR()
* @method static WoodenFence JUNGLE_FENCE()
@ -1062,6 +1063,7 @@ final class VanillaBlocks{
self::register("iron_ore", $factory->get(15));
self::register("iron_trapdoor", $factory->get(167));
self::register("item_frame", $factory->get(199));
self::register("jukebox", $factory->get(84));
self::register("jungle_button", $factory->get(398));
self::register("jungle_door", $factory->get(195));
self::register("jungle_fence", $factory->get(85, 3));

View File

@ -0,0 +1,65 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block\tile;
use pocketmine\item\Item;
use pocketmine\item\Record;
use pocketmine\nbt\tag\CompoundTag;
class Jukebox extends Spawnable{
private const TAG_RECORD = "RecordItem"; //Item CompoundTag
/** @var Record|null */
private $record = null;
public function getRecord() : ?Record{
return $this->record;
}
public function setRecord(?Record $record) : void{
$this->record = $record;
}
public function readSaveData(CompoundTag $nbt) : void{
if(($tag = $nbt->getCompoundTag(self::TAG_RECORD)) !== null){
$record = Item::nbtDeserialize($tag);
if($record instanceof Record){
$this->record = $record;
}
}
}
protected function writeSaveData(CompoundTag $nbt) : void{
if($this->record !== null){
$nbt->setTag(self::TAG_RECORD, $this->record->nbtSerialize());
}
}
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
//this is needed for the note particles to show on the client side
if($this->record !== null){
$nbt->setTag(self::TAG_RECORD, $this->record->nbtSerialize());
}
}
}

View File

@ -60,6 +60,7 @@ final class TileFactory{
$this->register(Furnace::class, ["Furnace", "minecraft:furnace"]);
$this->register(Hopper::class, ["Hopper", "minecraft:hopper"]);
$this->register(ItemFrame::class, ["ItemFrame"]); //this is an entity in PC
$this->register(Jukebox::class, ["Jukebox", "RecordPlayer", "minecraft:jukebox"]);
$this->register(MonsterSpawner::class, ["MobSpawner", "minecraft:mob_spawner"]);
$this->register(Note::class, ["Music", "minecraft:noteblock"]);
$this->register(Sign::class, ["Sign", "minecraft:sign"]);

View File

@ -0,0 +1,95 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\utils\EnumTrait;
/**
* This doc-block is generated automatically, do not modify it manually.
* This must be regenerated whenever registry members are added, removed or changed.
* @see RegistryTrait::_generateMethodAnnotations()
*
* @method static self DISK_13()
* @method static self DISK_CAT()
* @method static self DISK_BLOCKS()
* @method static self DISK_CHIRP()
* @method static self DISK_FAR()
* @method static self DISK_MALL()
* @method static self DISK_MELLOHI()
* @method static self DISK_STAL()
* @method static self DISK_STRAD()
* @method static self DISK_WARD()
* @method static self DISK_11()
* @method static self DISK_WAIT()
*/
final class RecordType{
use EnumTrait {
__construct as Enum___construct;
}
protected static function setup() : void{
self::registerAll(
new RecordType("disk_13", "C418 - 13", LevelSoundEventPacket::SOUND_RECORD_13, "item.record_13.desc"),
new RecordType("disk_cat", "C418 - cat", LevelSoundEventPacket::SOUND_RECORD_CAT, "item.record_cat.desc"),
new RecordType("disk_blocks", "C418 - blocks", LevelSoundEventPacket::SOUND_RECORD_BLOCKS, "item.record_blocks.desc"),
new RecordType("disk_chirp", "C418 - chirp", LevelSoundEventPacket::SOUND_RECORD_CHIRP, "item.record_chirp.desc"),
new RecordType("disk_far", "C418 - far", LevelSoundEventPacket::SOUND_RECORD_FAR, "item.record_far.desc"),
new RecordType("disk_mall", "C418 - mall", LevelSoundEventPacket::SOUND_RECORD_MALL, "item.record_mall.desc"),
new RecordType("disk_mellohi", "C418 - mellohi", LevelSoundEventPacket::SOUND_RECORD_MELLOHI, "item.record_mellohi.desc"),
new RecordType("disk_stal", "C418 - stal", LevelSoundEventPacket::SOUND_RECORD_STAL, "item.record_stal.desc"),
new RecordType("disk_strad", "C418 - strad", LevelSoundEventPacket::SOUND_RECORD_STRAD, "item.record_strad.desc"),
new RecordType("disk_ward", "C418 - ward", LevelSoundEventPacket::SOUND_RECORD_WARD, "item.record_ward.desc"),
new RecordType("disk_11", "C418 - 11", LevelSoundEventPacket::SOUND_RECORD_11, "item.record_11.desc"),
new RecordType("disk_wait", "C418 - wait", LevelSoundEventPacket::SOUND_RECORD_WAIT, "item.record_wait.desc")
//TODO: Lena Raine - Pigstep
);
}
/** @var string */
private $soundName;
/** @var int */
private $soundId;
/** @var string */
private $translationKey;
private function __construct(string $enumName, string $soundName, int $soundId, string $translationKey){
$this->Enum___construct($enumName);
$this->soundName = $soundName;
$this->soundId = $soundId;
$this->translationKey = $translationKey;
}
public function getSoundName() : string{
return $this->soundName;
}
public function getSoundId() : int{
return $this->soundId;
}
public function getTranslationKey() : string{
return $this->translationKey;
}
}

View File

@ -26,6 +26,7 @@ namespace pocketmine\item;
use pocketmine\block\BlockFactory;
use pocketmine\block\BlockLegacyIds;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\RecordType;
use pocketmine\block\utils\SkullType;
use pocketmine\block\utils\TreeType;
use pocketmine\block\VanillaBlocks;
@ -215,6 +216,18 @@ class ItemFactory{
$this->register(new RawPorkchop(new ItemIdentifier(ItemIds::RAW_PORKCHOP, 0), "Raw Porkchop"));
$this->register(new RawRabbit(new ItemIdentifier(ItemIds::RAW_RABBIT, 0), "Raw Rabbit"));
$this->register(new RawSalmon(new ItemIdentifier(ItemIds::RAW_SALMON, 0), "Raw Salmon"));
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_13, 0), RecordType::DISK_13(), "Record 13"));
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_CAT, 0), RecordType::DISK_CAT(), "Record Cat"));
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_BLOCKS, 0), RecordType::DISK_BLOCKS(), "Record Blocks"));
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_CHIRP, 0), RecordType::DISK_CHIRP(), "Record Chirp"));
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_FAR, 0), RecordType::DISK_FAR(), "Record Far"));
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_MALL, 0), RecordType::DISK_MALL(), "Record Mall"));
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_MELLOHI, 0), RecordType::DISK_MELLOHI(), "Record Mellohi"));
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_STAL, 0), RecordType::DISK_STAL(), "Record Stal"));
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_STRAD, 0), RecordType::DISK_STRAD(), "Record Strad"));
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_WARD, 0), RecordType::DISK_WARD(), "Record Ward"));
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_11, 0), RecordType::DISK_11(), "Record 11"));
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_WAIT, 0), RecordType::DISK_WAIT(), "Record Wait"));
$this->register(new Redstone(new ItemIdentifier(ItemIds::REDSTONE, 0), "Redstone"));
$this->register(new RottenFlesh(new ItemIdentifier(ItemIds::ROTTEN_FLESH, 0), "Rotten Flesh"));
$this->register(new Shears(new ItemIdentifier(ItemIds::SHEARS, 0), "Shears"));
@ -294,18 +307,7 @@ class ItemFactory{
//TODO: minecraft:name_tag
//TODO: minecraft:phantom_membrane
//TODO: minecraft:rapid_fertilizer
//TODO: minecraft:record_11
//TODO: minecraft:record_13
//TODO: minecraft:record_blocks
//TODO: minecraft:record_cat
//TODO: minecraft:record_chirp
//TODO: minecraft:record_far
//TODO: minecraft:record_mall
//TODO: minecraft:record_mellohi
//TODO: minecraft:record_stal
//TODO: minecraft:record_strad
//TODO: minecraft:record_wait
//TODO: minecraft:record_ward
//TODO: minecraft:record_pigstep
//TODO: minecraft:saddle
//TODO: minecraft:shield
//TODO: minecraft:sparkler

44
src/item/Record.php Normal file
View File

@ -0,0 +1,44 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\block\utils\RecordType;
class Record extends Item{
/** @var RecordType */
private $recordType;
public function __construct(ItemIdentifier $identifier, RecordType $recordType, string $name){
$this->recordType = $recordType;
parent::__construct($identifier, $name);
}
public function getRecordType() : RecordType{
return $this->recordType;
}
public function getMaxStackSize() : int{
return 1;
}
}

View File

@ -247,6 +247,18 @@ use function assert;
* @method static RawPorkchop RAW_PORKCHOP()
* @method static RawRabbit RAW_RABBIT()
* @method static RawSalmon RAW_SALMON()
* @method static Record RECORD_11()
* @method static Record RECORD_13()
* @method static Record RECORD_BLOCKS()
* @method static Record RECORD_CAT()
* @method static Record RECORD_CHIRP()
* @method static Record RECORD_FAR()
* @method static Record RECORD_MALL()
* @method static Record RECORD_MELLOHI()
* @method static Record RECORD_STAL()
* @method static Record RECORD_STRAD()
* @method static Record RECORD_WAIT()
* @method static Record RECORD_WARD()
* @method static Banner RED_BANNER()
* @method static Bed RED_BED()
* @method static Dye RED_DYE()
@ -535,6 +547,18 @@ final class VanillaItems{
self::register("raw_porkchop", $factory->get(319));
self::register("raw_rabbit", $factory->get(411));
self::register("raw_salmon", $factory->get(460));
self::register("record_11", $factory->get(510));
self::register("record_13", $factory->get(500));
self::register("record_blocks", $factory->get(502));
self::register("record_cat", $factory->get(501));
self::register("record_chirp", $factory->get(503));
self::register("record_far", $factory->get(504));
self::register("record_mall", $factory->get(505));
self::register("record_mellohi", $factory->get(506));
self::register("record_stal", $factory->get(507));
self::register("record_strad", $factory->get(508));
self::register("record_wait", $factory->get(511));
self::register("record_ward", $factory->get(509));
self::register("red_banner", $factory->get(446, 1));
self::register("red_bed", $factory->get(355, 14));
self::register("red_dye", $factory->get(351, 1));

View File

@ -792,6 +792,13 @@ class NetworkSession{
$this->sendDataPacket(TextPacket::translation($key, $parameters));
}
/**
* @param string[] $parameters
*/
public function onJukeboxPopup(string $key, array $parameters) : void{
$this->sendDataPacket(TextPacket::jukeboxPopup($key, $parameters));
}
public function onPopup(string $message) : void{
$this->sendDataPacket(TextPacket::popup($message));
}

View File

@ -1851,6 +1851,15 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
}
}
/**
* @param string[] $args
*/
public function sendJukeboxPopup(string $key, array $args) : void{
if($this->networkSession !== null){
$this->networkSession->onJukeboxPopup($key, $args);
}
}
/**
* Sends a popup message to the player
*

View File

@ -0,0 +1,42 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\sound;
use pocketmine\block\utils\RecordType;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
class RecordSound implements Sound{
/** @var RecordType */
private $recordType;
public function __construct(RecordType $recordType){
$this->recordType = $recordType;
}
public function encode(?Vector3 $pos){
return LevelSoundEventPacket::create($this->recordType->getSoundId(), $pos);
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\world\sound;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
class RecordStopSound implements Sound{
public function encode(?Vector3 $pos){
return LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_STOP_RECORD, $pos);
}
}

File diff suppressed because one or more lines are too long