Added custom block data (example, chests), better deep checking of same NBT

This commit is contained in:
Shoghi Cervantes 2015-08-07 17:24:35 +02:00
parent e9c981b586
commit 696edfd31f
10 changed files with 179 additions and 17 deletions

View File

@ -1945,7 +1945,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
break;
}
}
}elseif($item === null or $slot === -1 or !$item->equals($packet->item)){ // packet error or not implemented
}elseif($item === null or $slot === -1 or !$item->deepEquals($packet->item)){ // packet error or not implemented
$this->inventory->sendContents($this);
break;
}elseif($this->isCreative()){
@ -1985,14 +1985,14 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
if($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this) === true){
break;
}
}elseif(!$this->inventory->getItemInHand()->equals($packet->item)){
}elseif(!$this->inventory->getItemInHand()->deepEquals($packet->item)){
$this->inventory->sendHeldItem($this);
}else{
$item = $this->inventory->getItemInHand();
$oldItem = clone $item;
//TODO: Implement adventure mode checks
if($this->level->useItemOn($blockVector, $item, $packet->face, $packet->fx, $packet->fy, $packet->fz, $this)){
if(!$item->equals($oldItem, true) or $item->getCount() !== $oldItem->getCount()){
if(!$item->deepEquals($oldItem) or $item->getCount() !== $oldItem->getCount()){
$this->inventory->setItemInHand($item, $this);
$this->inventory->sendHeldItem($this->hasSpawned);
}
@ -2015,7 +2015,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
if($this->isCreative()){
$item = $this->inventory->getItemInHand();
}elseif(!$this->inventory->getItemInHand()->equals($packet->item)){
}elseif(!$this->inventory->getItemInHand()->deepEquals($packet->item)){
$this->inventory->sendHeldItem($this);
break;
}else{
@ -2251,7 +2251,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
if($this->canInteract($vector->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 6) and $this->level->useBreakOn($vector, $item, $this)){
if($this->isSurvival()){
if(!$item->equals($oldItem, true) or $item->getCount() !== $oldItem->getCount()){
if(!$item->deepEquals($oldItem) or $item->getCount() !== $oldItem->getCount()){
$this->inventory->setItemInHand($item, $this);
$this->inventory->sendHeldItem($this->hasSpawned);
}
@ -2610,7 +2610,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
$slot = -1;
$checkDamage = $ingredient->getDamage() === null ? false : true;
foreach($this->inventory->getContents() as $index => $i){
if($ingredient->equals($i, $checkDamage) and ($i->getCount() - $used[$index]) >= 1){
if($ingredient->deepEquals($i, $checkDamage) and ($i->getCount() - $used[$index]) >= 1){
$slot = $index;
$used[$index]++;
break;
@ -2723,7 +2723,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
break;
}
if($transaction->getSourceItem()->equals($transaction->getTargetItem()) and $transaction->getTargetItem()->getCount() === $transaction->getSourceItem()->getCount()){ //No changes!
if($transaction->getSourceItem()->deepEquals($transaction->getTargetItem()) and $transaction->getTargetItem()->getCount() === $transaction->getSourceItem()->getCount()){ //No changes!
//No changes, just a local inventory update sent by the server
break;
}

View File

@ -82,6 +82,12 @@ class BurningFurnace extends Solid{
$nbt->CustomName = new String("CustomName", $item->getCustomName());
}
if($item->hasCustomBlockData()){
foreach($item->getCustomBlockData() as $key => $v){
$nbt->{$key} = $v;
}
}
Tile::createTile("Furnace", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
return true;

View File

@ -109,6 +109,12 @@ class Chest extends Transparent{
$nbt->CustomName = new String("CustomName", $item->getCustomName());
}
if($item->hasCustomBlockData()){
foreach($item->getCustomBlockData() as $key => $v){
$nbt->{$key} = $v;
}
}
$tile = Tile::createTile("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
if($chest instanceof TileChest and $tile instanceof TileChest){

View File

@ -52,6 +52,12 @@ class EnchantingTable extends Transparent{
$nbt->CustomName = new String("CustomName", $item->getCustomName());
}
if($item->hasCustomBlockData()){
foreach($item->getCustomBlockData() as $key => $v){
$nbt->{$key} = $v;
}
}
Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
return true;

View File

@ -70,6 +70,10 @@ class Item extends Entity{
if(isset($this->namedtag->Thrower)){
$this->thrower = $this->namedtag["Thrower"];
}
if(!isset($this->namedtag->Item)){
$this->close();
return;
}
$this->item = NBT::getItemHelper($this->namedtag->Item);

View File

@ -98,7 +98,7 @@ class SimpleTransactionGroup implements TransactionGroup{
}
$checkSourceItem = $ts->getInventory()->getItem($ts->getSlot());
$sourceItem = $ts->getSourceItem();
if(!$checkSourceItem->equals($sourceItem) or $sourceItem->getCount() !== $checkSourceItem->getCount()){
if(!$checkSourceItem->deepEquals($sourceItem) or $sourceItem->getCount() !== $checkSourceItem->getCount()){
return false;
}
if($sourceItem->getId() !== Item::AIR){
@ -108,7 +108,7 @@ class SimpleTransactionGroup implements TransactionGroup{
foreach($needItems as $i => $needItem){
foreach($haveItems as $j => $haveItem){
if($needItem->equals($haveItem)){
if($needItem->deepEquals($haveItem)){
$amount = min($needItem->getCount(), $haveItem->getCount());
$needItem->setCount($needItem->getCount() - $amount);
$haveItem->setCount($haveItem->getCount() - $amount);

View File

@ -968,6 +968,62 @@ class Item{
return $this->tags !== "" and $this->tags !== null;
}
public function hasCustomBlockData(){
if(!$this->hasCompoundTag()){
return false;
}
$tag = $this->getNamedTag();
if(isset($tag->BlockEntityTag) and $tag->BlockEntityTag instanceof Compound){
return true;
}
return false;
}
public function clearCustomBlockData(){
if(!$this->hasCompoundTag()){
return $this;
}
$tag = $this->getNamedTag();
if(isset($tag->BlockEntityTag) and $tag->BlockEntityTag instanceof Compound){
unset($tag->display->BlockEntityTag);
$this->setNamedTag($tag);
}
return $this;
}
public function setCustomBlockData(Compound $compound){
$tags = clone $compound;
$tags->setName("BlockEntityTag");
if(!$this->hasCompoundTag()){
$tag = new Compound("", []);
}else{
$tag = $this->getNamedTag();
}
$tag->BlockEntityTag = $tags;
$this->setNamedTag($tag);
return $this;
}
public function getCustomBlockData(){
if(!$this->hasCompoundTag()){
return null;
}
$tag = $this->getNamedTag();
if(isset($tag->BlockEntityTag) and $tag->BlockEntityTag instanceof Compound){
return $tag->BlockEntityTag;
}
return null;
}
public function hasCustomName(){
if(!$this->hasCompoundTag()){
return false;
@ -1191,4 +1247,14 @@ class Item{
return $this->id === $item->getId() and ($checkDamage === false or $this->getDamage() === $item->getDamage()) and ($checkCompound === false or $this->getCompoundTag() === $item->getCompoundTag());
}
public final function deepEquals(Item $item){
if($item->equals($item)){
return true;
}elseif($item->hasCompoundTag() or $this->hasCompoundTag()){
return NBT::matchTree($this->getNamedTag(), $item->getNamedTag());
}
return false;
}
}

View File

@ -1727,7 +1727,8 @@ class Level implements ChunkManager, Metadatable{
}
if($hand->getId() === Item::SIGN_POST or $hand->getId() === Item::WALL_SIGN){
$tile = Tile::createTile("Sign", $this->getChunk($block->x >> 4, $block->z >> 4), new Compound("", [
$nbt = new Compound("", [
"id" => new String("id", Tile::SIGN),
"x" => new Int("x", $block->x),
"y" => new Int("y", $block->y),
@ -1736,10 +1737,19 @@ class Level implements ChunkManager, Metadatable{
"Text2" => new String("Text2", ""),
"Text3" => new String("Text3", ""),
"Text4" => new String("Text4", "")
]));
]);
if($player !== null){
$tile->namedtag->Creator = new String("Creator", $player->getRawUniqueId());
$nbt->Creator = new String("Creator", $player->getRawUniqueId());
}
if($item->hasCustomBlockData()){
foreach($item->getCustomBlockData() as $key => $v){
$nbt->{$key} = $v;
}
}
Tile::createTile("Sign", $this->getChunk($block->x >> 4, $block->z >> 4), $nbt);
}
$item->setCount($item->getCount() - 1);
if($item->getCount() <= 0){

View File

@ -104,11 +104,11 @@ class NBT{
* @return Item
*/
public static function getItemHelper(Compound $tag){
if(!isset($tag->id) or !isset($tag->Damage) or !isset($tag->Count)){
if(!isset($tag->id) or !isset($tag->Count)){
return Item::get(0);
}
$item = Item::get($tag->id->getValue(), $tag->Damage->getValue(), $tag->Count->getValue());
$item = Item::get($tag->id->getValue(), !isset($tag->Damage) ? 0 : $tag->Damage->getValue(), $tag->Count->getValue());
if(isset($tag->tag) and $tag->tag instanceof Compound){
$item->setNamedTag($tag->tag);
@ -117,6 +117,70 @@ class NBT{
return $item;
}
public static function matchList(Enum $tag1, Enum $tag2){
if($tag1->getName() !== $tag2->getName() or $tag1->getCount() !== $tag2->getCount()){
return false;
}
foreach($tag1 as $k => $v){
if(!($v instanceof Tag)){
continue;
}
if(!isset($tag2->{$k}) or !($tag2->{$k} instanceof $v)){
return false;
}
if($v instanceof Compound){
if(!self::matchTree($v, $tag2->{$k})){
return false;
}
}elseif($v instanceof Enum){
if(!self::matchList($v, $tag2->{$k})){
return false;
}
}else{
if($v->getValue() !== $tag2->{$k}->getValue()){
return false;
}
}
}
return true;
}
public static function matchTree(Compound $tag1, Compound $tag2){
if($tag1->getName() !== $tag2->getName() or $tag1->getCount() !== $tag2->getCount()){
return false;
}
foreach($tag1 as $k => $v){
if(!($v instanceof Tag)){
continue;
}
if(!isset($tag2->{$k}) or !($tag2->{$k} instanceof $v)){
return false;
}
if($v instanceof Compound){
if(!self::matchTree($v, $tag2->{$k})){
return false;
}
}elseif($v instanceof Enum){
if(!self::matchList($v, $tag2->{$k})){
return false;
}
}else{
if($v->getValue() !== $tag2->{$k}->getValue()){
return false;
}
}
}
return true;
}
public function get($len){
if($len < 0){
$this->offset = strlen($this->buffer) - 1;

View File

@ -47,7 +47,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
$this->inventory = new ChestInventory($this);
if(!isset($this->namedtag->Items) or !($this->namedtag->Items instanceof Enum)){
$this->namedtag->Items = new Enum("Inventory", []);
$this->namedtag->Items = new Enum("Items", []);
$this->namedtag->Items->setTagType(NBT::TAG_Compound);
}
@ -91,8 +91,8 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
*/
protected function getSlotIndex($index){
foreach($this->namedtag->Items as $i => $slot){
if($slot["Slot"] === $index){
return $i;
if((int) $slot["Slot"] === (int) $index){
return (int) $i;
}
}