Merged branch master into Core-Rewrite (includes new NBT changes)

This commit is contained in:
Shoghi Cervantes 2014-02-26 16:26:59 +01:00
commit 38c5174da7
31 changed files with 941 additions and 339 deletions

View File

@ -48,7 +48,7 @@ class BanAPI{
$this->server->api->console->register("whitelist", "<on|off|list|add|remove|reload> [username]", array($this, "commandHandler"));
$this->server->api->console->register("op", "<player>", array($this, "commandHandler"));
$this->server->api->console->register("deop", "<player>", array($this, "commandHandler"));
$this->server->api->console->register("sudo", "<player>", array($this, "commandHandler"));
$this->server->api->console->register("sudo", "<player> <command>", array($this, "commandHandler"));
$this->server->api->console->alias("ban-ip", "banip add");
$this->server->api->console->alias("banlist", "ban list");
$this->server->api->console->alias("pardon", "ban remove");

View File

@ -249,7 +249,7 @@ class ConsoleAPI{
if(($d1 = $this->server->api->dhandle("console.command.".$cmd, array("cmd" => $cmd, "parameters" => $params, "issuer" => $issuer, "alias" => $alias))) === false
or ($d2 = $this->server->api->dhandle("console.command", array("cmd" => $cmd, "parameters" => $params, "issuer" => $issuer, "alias" => $alias))) === false){
$output = "You don't have permissions to use this command.\n";
}elseif($d1 !== true and (isset($d2) and $d2 !== true)){
}elseif($d1 !== true and (!isset($d2) or $d2 !== true)){
if(isset($this->cmds[$cmd]) and is_callable($this->cmds[$cmd])){
$output = @call_user_func($this->cmds[$cmd], $cmd, $params, $issuer, $alias);
}elseif($this->server->api->dhandle("console.command.unknown", array("cmd" => $cmd, "params" => $params, "issuer" => $issuer, "alias" => $alias)) !== false){

View File

@ -337,7 +337,7 @@ class PlayerAPI{
$players = array();
if($query !== false and $query !== true){
while(($d = $query->fetchArray(SQLITE3_ASSOC)) !== false){
$CID = PocketMinecraftServer::clientID($d["ip"], $d["port"]);
$CID = MainServer::clientID($d["ip"], $d["port"]);
if(isset($this->server->clients[$CID])){
$players[$CID] = $this->server->clients[$CID];
if($multiple === false and $d["name"] === $name){
@ -384,7 +384,7 @@ class PlayerAPI{
public function getByEID($eid){
$eid = (int) $eid;
$CID = $this->server->query("SELECT ip,port FROM players WHERE EID = '".$eid."';", true);
$CID = PocketMinecraftServer::clientID($CID["ip"], $CID["port"]);
$CID = MainServer::clientID($CID["ip"], $CID["port"]);
if(isset($this->server->clients[$CID])){
return $this->server->clients[$CID];
}

View File

@ -79,7 +79,7 @@ class ServerAPI{
public $tile;
/**
* @return PocketMinecraftServer
* @return MainServer
*/
public static function request(){
return self::$serverRequest;
@ -138,7 +138,6 @@ class ServerAPI{
"enable-query" => true,
"enable-rcon" => false,
"rcon.password" => substr(base64_encode(Utils::getRandomBytes(20, false)), 3, 10),
"send-usage" => true,
"auto-save" => true,
));
@ -156,7 +155,7 @@ class ServerAPI{
UPnP_PortForward($this->getProperty("server-port"));
}
$this->server = new PocketMinecraftServer($this->getProperty("server-name"), $this->getProperty("gamemode"), ($seed = $this->getProperty("level-seed")) != "" ? (int) $seed:false, $this->getProperty("server-port"), ($ip = $this->getProperty("server-ip")) != "" ? $ip:"0.0.0.0");
$this->server = new MainServer($this->getProperty("server-name"), $this->getProperty("gamemode"), ($seed = $this->getProperty("level-seed")) != "" ? (int) $seed:false, $this->getProperty("server-port"), ($ip = $this->getProperty("server-ip")) != "" ? $ip:"0.0.0.0");
$this->server->api = $this;
self::$serverRequest = $this->server;
console("[INFO] This server is running PocketMine-MP version ".($version->isDev() ? FORMAT_YELLOW:"").MAJOR_VERSION.FORMAT_RESET." \"".CODENAME."\" (MCPE: ".CURRENT_MINECRAFT_VERSION.") (API ".CURRENT_API_VERSION.")", true, true, 0);
@ -293,7 +292,7 @@ class ServerAPI{
$this->setProperty("memory-limit", "128M");
}
if($this->server instanceof PocketMinecraftServer){
if($this->server instanceof MainServer){
$this->server->setType($this->getProperty("server-type"));
$this->server->maxClients = $this->getProperty("max-players");
$this->server->description = $this->getProperty("description");
@ -339,11 +338,11 @@ class ServerAPI{
}
public function init(){
if(!(self::$serverRequest instanceof PocketMinecraftServer)){
if(!(self::$serverRequest instanceof MainServer)){
self::$serverRequest = $this->server;
}
if($this->getProperty("send-usage") !== false){
if($this->getProperty("send-usage", true) !== false){
$this->server->schedule(6000, array($this, "sendUsage"), array(), true); //Send the info after 5 minutes have passed
$this->sendUsage();
}

View File

@ -19,7 +19,7 @@
*
*/
class PocketMinecraftServer{
class MainServer{
public $tCnt;
public $serverID, $interface, $database, $version, $invisible, $tickMeasure, $preparedSQL, $spawn, $whitelist, $seed, $stop, $gamemode, $difficulty, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $port, $saveEnabled;
private $serverip, $evCnt, $handCnt, $events, $eventsID, $handlers, $serverType, $lastTick, $doTick, $ticks, $memoryStats, $schedule, $asyncThread, $async = array(), $asyncID = 0;
@ -228,6 +228,10 @@ class PocketMinecraftServer{
$d .= Utils::writeShort(strlen($key)).$key . Utils::writeInt(strlen($value)).$value;
}
break;
case ASYNC_FUNCTION:
$params = serialize($data["arguments"]);
$d .= Utils::writeShort(strlen($data["function"])).$data["function"] . Utils::writeInt(strlen($params)) . $params;
break;
default:
return false;
}
@ -256,6 +260,12 @@ class PocketMinecraftServer{
$data["result"] = substr($this->asyncThread->output, $offset, $len);
$offset += $len;
break;
case ASYNC_FUNCTION:
$len = Utils::readInt(substr($this->asyncThread->output, $offset, 4));
$offset += 4;
$data["result"] = unserialize(substr($this->asyncThread->output, $offset, $len));
$offset += $len;
break;
}
$this->asyncThread->output = substr($this->asyncThread->output, $offset);
if(isset($this->async[$ID]) and $this->async[$ID] !== null and is_callable($this->async[$ID])){
@ -384,6 +394,7 @@ class PocketMinecraftServer{
if($this->stop === true){
return;
}
ini_set("memory_limit", "-1"); //Fix error dump not dumped on memory problems
console("[SEVERE] An unrecovereable has ocurred and the server has crashed. Creating an error dump");
$dump = "```\r\n# PocketMine-MP Error Dump ".date("D M j H:i:s T Y")."\r\n";
$er = error_get_last();
@ -452,6 +463,7 @@ class PocketMinecraftServer{
}
$dump .= "Loaded Modules: ".var_export($extensions, true)."\r\n";
$this->checkMemory();
$dump .= "Memory Usage Tracking: \r\n".chunk_split(base64_encode(gzdeflate(implode(";", $this->memoryStats), 9)))."\r\n";
ob_start();
phpinfo();
@ -480,7 +492,7 @@ class PocketMinecraftServer{
public function packetHandler(Packet $packet){
$data =& $packet;
$CID = PocketMinecraftServer::clientID($packet->ip, $packet->port);
$CID = MainServer::clientID($packet->ip, $packet->port);
if(isset($this->clients[$CID])){
$this->clients[$CID]->handlePacket($packet);
}else{

View File

@ -104,7 +104,7 @@ class Player{
$this->server = ServerAPI::request();
$this->lastBreak = microtime(true);
$this->clientID = $clientID;
$this->CID = PocketMinecraftServer::clientID($ip, $port);
$this->CID = MainServer::clientID($ip, $port);
$this->ip = $ip;
$this->port = $port;
$this->spawnPosition = $this->server->spawn;
@ -2250,12 +2250,11 @@ class Player{
$t->spawn($this);
}else{
$nbt = new NBT();
$nbt->load($packet->namedtag);
$d = array_shift($nbt->tree);
if($d["id"] !== TILE_SIGN){
$nbt->read($packet->namedtag);
if($nbt->id !== TILE_SIGN){
$t->spawn($this);
}else{
$t->setText($d["Text1"], $d["Text2"], $d["Text3"], $d["Text4"]);
$t->setText($nbt->Text1, $nbt->Text2, $nbt->Text3, $nbt->Text4);
}
}
}

View File

@ -19,18 +19,207 @@
*
*/
class NBT{
const MODE_WRITE = 0;
const MODE_OVERWRITE = 1;
class NBT{
const LITTLE_ENDIAN = 0;
const BIG_ENDIAN = 1;
private $buffer;
private $offset;
private $mode = NBT::MODE_WRITE;
public function __construct($buffer, $endianness = NBT::BIG_ENDIAN){
private $endianness;
private $data;
public function get($len){
if($len < 0){
$this->offset = strlen($this->buffer) - 1;
return "";
}
if($len === true){
return substr($this->buffer, $this->offset);
}
$this->offset += $len;
return substr($this->buffer, $this->offset - $len, $len);
}
}
public function put($v){
$this->buffer .= $v;
}
public function feof(){
return !isset($this->buffer{$this->offset});
}
public function __construct($endianness = NBT::LITTLE_ENDIAN){
$this->offset = 0;
$this->endianness = $endianness & 0x01;
}
public function read($buffer){
$this->offset = 0;
$this->buffer = $buffer;
$this->data = $this->readTag();
}
public function write(){
$this->offset = 0;
if($this->data instanceof NBTTag_Compound){
$this->writeTag($this->data);
return $this->buffer;
}else{
return false;
}
}
public function readTag(){
switch($this->getByte()){
case NBTTag::TAG_Byte:
$tag = new NBTTag_Byte($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Byte:
$tag = new NBTTag_Byte($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Short:
$tag = new NBTTag_Short($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Int:
$tag = new NBTTag_Int($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Long:
$tag = new NBTTag_Long($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Float:
$tag = new NBTTag_Float($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Double:
$tag = new NBTTag_Double($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Byte_Array:
$tag = new NBTTag_Byte_Array($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_String:
$tag = new NBTTag_String($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_List:
$tag = new NBTTag_List($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Compound:
$tag = new NBTTag_Compound($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_Int_Array:
$tag = new NBTTag_Int_Array($this->getString());
$tag->read($this);
break;
case NBTTag::TAG_End: //No named tag
default:
$tag = new NBTTag_End;
break;
}
return $tag;
}
public function writeTag(NBTTag $tag){
$this->putByte($tag->getType());
if($tag instanceof NamedNBTTag and $tag->getName() !== false){
$this->putString($tag->getName());
}
$tag->write($this);
}
public function getByte(){
return Utils::readByte($this->get(1), true);
}
public function putByte($v){
$this->buffer .= Utils::writeByte($v);
}
public function getShort(){
return $this->endianness === self::BIG_ENDIAN ? Utils::readShort($this->get(2)) : Utils::readLShort($this->get(2));
}
public function putShort($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Utils::writeShort($v) : Utils::writeLShort($v);
}
public function getInt(){
return $this->endianness === self::BIG_ENDIAN ? Utils::readInt($this->get(4)) : Utils::readLInt($this->get(4));
}
public function putInt($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Utils::writeInt($v) : Utils::writeLInt($v);
}
public function getLong(){
return $this->endianness === self::BIG_ENDIAN ? Utils::readLong($this->get(8)) : Utils::readLLong($this->get(8));
}
public function putLong($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Utils::writeLong($v) : Utils::writeLLong($v);
}
public function getFloat(){
return $this->endianness === self::BIG_ENDIAN ? Utils::readFloat($this->get(4)) : Utils::readLFloat($this->get(4));
}
public function putFloat($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Utils::writeFloat($v) : Utils::writeLFloat($v);
}
public function getDouble(){
return $this->endianness === self::BIG_ENDIAN ? Utils::readDouble($this->get(8)) : Utils::readLDouble($this->get(8));
}
public function putDouble($v){
$this->buffer .= $this->endianness === self::BIG_ENDIAN ? Utils::writeDouble($v) : Utils::writeLDouble($v);
}
public function getString(){
return $this->get($this->getShort());
}
public function putString($v){
$this->putShort(strlen($v));
$this->buffer .= $v;
}
public function __get($name){
return $this->data instanceof NBTTag_Compound ? $this->data->{$name} : false;
}
public function __set($name, $value){
if($this->data instanceof NBTTag_Compound){
$this->data->{$name} = $value;
}
}
public function __isset($name){
return $this->data instanceof NBTTag_Compound ? isset($this->data->{$name}) : false;
}
public function __unset($name){
if($this->data instanceof NBTTag_Compound){
unset($this->data->{$name});
}
}
public function getData(){
return $this->data;
}
public function setData(NBTTag_Compound $data){
$this->data = $data;
}
}
>>>>>>> origin/master

55
src/nbt/NBTTag.php Normal file
View File

@ -0,0 +1,55 @@
<?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/
*
*
*/
abstract class NBTTag{
const TAG_End = 0;
const TAG_Byte = 1;
const TAG_Short = 2;
const TAG_Int = 3;
const TAG_Long = 4;
const TAG_Float = 5;
const TAG_Double = 6;
const TAG_Byte_Array = 7;
const TAG_String = 8;
const TAG_List = 9;
const TAG_Compound = 10;
const TAG_Int_Array = 11;
protected $value = 0;
public function getValue(){
return $this->value;
}
public abstract function getType();
public function setValue($value){
$this->value = $value;
}
abstract public function write(NBT $nbt);
abstract public function read(NBT $nbt);
public final function __toString(){
return $this->value;
}
}

43
src/nbt/NamedNBTTag.php Normal file
View File

@ -0,0 +1,43 @@
<?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/
*
*
*/
/***REM_START***/
require_once("NBTTag.php");
/***REM_END***/
abstract class NamedNBTTag extends NBTTag{
protected $name;
public function __construct($name = "", $value = false){
$this->name = $name;
if($value !== false){
$this->value = $value;
}
}
public function getName(){
return $this->name;
}
public function setName($name){
$this->name = $name;
}
}

35
src/nbt/tags/TAG_Byte.php Normal file
View File

@ -0,0 +1,35 @@
<?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/
*
*
*/
class NBTTag_Byte extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Byte;
}
public function read(NBT $nbt){
$this->value = $nbt->getByte();
}
public function write(NBT $nbt){
$nbt->putByte($this->value);
}
}

View File

@ -0,0 +1,36 @@
<?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/
*
*
*/
class NBTTag_Byte_Array extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Byte_Array;
}
public function read(NBT $nbt){
$this->value = $nbt->get($this->getInt());
}
public function write(NBT $nbt){
$nbt->putInt(strlen($this->value));
$nbt->put($this->value);
}
}

View File

@ -0,0 +1,63 @@
<?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/
*
*
*/
class NBTTag_Compound extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Compound;
}
public function __get($name){
return isset($this->value[$name]) ? $this->value[$name]->getValue() : false;
}
public function __set($name, $value){
if(isset($this->value[$name])){
$this->value[$name]->setValue($value);
}
}
public function __isset($name){
return isset($this->value[$name]);
}
public function __unset($name){
unset($this->value[$name]);
}
public function read(NBT $nbt){
$this->value = array();
do{
$tag = $nbt->readTag();
if($tag instanceof NamedNBTTag and $tag->getName() !== ""){
$this->value[$tag->getName()] = $tag;
}else{
$this->value[] = $tag;
}
}while(!($tag instanceof NBTTag_End) and !$nbt->feof());
}
public function write(NBT $nbt){
foreach($this->value as $tag){
$nbt->writeTag($tag);
}
}
}

View File

@ -0,0 +1,35 @@
<?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/
*
*
*/
class NBTTag_Double extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Double;
}
public function read(NBT $nbt){
$this->value = $nbt->getDouble();
}
public function write(NBT $nbt){
$nbt->putDouble($this->value);
}
}

35
src/nbt/tags/TAG_End.php Normal file
View File

@ -0,0 +1,35 @@
<?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/
*
*
*/
class NBTTag_End extends NBTTag{
public function getType(){
return NBTTag::TAG_End;
}
public function read(NBT $nbt){
}
public function write(NBT $nbt){
}
}

View File

@ -0,0 +1,35 @@
<?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/
*
*
*/
class NBTTag_Float extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Float;
}
public function read(NBT $nbt){
$this->value = $nbt->getFloat();
}
public function write(NBT $nbt){
$nbt->putFloat($this->value);
}
}

35
src/nbt/tags/TAG_Int.php Normal file
View File

@ -0,0 +1,35 @@
<?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/
*
*
*/
class NBTTag_Int extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Int;
}
public function read(NBT $nbt){
$this->value = $nbt->getInt();
}
public function write(NBT $nbt){
$nbt->putInt($this->value);
}
}

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/
*
*
*/
class NBTTag_Int_Array extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Int_Array;
}
public function read(NBT $nbt){
$this->value = array();
$size = $nbt->getInt();
for($i = 0; $i < $size and !$nbt->feof(); ++$i){
$this->value[] = $nbt->getInt();
}
}
public function write(NBT $nbt){
$nbt->putInt(count($this->value));
foreach($this->value as $v){
$nbt->putInt($v);
}
}
}

126
src/nbt/tags/TAG_List.php Normal file
View File

@ -0,0 +1,126 @@
<?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/
*
*
*/
class NBTTag_List extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_List;
}
public function __get($name){
return isset($this->value[$name]) ? $this->value[$name]->getValue() : false;
}
public function __set($name, $value){
if(isset($this->value[$name])){
$this->value[$name]->setValue($value);
}
}
public function __isset($name){
return isset($this->value[$name]);
}
public function __unset($name){
unset($this->value[$name]);
}
public function read(NBT $nbt){
$this->value = array();
$tagId = $nbt->getByte();
$this->value[-1] = $tagId;
$size = $nbt->getInt();
for($i = 0; $i < $size and !$nbt->feof(); ++$i){
switch($tagId){
case NBTTag::TAG_Byte:
$tag = new NBTTag_Byte(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Byte:
$tag = new NBTTag_Byte(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Short:
$tag = new NBTTag_Short(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Int:
$tag = new NBTTag_Int(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Long:
$tag = new NBTTag_Long(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Float:
$tag = new NBTTag_Float(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Double:
$tag = new NBTTag_Double(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Byte_Array:
$tag = new NBTTag_Byte_Array(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_String:
$tag = new NBTTag_String(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_List:
$tag = new NBTTag_List(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Compound:
$tag = new NBTTag_Compound(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
case NBTTag::TAG_Int_Array:
$tag = new NBTTag_Int_Array(false);
$tag->read($nbt);
$this->value[] = $tag;
break;
}
}
}
public function write(NBT $nbt){
$nbt->putByte($this->value[-1]);
$nbt->putInt(count($this->value) - 1);
foreach($this->value as $tag){
if($tag instanceof NBTTag){
$nbt->writeTag($tag);
}
}
}
}

35
src/nbt/tags/TAG_Long.php Normal file
View File

@ -0,0 +1,35 @@
<?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/
*
*
*/
class NBTTag_Long extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Long;
}
public function read(NBT $nbt){
$this->value = $nbt->getLong();
}
public function write(NBT $nbt){
$nbt->putLong($this->value);
}
}

View File

@ -0,0 +1,35 @@
<?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/
*
*
*/
class NBTTag_Short extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_Short;
}
public function read(NBT $nbt){
$this->value = $nbt->getShort();
}
public function write(NBT $nbt){
$nbt->putShort($this->value);
}
}

View File

@ -0,0 +1,36 @@
<?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/
*
*
*/
class NBTTag_String extends NamedNBTTag{
public function getType(){
return NBTTag::TAG_String;
}
public function read(NBT $nbt){
$this->value = $nbt->get($nbt->getShort());
}
public function write(NBT $nbt){
$nbt->putShort(strlen($this->value));
$nbt->put($this->value);
}
}

View File

@ -38,12 +38,9 @@ class MinecraftInterface{
}
public function readPacket(){
if($this->socket->connected === false){
return false;
}
$buf = "";
$source = false;
$port = 1;
$buf = null;
$source = null;
$port = null;
$len = $this->socket->read($buf, $source, $port);
if($len === false or $len === 0){
return false;

View File

@ -104,7 +104,11 @@ class RCONInstance extends Thread{
}
private function writePacket($client, $requestID, $packetType, $payload){
return socket_write($client, Utils::writeLInt(strlen($payload)).Utils::writeLInt((int) $requestID).Utils::writeLInt((int) $packetType).($payload === "" ? "\x00":$payload)."\x00");
$pk = Utils::writeLInt((int) $requestID)
. Utils::writeLInt((int) $packetType)
. $payload
. "\x00\x00"; //Terminate payload and packet
return socket_write($client, Utils::writeLInt(strlen($pk)).$pk);
}
private function readPacket($client, &$size, &$requestID, &$packetType, &$payload){

View File

@ -45,7 +45,6 @@ class UDPSocket{
}
public function close($error = 125){
$this->connected = false;
return @socket_close($this->sock);
}
@ -58,16 +57,10 @@ class UDPSocket{
}
public function read(&$buf, &$source, &$port){
if($this->connected === false){
return false;
}
return @socket_recvfrom($this->sock, $buf, 65535, 0, $source, $port);
}
public function write($data, $dest, $port){
if($this->connected === false){
return false;
}
return @socket_sendto($this->sock, $data, strlen($data), 0, $dest, $port);
}

View File

@ -91,7 +91,11 @@ class QueryHandler{
public function regenerateToken(){
$this->lastToken = $this->token;
$this->token = Utils::readInt("\x00".Utils::getRandomBytes(3, false));
$this->token = Utils::getRandomBytes(16, false);
}
public static function getTokenString($token, $salt){
return Utils::readInt(substr(hash("sha512", $salt . ":". $token, true), 7, 4));
}
public function handle(QueryPacket $packet){
@ -103,13 +107,13 @@ class QueryHandler{
$pk->port = $packet->port;
$pk->packetType = QueryPacket::HANDSHAKE;
$pk->sessionID = $packet->sessionID;
$pk->payload = $this->token."\x00";
$pk->payload = self::getTokenString($this->token, $packet->ip)."\x00";
$pk->encode();
$this->server->send($pk);
break;
case QueryPacket::STATISTICS: //Stat
$token = Utils::readInt(substr($packet->payload, 0, 4));
if($token !== $this->token and $token !== $this->lastToken){
if($token !== self::getTokenString($this->token, $packet->ip) and $token !== self::getTokenString($this->lastToken, $packet->ip)){
break;
}
$pk = new QueryPacket;
@ -131,4 +135,4 @@ class QueryHandler{
}
}
}
}

View File

@ -12,7 +12,7 @@
}
}
if(!class_exists("PocketMinecraftServer", false)){
if(!class_exists("MainServer", false)){
define("NO_THREADS", true);
require_once(dirname(__FILE__)."/../dependencies.php");
require_once(FILE_PATH."/src/functions.php");

View File

@ -1,213 +0,0 @@
<?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/
*
*
*/
class NBTOld{
public $tree = array();
public $binary = b"";
private $offset = 0;
const TAG_END = 0;
const TAG_BYTE = 1;
const TAG_SHORT = 2;
const TAG_INT = 3;
const TAG_LONG = 4;
const TAG_FLOAT = 5;
const TAG_DOUBLE = 6;
const TAG_BYTE_ARRAY = 7;
const TAG_STRING = 8;
const TAG_LIST = 9;
const TAG_COMPOUND = 10;
public function read($n){
if($n <= 0){
return "";
}
$this->offset += $n;
return substr($this->binary, $this->offset - $n, $n);
}
private function feof(){
return !isset($this->binary{$this->offset});
}
public function write($bin){
$this->binary .= $bin;
}
public function load($str){
$this->offset = 0;
$this->binary = (string) $str;
$this->parseTree($this->tree);
}
public function readTAG_BYTE(){
return Utils::readByte($this->read(1));
}
public function readTAG_SHORT(){
return Utils::readLShort($this->read(2));
}
public function readTAG_INT(){
return Utils::readLInt($this->read(4));
}
public function readTAG_LONG(){
return Utils::readLLong($this->read(8));
}
public function readTAG_FLOAT(){
return Utils::readLFloat($this->read(4));
}
public function readTAG_DOUBLE(){
return Utils::readLDouble($this->read(8));
}
public function readTAG_BYTE_ARRAY(){
return $this->read($this->readTAG_INT());
}
public function readTAG_STRING(){
return $this->read(Utils::readLShort($this->read(2), false));
}
public function writeTAG_BYTE($v){
$this->binary .= chr($v);
}
public function writeTAG_SHORT($v){
$this->binary .= Utils::writeLShort($v);
}
public function writeTAG_INT($v){
$this->binary .= Utils::writeLInt($v);
}
public function writeTAG_LONG($v){
$this->binary .= Utils::writeLLong($v);
}
public function writeTAG_FLOAT($v){
$this->binary .= Utils::writeLFloat($v);
}
public function writeTAG_DOUBLE($v){
$this->binary .= Utils::writeLDouble($v);
}
public function writeTAG_BYTE_ARRAY($v){
$this->binary .= $this->writeTAG_INT(strlen($v)).$v;
}
public function writeTAG_STRING($v){
$this->binary .= $this->writeTAG_SHORT(strlen($v)).$v;
}
private function parseList(&$node, $tag, $cnt){
for($i = 0; $i < $cnt and !$this->feof(); ++$i){
switch($tag){
case self::TAG_BYTE:
$value = $this->readTAG_BYTE();
break;
case self::TAG_SHORT:
$value = $this->readTAG_SHORT();
break;
case self::TAG_INT:
$value = $this->readTAG_INT();
break;
case self::TAG_LONG:
$value = $this->readTAG_LONG();
break;
case self::TAG_FLOAT:
$value = $this->readTAG_FLOAT();
break;
case self::TAG_DOUBLE:
$value = $this->readTAG_DOUBLE();
break;
case self::TAG_BYTE_ARRAY:
$value = $this->readTAG_BYTE_ARRAY();
break;
case self::TAG_STRING:
$value = $this->readTAG_STRING();
break;
case self::TAG_LIST:
$value = array();
$this->parseList($value, ord($this->read(1)), Utils::readLInt($this->read(4)));
break;
case self::TAG_COMPOUND:
$value = array();
$this->parseTree($value);
break;
default:
echo bin2hex(substr($this->binary, $this->offset - 1)).PHP_EOL.PHP_EOL;
die("Invalid NBT Tag $tag");
break;
}
$node[] = $value;
}
}
private function parseTree(&$node){
while(($tag = ord($this->read(1))) !== self::TAG_END and !$this->feof()){
$name = $this->readTAG_STRING();
switch($tag){
case self::TAG_BYTE:
$value = $this->readTAG_BYTE();
break;
case self::TAG_SHORT:
$value = $this->readTAG_SHORT();
break;
case self::TAG_INT:
$value = $this->readTAG_INT();
break;
case self::TAG_LONG:
$value = $this->readTAG_LONG();
break;
case self::TAG_FLOAT:
$value = $this->readTAG_FLOAT();
break;
case self::TAG_DOUBLE:
$value = $this->readTAG_DOUBLE();
break;
case self::TAG_BYTE_ARRAY:
$value = $this->readTAG_BYTE_ARRAY();
break;
case self::TAG_STRING:
$value = $this->readTAG_STRING();
break;
case self::TAG_LIST:
$value = array();
$this->parseList($value, ord($this->read(1)), Utils::readLInt($this->read(4)));
break;
case self::TAG_COMPOUND:
$value = array();
$this->parseTree($value);
break;
default:
echo bin2hex(substr($this->binary, $this->offset - 1)).PHP_EOL.PHP_EOL;
die("Invalid NBT Tag $tag");
break;
}
$node[$name] = $value;
}
}
}

View File

@ -21,6 +21,7 @@
define("ASYNC_CURL_GET", 1);
define("ASYNC_CURL_POST", 2);
define("ASYNC_FUNCTION", 3);
class StackableArray extends Stackable{
public function __construct(){
@ -94,6 +95,12 @@ class AsyncMultipleQueue extends Thread{
$this->output .= Utils::writeInt($rID).Utils::writeShort(ASYNC_CURL_POST).Utils::writeInt(strlen($res)).$res;
$this->unlock();
break;
case ASYNC_FUNCTION:
$function = $this->get(Utils::readShort($this->get(2), false));
$params = unserialize($this->get(Utils::readInt($this->get(4))));
$res = serialize(@call_user_func_array($function, $params));
$this->output .= Utils::writeInt($rID).Utils::writeShort(ASYNC_FUNCTION).Utils::writeInt(strlen($res)).$res;
break;
}
}
usleep(10000);

View File

@ -43,7 +43,7 @@ class Level{
$this->nextSave = $this->startCheck = microtime(true);
$this->nextSave += 90;
$this->stopTime = false;
$this->server->schedule(15, array($this, "checkThings"), array(), true);
$this->server->schedule(2, array($this, "checkThings"), array(), true);
$this->server->schedule(20 * 13, array($this, "checkTime"), array(), true);
$this->name = $name;
$this->usedChunks = array();

View File

@ -34,22 +34,22 @@ class LevelImport{
$tiles = new Config($this->path."tiles.yml", Config::YAML, unserialize(file_get_contents($this->path."tileEntities.dat")));
$tiles->save();
}elseif(file_exists($this->path."chunks.dat") and file_exists($this->path."level.dat")){ //Pocket
$nbt = new NBT();
$nbt->load(substr(file_get_contents($this->path."level.dat"), 8));
$level = array_shift($nbt->tree);
if($level["LevelName"] == ""){
$level["LevelName"] = "world".time();
$nbt = new NBT(NBT::LITTLE_ENDIAN);
$nbt->read(substr(file_get_contents($this->path."level.dat"), 8));
$level = $nbt->getData();
if($level->LevelName == ""){
$level->LevelName = "world".time();
}
console("[INFO] Importing Pocket level \"".$level["LevelName"]."\" to PMF format");
unset($level["Player"]);
$nbt->load(substr(file_get_contents($this->path."entities.dat"), 12));
$entities = array_shift($nbt->tree);
if(!isset($entities["TileEntities"])){
$entities["TileEntities"] = array();
console("[INFO] Importing Pocket level \"".$level->LevelName."\" to PMF format");
unset($level->Player);
$nbt->read(substr(file_get_contents($this->path."entities.dat"), 12));
$entities = $nbt->getData();
if(!isset($entities->TileEntities)){
$entities->TileEntities = array();
}
$tiles = $entities["TileEntities"];
$entities = $entities["Entities"];
$entities = new Config($this->path."entities.yml", Config::YAML, $entities);
$tiles = $entities->TileEntities;
$entities = $entities->Entities;
$entities = new Config($this->path."entities.yml", CONFIG_YAML, $entities);
$entities->save();
$tiles = new Config($this->path."tiles.yml", Config::YAML, $tiles);
$tiles->save();

View File

@ -356,87 +356,52 @@ class Tile extends Position{
}
switch($this->class){
case TILE_CHEST:
$nbt = new NBT();
$nbt->write(chr(NBT::TAG_COMPOUND)."\x00\x00");
$nbt->write(chr(NBT::TAG_STRING));
$nbt->writeTAG_String("id");
$nbt->writeTAG_String($this->class);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("x");
$nbt->writeTAG_Int((int) $this->x);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("y");
$nbt->writeTAG_Int((int) $this->y);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("z");
$nbt->writeTAG_Int((int) $this->z);
$nbt = new NBT(NBT::LITTLE_ENDIAN);
if($this->isPaired()){
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("pairx");
$nbt->writeTAG_Int((int) $this->data["pairx"]);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("pairz");
$nbt->writeTAG_Int((int) $this->data["pairz"]);
$nbt->setData(new NBTTag_Compound("", array(
new NBTTag_String("id", $this->class),
new NBTTag_Int("x", (int) $this->x),
new NBTTag_Int("y", (int) $this->y),
new NBTTag_Int("z", (int) $this->z),
new NBTTag_Int("pairx", (int) $this->data["pairx"]),
new NBTTag_Int("pairz", (int) $this->data["pairz"]),
new NBTTag_End
)));
}else{
$nbt->setData(new NBTTag_Compound("", array(
new NBTTag_String("id", $this->class),
new NBTTag_Int("x", (int) $this->x),
new NBTTag_Int("y", (int) $this->y),
new NBTTag_Int("z", (int) $this->z),
new NBTTag_End
)));
}
$nbt->write(chr(NBT::TAG_END));
$pk = new EntityDataPacket;
$pk->x = $this->x;
$pk->y = $this->y;
$pk->z = $this->z;
$pk->namedtag = $nbt->binary;
$pk->namedtag = $nbt->write();
$player->dataPacket($pk);
break;
case TILE_SIGN:
$nbt = new NBT();
$nbt->write(chr(NBT::TAG_COMPOUND)."\x00\x00");
$nbt->write(chr(NBT::TAG_STRING));
$nbt->writeTAG_String("Text1");
$nbt->writeTAG_String($this->data["Text1"]);
$nbt->write(chr(NBT::TAG_STRING));
$nbt->writeTAG_String("Text2");
$nbt->writeTAG_String($this->data["Text2"]);
$nbt->write(chr(NBT::TAG_STRING));
$nbt->writeTAG_String("Text3");
$nbt->writeTAG_String($this->data["Text3"]);
$nbt->write(chr(NBT::TAG_STRING));
$nbt->writeTAG_String("Text4");
$nbt->writeTAG_String($this->data["Text4"]);
$nbt->write(chr(NBT::TAG_STRING));
$nbt->writeTAG_String("id");
$nbt->writeTAG_String($this->class);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("x");
$nbt->writeTAG_Int((int) $this->x);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("y");
$nbt->writeTAG_Int((int) $this->y);
$nbt->write(chr(NBT::TAG_INT));
$nbt->writeTAG_String("z");
$nbt->writeTAG_Int((int) $this->z);
$nbt->write(chr(NBT::TAG_END));
$nbt = new NBT(NBT::LITTLE_ENDIAN);
$nbt->setData(new NBTTag_Compound("", array(
new NBTTag_String("Text1", $this->data["Text1"]),
new NBTTag_String("Text2", $this->data["Text2"]),
new NBTTag_String("Text3", $this->data["Text3"]),
new NBTTag_String("Text4", $this->data["Text4"]),
new NBTTag_String("id", $this->class),
new NBTTag_Int("x", (int) $this->x),
new NBTTag_Int("y", (int) $this->y),
new NBTTag_Int("z", (int) $this->z),
new NBTTag_End
)));
$pk = new EntityDataPacket;
$pk->x = $this->x;
$pk->y = $this->y;
$pk->z = $this->z;
$pk->namedtag = $nbt->binary;
$pk->namedtag = $nbt->write();
$player->dataPacket($pk);
break;
}