mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-14 22:01:59 +00:00
Merge branch 'master' into mcpe-1.2.5
This commit is contained in:
commit
dcdea6a1f4
@ -762,6 +762,15 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* If null is given, will additionally send the skin to the player itself as well as its viewers.
|
||||||
|
*/
|
||||||
|
public function sendSkin(array $targets = null) : void{
|
||||||
|
parent::sendSkin($targets ?? $this->server->getOnlinePlayers());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the player IP address
|
* Gets the player IP address
|
||||||
*
|
*
|
||||||
@ -1988,24 +1997,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mojang, some stupid reason, send every single model for every single skin in the selected skin-pack.
|
|
||||||
* Not only that, they are pretty-printed. This decode/encode is to get rid of the pretty-print, which cuts down
|
|
||||||
* significantly on the amount of wasted bytes.
|
|
||||||
* TODO: find out what model crap can be safely dropped from the packet (unless it gets fixed first)
|
|
||||||
*/
|
|
||||||
|
|
||||||
$geometryJsonEncoded = base64_decode($packet->clientData["SkinGeometry"] ?? "");
|
|
||||||
if($geometryJsonEncoded !== ""){
|
|
||||||
$geometryJsonEncoded = json_encode(json_decode($geometryJsonEncoded));
|
|
||||||
}
|
|
||||||
|
|
||||||
$skin = new Skin(
|
$skin = new Skin(
|
||||||
$packet->clientData["SkinId"],
|
$packet->clientData["SkinId"],
|
||||||
base64_decode($packet->clientData["SkinData"] ?? ""),
|
base64_decode($packet->clientData["SkinData"] ?? ""),
|
||||||
base64_decode($packet->clientData["CapeData"] ?? ""),
|
base64_decode($packet->clientData["CapeData"] ?? ""),
|
||||||
$packet->clientData["SkinGeometryName"],
|
$packet->clientData["SkinGeometryName"],
|
||||||
$geometryJsonEncoded
|
base64_decode($packet->clientData["SkinGeometry"] ?? "")
|
||||||
);
|
);
|
||||||
|
$skin->debloatGeometryData();
|
||||||
|
|
||||||
if(!$skin->isValid()){
|
if(!$skin->isValid()){
|
||||||
$this->close("", "disconnectionScreen.invalidSkin");
|
$this->close("", "disconnectionScreen.invalidSkin");
|
||||||
@ -2911,7 +2910,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tile = $this->level->getTile($this->temporalVector->setComponents($packet->x, $packet->y, $packet->z));
|
$tile = $this->level->getTileAt($packet->x, $packet->y, $packet->z);
|
||||||
if($tile instanceof ItemFrame){
|
if($tile instanceof ItemFrame){
|
||||||
$ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $tile->getBlock(), null, 5 - $tile->getBlock()->getDamage(), PlayerInteractEvent::LEFT_CLICK_BLOCK);
|
$ev = new PlayerInteractEvent($this, $this->inventory->getItemInHand(), $tile->getBlock(), null, 5 - $tile->getBlock()->getDamage(), PlayerInteractEvent::LEFT_CLICK_BLOCK);
|
||||||
$this->server->getPluginManager()->callEvent($ev);
|
$this->server->getPluginManager()->callEvent($ev);
|
||||||
|
@ -410,6 +410,12 @@ namespace pocketmine {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $start
|
||||||
|
* @param array|null $trace
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
function getTrace($start = 0, $trace = null){
|
function getTrace($start = 0, $trace = null){
|
||||||
if($trace === null){
|
if($trace === null){
|
||||||
if(function_exists("xdebug_get_function_stack")){
|
if(function_exists("xdebug_get_function_stack")){
|
||||||
|
@ -2156,6 +2156,10 @@ class Server{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Throwable $e
|
||||||
|
* @param array|null $trace
|
||||||
|
*/
|
||||||
public function exceptionHandler(\Throwable $e, $trace = null){
|
public function exceptionHandler(\Throwable $e, $trace = null){
|
||||||
if($e === null){
|
if($e === null){
|
||||||
return;
|
return;
|
||||||
|
@ -126,16 +126,20 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->skin = $skin;
|
$this->skin = $skin;
|
||||||
|
$this->skin->debloatGeometryData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Player[] $targets
|
* Sends the human's skin to the specified list of players. If null is given for targets, the skin will be sent to
|
||||||
|
* all viewers.
|
||||||
|
*
|
||||||
|
* @param Player[]|null $targets
|
||||||
*/
|
*/
|
||||||
public function sendSkin(array $targets) : void{
|
public function sendSkin(array $targets = null) : void{
|
||||||
$pk = new PlayerSkinPacket();
|
$pk = new PlayerSkinPacket();
|
||||||
$pk->uuid = $this->getUniqueId();
|
$pk->uuid = $this->getUniqueId();
|
||||||
$pk->skin = $this->skin;
|
$pk->skin = $this->skin;
|
||||||
$this->server->broadcastPacket($targets, $pk);
|
$this->server->broadcastPacket($targets ?? $this->hasSpawned, $pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function jump(){
|
public function jump(){
|
||||||
|
@ -87,4 +87,17 @@ class Skin{
|
|||||||
return $this->geometryData;
|
return $this->geometryData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hack to cut down on network overhead due to skins, by un-pretty-printing geometry JSON.
|
||||||
|
*
|
||||||
|
* Mojang, some stupid reason, send every single model for every single skin in the selected skin-pack.
|
||||||
|
* Not only that, they are pretty-printed.
|
||||||
|
* TODO: find out what model crap can be safely dropped from the packet (unless it gets fixed first)
|
||||||
|
*/
|
||||||
|
public function debloatGeometryData() : void{
|
||||||
|
if($this->geometryData !== ""){
|
||||||
|
$this->geometryData = (string) json_encode(json_decode($this->geometryData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -26,6 +26,7 @@ namespace pocketmine\inventory;
|
|||||||
use pocketmine\event\Timings;
|
use pocketmine\event\Timings;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\ItemFactory;
|
use pocketmine\item\ItemFactory;
|
||||||
|
use pocketmine\network\mcpe\protocol\BatchPacket;
|
||||||
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
use pocketmine\network\mcpe\protocol\CraftingDataPacket;
|
||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
use pocketmine\utils\Config;
|
use pocketmine\utils\Config;
|
||||||
@ -35,19 +36,18 @@ use pocketmine\utils\UUID;
|
|||||||
class CraftingManager{
|
class CraftingManager{
|
||||||
|
|
||||||
/** @var CraftingRecipe[] */
|
/** @var CraftingRecipe[] */
|
||||||
public $recipes = [];
|
protected $recipes = [];
|
||||||
|
|
||||||
/** @var ShapedRecipe[][] */
|
/** @var ShapedRecipe[][] */
|
||||||
protected $shapedRecipes = [];
|
protected $shapedRecipes = [];
|
||||||
/** @var ShapelessRecipe[][] */
|
/** @var ShapelessRecipe[][] */
|
||||||
protected $shapelessRecipes = [];
|
protected $shapelessRecipes = [];
|
||||||
|
|
||||||
/** @var FurnaceRecipe[] */
|
/** @var FurnaceRecipe[] */
|
||||||
public $furnaceRecipes = [];
|
protected $furnaceRecipes = [];
|
||||||
|
|
||||||
private static $RECIPE_COUNT = 0;
|
private static $RECIPE_COUNT = 0;
|
||||||
|
|
||||||
/** @var CraftingDataPacket */
|
/** @var BatchPacket */
|
||||||
private $craftingDataCache;
|
private $craftingDataCache;
|
||||||
|
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
@ -113,16 +113,21 @@ class CraftingManager{
|
|||||||
|
|
||||||
$pk->encode();
|
$pk->encode();
|
||||||
|
|
||||||
$this->craftingDataCache = $pk;
|
$batch = new BatchPacket();
|
||||||
|
$batch->addPacket($pk);
|
||||||
|
$batch->setCompressionLevel(Server::getInstance()->networkCompressionLevel);
|
||||||
|
$batch->encode();
|
||||||
|
|
||||||
|
$this->craftingDataCache = $batch;
|
||||||
Timings::$craftingDataCacheRebuildTimer->stopTiming();
|
Timings::$craftingDataCacheRebuildTimer->stopTiming();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a CraftingDataPacket for sending to players. Rebuilds the cache if it is outdated.
|
* Returns a pre-compressed CraftingDataPacket for sending to players. Rebuilds the cache if it is not found.
|
||||||
*
|
*
|
||||||
* @return CraftingDataPacket
|
* @return BatchPacket
|
||||||
*/
|
*/
|
||||||
public function getCraftingDataPacket() : CraftingDataPacket{
|
public function getCraftingDataPacket() : BatchPacket{
|
||||||
if($this->craftingDataCache === null){
|
if($this->craftingDataCache === null){
|
||||||
$this->buildCraftingDataCache();
|
$this->buildCraftingDataCache();
|
||||||
}
|
}
|
||||||
@ -230,7 +235,7 @@ class CraftingManager{
|
|||||||
/** @var Item[] $row */
|
/** @var Item[] $row */
|
||||||
foreach($map as $y => $row){
|
foreach($map as $y => $row){
|
||||||
foreach($row as $x => $item){
|
foreach($row as $x => $item){
|
||||||
$item = clone $item;
|
$map[$y][$x] = clone $item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,14 @@ namespace pocketmine\inventory;
|
|||||||
use pocketmine\utils\UUID;
|
use pocketmine\utils\UUID;
|
||||||
|
|
||||||
class MultiRecipe{
|
class MultiRecipe{
|
||||||
|
const TYPE_REPAIR_ITEM = "00000000-0000-0000-0000-000000000001";
|
||||||
|
const TYPE_MAP_EXTENDING = "D392B075-4BA1-40AE-8789-AF868D56F6CE";
|
||||||
|
const TYPE_MAP_CLONING = "85939755-BA10-4D9D-A4CC-EFB7A8E943C4";
|
||||||
|
const TYPE_MAP_UPGRADING = "AECD2294-4B94-434B-8667-4499BB2C9327";
|
||||||
|
const TYPE_BOOK_CLONING = "D1CA6B84-338E-4F2F-9C6B-76CC8B4BD98D";
|
||||||
|
const TYPE_BANNER_DUPLICATE = "B5C5D105-75A2-4076-AF2B-923EA2BF4BF0";
|
||||||
|
const TYPE_BANNER_ADD_PATTERN = "D81AAEAF-E172-4440-9225-868DF030D27B";
|
||||||
|
const TYPE_FIREWORKS = "00000000-0000-0000-0000-000000000002";
|
||||||
|
|
||||||
private $uuid;
|
private $uuid;
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ class Explosion{
|
|||||||
|
|
||||||
$this->level->setBlockIdAt($block->x, $block->y, $block->z, 0);
|
$this->level->setBlockIdAt($block->x, $block->y, $block->z, 0);
|
||||||
|
|
||||||
$t = $this->level->getTile($block);
|
$t = $this->level->getTileAt($block->x, $block->y, $block->z);
|
||||||
if($t instanceof Tile){
|
if($t instanceof Tile){
|
||||||
if($yieldDrops and $t instanceof Container){
|
if($yieldDrops and $t instanceof Container){
|
||||||
if($t instanceof Chest){
|
if($t instanceof Chest){
|
||||||
|
@ -1962,17 +1962,33 @@ class Level implements ChunkManager, Metadatable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Tile in a position, or null if not found
|
* Returns the Tile in a position, or null if not found.
|
||||||
|
*
|
||||||
|
* Note: This method wraps getTileAt(). If you're guaranteed to be passing integers, and you're using this method
|
||||||
|
* in performance-sensitive code, consider using getTileAt() instead of this method for better performance.
|
||||||
*
|
*
|
||||||
* @param Vector3 $pos
|
* @param Vector3 $pos
|
||||||
*
|
*
|
||||||
* @return Tile|null
|
* @return Tile|null
|
||||||
*/
|
*/
|
||||||
public function getTile(Vector3 $pos){
|
public function getTile(Vector3 $pos) : ?Tile{
|
||||||
$chunk = $this->getChunk($pos->x >> 4, $pos->z >> 4, false);
|
return $this->getTileAt((int) floor($pos->x), (int) floor($pos->y), (int) floor($pos->z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tile at the specified x,y,z coordinates, or null if it does not exist.
|
||||||
|
*
|
||||||
|
* @param int $x
|
||||||
|
* @param int $y
|
||||||
|
* @param int $z
|
||||||
|
*
|
||||||
|
* @return Tile|null
|
||||||
|
*/
|
||||||
|
public function getTileAt(int $x, int $y, int $z) : ?Tile{
|
||||||
|
$chunk = $this->getChunk($x >> 4, $z >> 4);
|
||||||
|
|
||||||
if($chunk !== null){
|
if($chunk !== null){
|
||||||
return $chunk->getTile($pos->x & 0x0f, $pos->y, $pos->z & 0x0f);
|
return $chunk->getTile($x & 0x0f, $y, $z & 0x0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -54,13 +54,9 @@ class Anvil extends McRegion{
|
|||||||
if($subChunk->isEmpty()){
|
if($subChunk->isEmpty()){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$nbt->Sections[++$subChunks] = new CompoundTag("", [
|
$tag = $this->serializeSubChunk($subChunk);
|
||||||
new ByteTag("Y", $y),
|
$tag->setByte("Y", $y);
|
||||||
new ByteArrayTag("Blocks", ChunkUtils::reorderByteArray($subChunk->getBlockIdArray())), //Generic in-memory chunks are currently always XZY
|
$nbt->Sections[++$subChunks] = $tag;
|
||||||
new ByteArrayTag("Data", ChunkUtils::reorderNibbleArray($subChunk->getBlockDataArray())),
|
|
||||||
new ByteArrayTag("SkyLight", ChunkUtils::reorderNibbleArray($subChunk->getBlockSkyLightArray(), "\xff")),
|
|
||||||
new ByteArrayTag("BlockLight", ChunkUtils::reorderNibbleArray($subChunk->getBlockLightArray()))
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$nbt->Biomes = new ByteArrayTag("Biomes", $chunk->getBiomeIdArray());
|
$nbt->Biomes = new ByteArrayTag("Biomes", $chunk->getBiomeIdArray());
|
||||||
@ -94,6 +90,15 @@ class Anvil extends McRegion{
|
|||||||
return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
|
return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function serializeSubChunk(SubChunk $subChunk) : CompoundTag{
|
||||||
|
return new CompoundTag("", [
|
||||||
|
new ByteArrayTag("Blocks", ChunkUtils::reorderByteArray($subChunk->getBlockIdArray())), //Generic in-memory chunks are currently always XZY
|
||||||
|
new ByteArrayTag("Data", ChunkUtils::reorderNibbleArray($subChunk->getBlockDataArray())),
|
||||||
|
new ByteArrayTag("SkyLight", ChunkUtils::reorderNibbleArray($subChunk->getBlockSkyLightArray(), "\xff")),
|
||||||
|
new ByteArrayTag("BlockLight", ChunkUtils::reorderNibbleArray($subChunk->getBlockLightArray()))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function nbtDeserialize(string $data){
|
public function nbtDeserialize(string $data){
|
||||||
$nbt = new NBT(NBT::BIG_ENDIAN);
|
$nbt = new NBT(NBT::BIG_ENDIAN);
|
||||||
try{
|
try{
|
||||||
@ -111,12 +116,7 @@ class Anvil extends McRegion{
|
|||||||
if($chunk->Sections instanceof ListTag){
|
if($chunk->Sections instanceof ListTag){
|
||||||
foreach($chunk->Sections as $subChunk){
|
foreach($chunk->Sections as $subChunk){
|
||||||
if($subChunk instanceof CompoundTag){
|
if($subChunk instanceof CompoundTag){
|
||||||
$subChunks[$subChunk->Y->getValue()] = new SubChunk(
|
$subChunks[$subChunk->Y->getValue()] = $this->deserializeSubChunk($subChunk);
|
||||||
ChunkUtils::reorderByteArray($subChunk->Blocks->getValue()),
|
|
||||||
ChunkUtils::reorderNibbleArray($subChunk->Data->getValue()),
|
|
||||||
ChunkUtils::reorderNibbleArray($subChunk->SkyLight->getValue(), "\xff"),
|
|
||||||
ChunkUtils::reorderNibbleArray($subChunk->BlockLight->getValue())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,6 +148,15 @@ class Anvil extends McRegion{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{
|
||||||
|
return new SubChunk(
|
||||||
|
ChunkUtils::reorderByteArray($subChunk->Blocks->getValue()),
|
||||||
|
ChunkUtils::reorderNibbleArray($subChunk->Data->getValue()),
|
||||||
|
ChunkUtils::reorderNibbleArray($subChunk->SkyLight->getValue(), "\xff"),
|
||||||
|
ChunkUtils::reorderNibbleArray($subChunk->BlockLight->getValue())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static function getProviderName() : string{
|
public static function getProviderName() : string{
|
||||||
return "anvil";
|
return "anvil";
|
||||||
}
|
}
|
||||||
|
@ -40,108 +40,22 @@ class PMAnvil extends Anvil{
|
|||||||
|
|
||||||
const REGION_FILE_EXTENSION = "mcapm";
|
const REGION_FILE_EXTENSION = "mcapm";
|
||||||
|
|
||||||
public function nbtSerialize(Chunk $chunk) : string{
|
protected function serializeSubChunk(SubChunk $subChunk) : CompoundTag{
|
||||||
$nbt = new CompoundTag("Level", []);
|
return new CompoundTag("", [
|
||||||
$nbt->xPos = new IntTag("xPos", $chunk->getX());
|
new ByteArrayTag("Blocks", $subChunk->getBlockIdArray()),
|
||||||
$nbt->zPos = new IntTag("zPos", $chunk->getZ());
|
new ByteArrayTag("Data", $subChunk->getBlockDataArray()),
|
||||||
|
new ByteArrayTag("SkyLight", $subChunk->getBlockSkyLightArray()),
|
||||||
$nbt->V = new ByteTag("V", 1);
|
new ByteArrayTag("BlockLight", $subChunk->getBlockLightArray())
|
||||||
$nbt->LastUpdate = new LongTag("LastUpdate", 0); //TODO
|
]);
|
||||||
$nbt->InhabitedTime = new LongTag("InhabitedTime", 0); //TODO
|
|
||||||
$nbt->TerrainPopulated = new ByteTag("TerrainPopulated", $chunk->isPopulated() ? 1 : 0);
|
|
||||||
$nbt->LightPopulated = new ByteTag("LightPopulated", $chunk->isLightPopulated() ? 1 : 0);
|
|
||||||
|
|
||||||
$nbt->Sections = new ListTag("Sections", [], NBT::TAG_Compound);
|
|
||||||
|
|
||||||
$subChunks = -1;
|
|
||||||
foreach($chunk->getSubChunks() as $y => $subChunk){
|
|
||||||
if($subChunk->isEmpty()){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$nbt->Sections[++$subChunks] = new CompoundTag("", [
|
|
||||||
new ByteTag("Y", $y),
|
|
||||||
new ByteArrayTag("Blocks", $subChunk->getBlockIdArray()),
|
|
||||||
new ByteArrayTag("Data", $subChunk->getBlockDataArray()),
|
|
||||||
new ByteArrayTag("SkyLight", $subChunk->getBlockSkyLightArray()),
|
|
||||||
new ByteArrayTag("BlockLight", $subChunk->getBlockLightArray())
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$nbt->Biomes = new ByteArrayTag("Biomes", $chunk->getBiomeIdArray());
|
|
||||||
$nbt->HeightMap = new IntArrayTag("HeightMap", $chunk->getHeightMapArray());
|
|
||||||
|
|
||||||
$entities = [];
|
|
||||||
|
|
||||||
foreach($chunk->getEntities() as $entity){
|
|
||||||
if($entity->canSaveWithChunk() and !$entity->isClosed()){
|
|
||||||
$entity->saveNBT();
|
|
||||||
$entities[] = $entity->namedtag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$nbt->Entities = new ListTag("Entities", $entities, NBT::TAG_Compound);
|
|
||||||
|
|
||||||
$tiles = [];
|
|
||||||
foreach($chunk->getTiles() as $tile){
|
|
||||||
$tile->saveNBT();
|
|
||||||
$tiles[] = $tile->namedtag;
|
|
||||||
}
|
|
||||||
|
|
||||||
$nbt->TileEntities = new ListTag("TileEntities", $tiles, NBT::TAG_Compound);
|
|
||||||
|
|
||||||
//TODO: TileTicks
|
|
||||||
|
|
||||||
$writer = new NBT(NBT::BIG_ENDIAN);
|
|
||||||
$nbt->setName("Level");
|
|
||||||
$writer->setData(new CompoundTag("", [$nbt]));
|
|
||||||
|
|
||||||
return $writer->writeCompressed(ZLIB_ENCODING_DEFLATE, RegionLoader::$COMPRESSION_LEVEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function nbtDeserialize(string $data){
|
protected function deserializeSubChunk(CompoundTag $subChunk) : SubChunk{
|
||||||
$nbt = new NBT(NBT::BIG_ENDIAN);
|
return new SubChunk(
|
||||||
try{
|
$subChunk->Blocks->getValue(),
|
||||||
$nbt->readCompressed($data);
|
$subChunk->Data->getValue(),
|
||||||
|
$subChunk->SkyLight->getValue(),
|
||||||
$chunk = $nbt->getData();
|
$subChunk->BlockLight->getValue()
|
||||||
|
);
|
||||||
if(!isset($chunk->Level) or !($chunk->Level instanceof CompoundTag)){
|
|
||||||
throw new ChunkException("Invalid NBT format");
|
|
||||||
}
|
|
||||||
|
|
||||||
$chunk = $chunk->Level;
|
|
||||||
|
|
||||||
$subChunks = [];
|
|
||||||
if($chunk->Sections instanceof ListTag){
|
|
||||||
foreach($chunk->Sections as $subChunk){
|
|
||||||
if($subChunk instanceof CompoundTag){
|
|
||||||
$subChunks[$subChunk->Y->getValue()] = new SubChunk(
|
|
||||||
$subChunk->Blocks->getValue(),
|
|
||||||
$subChunk->Data->getValue(),
|
|
||||||
$subChunk->SkyLight->getValue(),
|
|
||||||
$subChunk->BlockLight->getValue()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = new Chunk(
|
|
||||||
$chunk["xPos"],
|
|
||||||
$chunk["zPos"],
|
|
||||||
$subChunks,
|
|
||||||
isset($chunk->Entities) ? $chunk->Entities->getValue() : [],
|
|
||||||
isset($chunk->TileEntities) ? $chunk->TileEntities->getValue() : [],
|
|
||||||
isset($chunk->Biomes) ? $chunk->Biomes->getValue() : "",
|
|
||||||
isset($chunk->HeightMap) ? $chunk->HeightMap->getValue() : []
|
|
||||||
);
|
|
||||||
$result->setLightPopulated(isset($chunk->LightPopulated) ? ((bool) $chunk->LightPopulated->getValue()) : false);
|
|
||||||
$result->setPopulated(isset($chunk->TerrainPopulated) ? ((bool) $chunk->TerrainPopulated->getValue()) : false);
|
|
||||||
$result->setGenerated(true);
|
|
||||||
return $result;
|
|
||||||
}catch(\Throwable $e){
|
|
||||||
MainLogger::getLogger()->logException($e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getProviderName() : string{
|
public static function getProviderName() : string{
|
||||||
|
@ -151,22 +151,24 @@ class CompoundTag extends NamedTag implements \ArrayAccess{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value of the child tag with the specified name, or $default if the tag doesn't exist. If the child
|
* Returns the value of the child tag with the specified name, or $default if the tag doesn't exist. If the child
|
||||||
* tag is not of type $expectedType, an exception will be thrown.
|
* tag is not of type $expectedType, an exception will be thrown, unless a default is given and $badTagDefault is
|
||||||
|
* true.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param string $expectedClass
|
* @param string $expectedClass
|
||||||
* @param mixed $default
|
* @param mixed $default
|
||||||
|
* @param bool $badTagDefault Return the specified default if the tag is not of the expected type.
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getTagValue(string $name, string $expectedClass, $default = null){
|
public function getTagValue(string $name, string $expectedClass, $default = null, bool $badTagDefault = false){
|
||||||
$tag = $this->getTag($name, $expectedClass);
|
$tag = $this->getTag($name, $badTagDefault ? NamedTag::class : $expectedClass);
|
||||||
if($tag !== null){
|
if($tag instanceof $expectedClass){
|
||||||
return $tag->getValue();
|
return $tag->getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
if($default === null){
|
if($default === null){
|
||||||
throw new \RuntimeException("Tag with name \"$name\" not found and no default value given");
|
throw new \RuntimeException("Tag with name \"$name\" " . ($tag !== null ? "not of expected type" : "not found") . " and no valid default value given");
|
||||||
}
|
}
|
||||||
|
|
||||||
return $default;
|
return $default;
|
||||||
@ -179,91 +181,100 @@ class CompoundTag extends NamedTag implements \ArrayAccess{
|
|||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param int|null $default
|
* @param int|null $default
|
||||||
|
* @param bool $badTagDefault
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getByte(string $name, ?int $default = null) : int{
|
public function getByte(string $name, ?int $default = null, bool $badTagDefault = false) : int{
|
||||||
return $this->getTagValue($name, ByteTag::class, $default);
|
return $this->getTagValue($name, ByteTag::class, $default, $badTagDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param int|null $default
|
* @param int|null $default
|
||||||
|
* @param bool $badTagDefault
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getShort(string $name, ?int $default = null) : int{
|
public function getShort(string $name, ?int $default = null, bool $badTagDefault = false) : int{
|
||||||
return $this->getTagValue($name, ShortTag::class, $default);
|
return $this->getTagValue($name, ShortTag::class, $default, $badTagDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param int|null $default
|
* @param int|null $default
|
||||||
|
* @param bool $badTagDefault
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getInt(string $name, ?int $default = null) : int{
|
public function getInt(string $name, ?int $default = null, bool $badTagDefault = false) : int{
|
||||||
return $this->getTagValue($name, IntTag::class, $default);
|
return $this->getTagValue($name, IntTag::class, $default, $badTagDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param int|null $default
|
* @param int|null $default
|
||||||
|
* @param bool $badTagDefault
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getLong(string $name, ?int $default = null) : int{
|
public function getLong(string $name, ?int $default = null, bool $badTagDefault = false) : int{
|
||||||
return $this->getTagValue($name, LongTag::class, $default);
|
return $this->getTagValue($name, LongTag::class, $default, $badTagDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param float|null $default
|
* @param float|null $default
|
||||||
|
* @param bool $badTagDefault
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
public function getFloat(string $name, ?float $default = null) : float{
|
public function getFloat(string $name, ?float $default = null, bool $badTagDefault = false) : float{
|
||||||
return $this->getTagValue($name, FloatTag::class, $default);
|
return $this->getTagValue($name, FloatTag::class, $default, $badTagDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param float|null $default
|
* @param float|null $default
|
||||||
|
* @param bool $badTagDefault
|
||||||
*
|
*
|
||||||
* @return float
|
* @return float
|
||||||
*/
|
*/
|
||||||
public function getDouble(string $name, ?float $default = null) : float{
|
public function getDouble(string $name, ?float $default = null, bool $badTagDefault = false) : float{
|
||||||
return $this->getTagValue($name, DoubleTag::class, $default);
|
return $this->getTagValue($name, DoubleTag::class, $default, $badTagDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param null|string $default
|
* @param string|null $default
|
||||||
|
* @param bool $badTagDefault
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getByteArray(string $name, ?string $default = null) : string{
|
public function getByteArray(string $name, ?string $default = null, bool $badTagDefault = false) : string{
|
||||||
return $this->getTagValue($name, ByteArrayTag::class, $default);
|
return $this->getTagValue($name, ByteArrayTag::class, $default, $badTagDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param null|string $default
|
* @param string|null $default
|
||||||
|
* @param bool $badTagDefault
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getString(string $name, ?string $default = null) : string{
|
public function getString(string $name, ?string $default = null, bool $badTagDefault = false) : string{
|
||||||
return $this->getTagValue($name, StringTag::class, $default);
|
return $this->getTagValue($name, StringTag::class, $default, $badTagDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param int[]|null $default
|
* @param int[]|null $default
|
||||||
|
* @param bool $badTagDefault
|
||||||
*
|
*
|
||||||
* @return int[]
|
* @return int[]
|
||||||
*/
|
*/
|
||||||
public function getIntArray(string $name, ?array $default = null) : array{
|
public function getIntArray(string $name, ?array $default = null, bool $badTagDefault = false) : array{
|
||||||
return $this->getTagValue($name, IntArrayTag::class, $default);
|
return $this->getTagValue($name, IntArrayTag::class, $default, $badTagDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -273,11 +284,12 @@ class CompoundTag extends NamedTag implements \ArrayAccess{
|
|||||||
* @param string $name Name of the tag to set
|
* @param string $name Name of the tag to set
|
||||||
* @param string $tagClass Class that extends NamedTag
|
* @param string $tagClass Class that extends NamedTag
|
||||||
* @param mixed $value Value to set. This should be compatible with the specified tag type.
|
* @param mixed $value Value to set. This should be compatible with the specified tag type.
|
||||||
|
* @param bool $force Force set the value even if the existing tag is not the correct type (overwrite the old tag)
|
||||||
*/
|
*/
|
||||||
public function setTagValue(string $name, string $tagClass, $value) : void{
|
public function setTagValue(string $name, string $tagClass, $value, bool $force) : void{
|
||||||
assert(is_a($tagClass, NamedTag::class, true));
|
assert(is_a($tagClass, NamedTag::class, true));
|
||||||
$tag = $this->getTag($name, $tagClass);
|
$tag = $this->getTag($name, $force ? NamedTag::class : $tagClass);
|
||||||
if($tag !== null){
|
if($tag instanceof $tagClass){
|
||||||
$tag->setValue($value);
|
$tag->setValue($value);
|
||||||
}else{
|
}else{
|
||||||
$this->setTag(new $tagClass($name, $value));
|
$this->setTag(new $tagClass($name, $value));
|
||||||
@ -291,73 +303,82 @@ class CompoundTag extends NamedTag implements \ArrayAccess{
|
|||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param int $value
|
* @param int $value
|
||||||
|
* @param bool $force
|
||||||
*/
|
*/
|
||||||
public function setByte(string $name, int $value) : void{
|
public function setByte(string $name, int $value, bool $force = false) : void{
|
||||||
$this->setTagValue($name, ByteTag::class, $value);
|
$this->setTagValue($name, ByteTag::class, $value, $force);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param int $value
|
* @param int $value
|
||||||
|
* @param bool $force
|
||||||
*/
|
*/
|
||||||
public function setShort(string $name, int $value) : void{
|
public function setShort(string $name, int $value, bool $force = false) : void{
|
||||||
$this->setTagValue($name, ShortTag::class, $value);
|
$this->setTagValue($name, ShortTag::class, $value, $force);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param int $value
|
* @param int $value
|
||||||
|
* @param bool $force
|
||||||
*/
|
*/
|
||||||
public function setInt(string $name, int $value) : void{
|
public function setInt(string $name, int $value, bool $force = false) : void{
|
||||||
$this->setTagValue($name, IntTag::class, $value);
|
$this->setTagValue($name, IntTag::class, $value, $force);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param int $value
|
* @param int $value
|
||||||
|
* @param bool $force
|
||||||
*/
|
*/
|
||||||
public function setLong(string $name, int $value) : void{
|
public function setLong(string $name, int $value, bool $force = false) : void{
|
||||||
$this->setTagValue($name, LongTag::class, $value);
|
$this->setTagValue($name, LongTag::class, $value, $force);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param float $value
|
* @param float $value
|
||||||
|
* @param bool $force
|
||||||
*/
|
*/
|
||||||
public function setFloat(string $name, float $value) : void{
|
public function setFloat(string $name, float $value, bool $force = false) : void{
|
||||||
$this->setTagValue($name, FloatTag::class, $value);
|
$this->setTagValue($name, FloatTag::class, $value, $force);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param float $value
|
* @param float $value
|
||||||
|
* @param bool $force
|
||||||
*/
|
*/
|
||||||
public function setDouble(string $name, float $value) : void{
|
public function setDouble(string $name, float $value, bool $force = false) : void{
|
||||||
$this->setTagValue($name, DoubleTag::class, $value);
|
$this->setTagValue($name, DoubleTag::class, $value, $force);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param string $value
|
* @param string $value
|
||||||
|
* @param bool $force
|
||||||
*/
|
*/
|
||||||
public function setByteArray(string $name, string $value) : void{
|
public function setByteArray(string $name, string $value, bool $force = false) : void{
|
||||||
$this->setTagValue($name, ByteArrayTag::class, $value);
|
$this->setTagValue($name, ByteArrayTag::class, $value, $force);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param string $value
|
* @param string $value
|
||||||
|
* @param bool $force
|
||||||
*/
|
*/
|
||||||
public function setString(string $name, string $value) : void{
|
public function setString(string $name, string $value, bool $force = false) : void{
|
||||||
$this->setTagValue($name, StringTag::class, $value);
|
$this->setTagValue($name, StringTag::class, $value, $force);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param int[] $value
|
* @param int[] $value
|
||||||
|
* @param bool $force
|
||||||
*/
|
*/
|
||||||
public function setIntArray(string $name, array $value) : void{
|
public function setIntArray(string $name, array $value, bool $force = false) : void{
|
||||||
$this->setTagValue($name, IntArrayTag::class, $value);
|
$this->setTagValue($name, IntArrayTag::class, $value, $force);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,17 +31,17 @@ class EntityPickRequestPacket extends DataPacket{
|
|||||||
const NETWORK_ID = ProtocolInfo::ENTITY_PICK_REQUEST_PACKET;
|
const NETWORK_ID = ProtocolInfo::ENTITY_PICK_REQUEST_PACKET;
|
||||||
|
|
||||||
/** @var int */
|
/** @var int */
|
||||||
public $entityTypeId;
|
public $entityUniqueId;
|
||||||
/** @var int */
|
/** @var int */
|
||||||
public $hotbarSlot;
|
public $hotbarSlot;
|
||||||
|
|
||||||
protected function decodePayload(){
|
protected function decodePayload(){
|
||||||
$this->entityTypeId = $this->getLLong();
|
$this->entityUniqueId = $this->getLLong();
|
||||||
$this->hotbarSlot = $this->getByte();
|
$this->hotbarSlot = $this->getByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function encodePayload(){
|
protected function encodePayload(){
|
||||||
$this->putLLong($this->entityTypeId);
|
$this->putLLong($this->entityUniqueId);
|
||||||
$this->putByte($this->hotbarSlot);
|
$this->putByte($this->hotbarSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,5 +45,6 @@ interface WindowTypes{
|
|||||||
const STRUCTURE_EDITOR = 14;
|
const STRUCTURE_EDITOR = 14;
|
||||||
const TRADING = 15;
|
const TRADING = 15;
|
||||||
const COMMAND_BLOCK = 16;
|
const COMMAND_BLOCK = 16;
|
||||||
|
const JUKEBOX = 17;
|
||||||
|
|
||||||
}
|
}
|
@ -35,8 +35,8 @@ class Bed extends Spawnable{
|
|||||||
const TAG_COLOR = "color";
|
const TAG_COLOR = "color";
|
||||||
|
|
||||||
public function __construct(Level $level, CompoundTag $nbt){
|
public function __construct(Level $level, CompoundTag $nbt){
|
||||||
if(!$nbt->hasTag(self::TAG_COLOR, ByteTag::class)){
|
if(!$nbt->hasTag(self::TAG_COLOR, ByteTag::class)){ //TODO: check PC format
|
||||||
$nbt->setTag(new ByteTag(self::TAG_COLOR, 14)); //default to old red
|
$nbt->setByte(self::TAG_COLOR, 14, true); //default to old red
|
||||||
}
|
}
|
||||||
parent::__construct($level, $nbt);
|
parent::__construct($level, $nbt);
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
|
|||||||
*/
|
*/
|
||||||
public function getPair() : ?Chest{
|
public function getPair() : ?Chest{
|
||||||
if($this->isPaired()){
|
if($this->isPaired()){
|
||||||
$tile = $this->getLevel()->getTile(new Vector3($this->namedtag->getInt(self::TAG_PAIRX), $this->y, $this->namedtag->getInt(self::TAG_PAIRZ)));
|
$tile = $this->getLevel()->getTileAt($this->namedtag->getInt(self::TAG_PAIRX), $this->y, $this->namedtag->getInt(self::TAG_PAIRZ));
|
||||||
if($tile instanceof Chest){
|
if($tile instanceof Chest){
|
||||||
return $tile;
|
return $tile;
|
||||||
}
|
}
|
||||||
@ -152,8 +152,8 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
|
|||||||
|
|
||||||
$this->createPair($tile);
|
$this->createPair($tile);
|
||||||
|
|
||||||
$this->spawnToAll();
|
$this->onChanged();
|
||||||
$tile->spawnToAll();
|
$tile->onChanged();
|
||||||
$this->checkPairing();
|
$this->checkPairing();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -175,12 +175,12 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{
|
|||||||
$tile = $this->getPair();
|
$tile = $this->getPair();
|
||||||
$this->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
|
$this->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
|
||||||
|
|
||||||
$this->spawnToAll();
|
$this->onChanged();
|
||||||
|
|
||||||
if($tile instanceof Chest){
|
if($tile instanceof Chest){
|
||||||
$tile->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
|
$tile->namedtag->removeTag(self::TAG_PAIRX, self::TAG_PAIRZ);
|
||||||
$tile->checkPairing();
|
$tile->checkPairing();
|
||||||
$tile->spawnToAll();
|
$tile->onChanged();
|
||||||
}
|
}
|
||||||
$this->checkPairing();
|
$this->checkPairing();
|
||||||
|
|
||||||
|
@ -37,11 +37,12 @@ class FlowerPot extends Spawnable{
|
|||||||
const TAG_ITEM_DATA = "mData";
|
const TAG_ITEM_DATA = "mData";
|
||||||
|
|
||||||
public function __construct(Level $level, CompoundTag $nbt){
|
public function __construct(Level $level, CompoundTag $nbt){
|
||||||
|
//TODO: check PC format
|
||||||
if(!$nbt->hasTag(self::TAG_ITEM, ShortTag::class)){
|
if(!$nbt->hasTag(self::TAG_ITEM, ShortTag::class)){
|
||||||
$nbt->setTag(new ShortTag(self::TAG_ITEM, 0));
|
$nbt->setShort(self::TAG_ITEM, 0, true);
|
||||||
}
|
}
|
||||||
if(!$nbt->hasTag(self::TAG_ITEM_DATA, IntTag::class)){
|
if(!$nbt->hasTag(self::TAG_ITEM_DATA, IntTag::class)){
|
||||||
$nbt->setTag(new IntTag(self::TAG_ITEM_DATA, 0));
|
$nbt->setInt(self::TAG_ITEM_DATA, 0, true);
|
||||||
}
|
}
|
||||||
parent::__construct($level, $nbt);
|
parent::__construct($level, $nbt);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
|
|||||||
|
|
||||||
public function __construct(Level $level, CompoundTag $nbt){
|
public function __construct(Level $level, CompoundTag $nbt){
|
||||||
if(!$nbt->hasTag(self::TAG_BURN_TIME, ShortTag::class) or $nbt->getShort(self::TAG_BURN_TIME) < 0){
|
if(!$nbt->hasTag(self::TAG_BURN_TIME, ShortTag::class) or $nbt->getShort(self::TAG_BURN_TIME) < 0){
|
||||||
$nbt->setTag(new ShortTag(self::TAG_BURN_TIME, 0));
|
$nbt->setShort(self::TAG_BURN_TIME, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(
|
if(
|
||||||
@ -62,16 +62,16 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{
|
|||||||
$nbt->getShort(self::TAG_COOK_TIME) < 0 or
|
$nbt->getShort(self::TAG_COOK_TIME) < 0 or
|
||||||
($nbt->getShort(self::TAG_BURN_TIME) === 0 and $nbt->getShort(self::TAG_COOK_TIME) > 0)
|
($nbt->getShort(self::TAG_BURN_TIME) === 0 and $nbt->getShort(self::TAG_COOK_TIME) > 0)
|
||||||
){
|
){
|
||||||
$nbt->setTag(new ShortTag(self::TAG_COOK_TIME, 0));
|
$nbt->setShort(self::TAG_COOK_TIME, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$nbt->hasTag(self::TAG_MAX_TIME, ShortTag::class)){
|
if(!$nbt->hasTag(self::TAG_MAX_TIME, ShortTag::class)){
|
||||||
$nbt->setTag(new ShortTag(self::TAG_MAX_TIME, $nbt->getShort(self::TAG_BURN_TIME)));
|
$nbt->setShort(self::TAG_MAX_TIME, $nbt->getShort(self::TAG_BURN_TIME), true);
|
||||||
$nbt->removeTag(self::TAG_BURN_TICKS);
|
$nbt->removeTag(self::TAG_BURN_TICKS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$nbt->getTag(self::TAG_BURN_TICKS, ShortTag::class)){
|
if(!$nbt->getTag(self::TAG_BURN_TICKS, ShortTag::class)){
|
||||||
$nbt->setTag(new ShortTag(self::TAG_BURN_TICKS, 0));
|
$nbt->setShort(self::TAG_BURN_TICKS, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::__construct($level, $nbt);
|
parent::__construct($level, $nbt);
|
||||||
|
@ -39,11 +39,11 @@ class ItemFrame extends Spawnable{
|
|||||||
|
|
||||||
public function __construct(Level $level, CompoundTag $nbt){
|
public function __construct(Level $level, CompoundTag $nbt){
|
||||||
if(!$nbt->hasTag(self::TAG_ITEM_ROTATION, ByteTag::class)){
|
if(!$nbt->hasTag(self::TAG_ITEM_ROTATION, ByteTag::class)){
|
||||||
$nbt->setTag(new ByteTag(self::TAG_ITEM_ROTATION, 0));
|
$nbt->setByte(self::TAG_ITEM_ROTATION, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$nbt->hasTag(self::TAG_ITEM_DROP_CHANCE, FloatTag::class)){
|
if(!$nbt->hasTag(self::TAG_ITEM_DROP_CHANCE, FloatTag::class)){
|
||||||
$nbt->setTag(new FloatTag(self::TAG_ITEM_DROP_CHANCE, 1.0));
|
$nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, 1.0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::__construct($level, $nbt);
|
parent::__construct($level, $nbt);
|
||||||
|
@ -38,15 +38,17 @@ class Skull extends Spawnable{
|
|||||||
const TYPE_CREEPER = 4;
|
const TYPE_CREEPER = 4;
|
||||||
const TYPE_DRAGON = 5;
|
const TYPE_DRAGON = 5;
|
||||||
|
|
||||||
const TAG_SKULL_TYPE = "SkullType";
|
const TAG_SKULL_TYPE = "SkullType"; //TAG_Byte
|
||||||
const TAG_ROT = "Rot";
|
const TAG_ROT = "Rot"; //TAG_Byte
|
||||||
|
const TAG_MOUTH_MOVING = "MouthMoving"; //TAG_Byte
|
||||||
|
const TAG_MOUTH_TICK_COUNT = "MouthTickCount"; //TAG_Int
|
||||||
|
|
||||||
public function __construct(Level $level, CompoundTag $nbt){
|
public function __construct(Level $level, CompoundTag $nbt){
|
||||||
if(!$nbt->hasTag(self::TAG_SKULL_TYPE, ByteTag::class)){
|
if(!$nbt->hasTag(self::TAG_SKULL_TYPE, ByteTag::class)){
|
||||||
$nbt->setTag(new ByteTag(self::TAG_SKULL_TYPE, 0));
|
$nbt->setByte(self::TAG_SKULL_TYPE, 0, true);
|
||||||
}
|
}
|
||||||
if(!$nbt->hasTag(self::TAG_ROT, ByteTag::class)){
|
if(!$nbt->hasTag(self::TAG_ROT, ByteTag::class)){
|
||||||
$nbt->setTag(new ByteTag(self::TAG_ROT, 0));
|
$nbt->setByte(self::TAG_ROT, 0, true);
|
||||||
}
|
}
|
||||||
parent::__construct($level, $nbt);
|
parent::__construct($level, $nbt);
|
||||||
}
|
}
|
||||||
|
@ -164,8 +164,7 @@ class Binary{
|
|||||||
/**
|
/**
|
||||||
* Reads a 16-bit signed little-endian number
|
* Reads a 16-bit signed little-endian number
|
||||||
*
|
*
|
||||||
* @param $str
|
* @param string $str
|
||||||
*
|
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public static function readSignedLShort(string $str) : int{
|
public static function readSignedLShort(string $str) : int{
|
||||||
@ -175,8 +174,7 @@ class Binary{
|
|||||||
/**
|
/**
|
||||||
* Writes a 16-bit signed/unsigned little-endian number
|
* Writes a 16-bit signed/unsigned little-endian number
|
||||||
*
|
*
|
||||||
* @param $value
|
* @param int $value
|
||||||
*
|
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function writeLShort(int $value) : string{
|
public static function writeLShort(int $value) : string{
|
||||||
@ -379,12 +377,11 @@ class Binary{
|
|||||||
/**
|
/**
|
||||||
* Reads an 8-byte integer.
|
* Reads an 8-byte integer.
|
||||||
*
|
*
|
||||||
* @param string $x
|
* @param string $str
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public static function readLong(string $x) : int{
|
public static function readLong(string $str) : int{
|
||||||
$int = unpack("N*", $x);
|
return unpack("J", $str)[1];
|
||||||
return ($int[1] << 32) | $int[2];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -394,7 +391,7 @@ class Binary{
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function writeLong(int $value) : string{
|
public static function writeLong(int $value) : string{
|
||||||
return pack("NN", $value >> 32, $value & 0xFFFFFFFF);
|
return pack("J", $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -404,7 +401,7 @@ class Binary{
|
|||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public static function readLLong(string $str) : int{
|
public static function readLLong(string $str) : int{
|
||||||
return self::readLong(strrev($str));
|
return unpack("P", $str)[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -414,7 +411,7 @@ class Binary{
|
|||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function writeLLong(int $value) : string{
|
public static function writeLLong(int $value) : string{
|
||||||
return strrev(self::writeLong($value));
|
return pack("P", $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -342,7 +342,7 @@ class Config{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$base = $value;
|
$base = $value;
|
||||||
$this->nestedCache[$key] = $value;
|
$this->nestedCache = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -376,6 +376,26 @@ class Config{
|
|||||||
return $this->nestedCache[$key] = $base;
|
return $this->nestedCache[$key] = $base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function removeNested(string $key) : void{
|
||||||
|
$this->nestedCache = [];
|
||||||
|
|
||||||
|
$vars = explode(".", $key);
|
||||||
|
|
||||||
|
$currentNode =& $this->config;
|
||||||
|
while(count($vars) > 0){
|
||||||
|
$nodeName = array_shift($vars);
|
||||||
|
if(isset($currentNode[$nodeName])){
|
||||||
|
if(empty($vars)){ //final node
|
||||||
|
unset($currentNode[$nodeName]);
|
||||||
|
}elseif(is_array($currentNode[$nodeName])){
|
||||||
|
$currentNode =& $currentNode[$nodeName];
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $k
|
* @param $k
|
||||||
* @param mixed $default
|
* @param mixed $default
|
||||||
|
@ -119,6 +119,10 @@ class MainLogger extends \AttachableThreadedLogger{
|
|||||||
$this->logDebug = $logDebug;
|
$this->logDebug = $logDebug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Throwable $e
|
||||||
|
* @param array|null $trace
|
||||||
|
*/
|
||||||
public function logException(\Throwable $e, $trace = null){
|
public function logException(\Throwable $e, $trace = null){
|
||||||
if($trace === null){
|
if($trace === null){
|
||||||
$trace = $e->getTrace();
|
$trace = $e->getTrace();
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 9142e7decec23b302ab470a55e5ed160df4878db
|
Subproject commit a10881b0078559f646b570a12304dba71658357c
|
@ -1 +1 @@
|
|||||||
Subproject commit 4e28d74c9aafdf51b10bc274ddcf78fcb3b317d4
|
Subproject commit 3446bcc774bcc278430e2cecd9d46a47f491656f
|
Loading…
x
Reference in New Issue
Block a user