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

View File

@ -82,6 +82,12 @@ class BurningFurnace extends Solid{
$nbt->CustomName = new String("CustomName", $item->getCustomName()); $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); Tile::createTile("Furnace", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
return true; return true;

View File

@ -109,6 +109,12 @@ class Chest extends Transparent{
$nbt->CustomName = new String("CustomName", $item->getCustomName()); $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); $tile = Tile::createTile("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
if($chest instanceof TileChest and $tile instanceof TileChest){ 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()); $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); Tile::createTile(Tile::ENCHANT_TABLE, $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
return true; return true;

View File

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

View File

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

View File

@ -968,6 +968,62 @@ class Item{
return $this->tags !== "" and $this->tags !== null; 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(){ public function hasCustomName(){
if(!$this->hasCompoundTag()){ if(!$this->hasCompoundTag()){
return false; 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()); 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){ 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), "id" => new String("id", Tile::SIGN),
"x" => new Int("x", $block->x), "x" => new Int("x", $block->x),
"y" => new Int("y", $block->y), "y" => new Int("y", $block->y),
@ -1736,10 +1737,19 @@ class Level implements ChunkManager, Metadatable{
"Text2" => new String("Text2", ""), "Text2" => new String("Text2", ""),
"Text3" => new String("Text3", ""), "Text3" => new String("Text3", ""),
"Text4" => new String("Text4", "") "Text4" => new String("Text4", "")
])); ]);
if($player !== null){ 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); $item->setCount($item->getCount() - 1);
if($item->getCount() <= 0){ if($item->getCount() <= 0){

View File

@ -104,11 +104,11 @@ class NBT{
* @return Item * @return Item
*/ */
public static function getItemHelper(Compound $tag){ 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); 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){ if(isset($tag->tag) and $tag->tag instanceof Compound){
$item->setNamedTag($tag->tag); $item->setNamedTag($tag->tag);
@ -117,6 +117,70 @@ class NBT{
return $item; 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){ public function get($len){
if($len < 0){ if($len < 0){
$this->offset = strlen($this->buffer) - 1; $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); $this->inventory = new ChestInventory($this);
if(!isset($this->namedtag->Items) or !($this->namedtag->Items instanceof Enum)){ 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); $this->namedtag->Items->setTagType(NBT::TAG_Compound);
} }
@ -91,8 +91,8 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
*/ */
protected function getSlotIndex($index){ protected function getSlotIndex($index){
foreach($this->namedtag->Items as $i => $slot){ foreach($this->namedtag->Items as $i => $slot){
if($slot["Slot"] === $index){ if((int) $slot["Slot"] === (int) $index){
return $i; return (int) $i;
} }
} }