mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-16 18:59:00 +00:00
Updated some packets for 0.12, UUIDs, other stuff!
This commit is contained in:
parent
4258e22c02
commit
5621ab0c49
@ -25,6 +25,7 @@ use pocketmine\event\server\LowMemoryEvent;
|
||||
use pocketmine\event\Timings;
|
||||
use pocketmine\scheduler\GarbageCollectionTask;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\UUID;
|
||||
|
||||
class MemoryManager{
|
||||
|
||||
@ -231,7 +232,7 @@ class MemoryManager{
|
||||
}
|
||||
|
||||
$this->leakInfo[$identifier] = [
|
||||
"id" => $id = Utils::dataToUUID($identifier . ":" . $this->leakSeed++),
|
||||
"id" => $id = md5($identifier . ":" . $this->leakSeed++),
|
||||
"class" => get_class($object),
|
||||
"hash" => $identifier
|
||||
];
|
||||
|
@ -127,6 +127,7 @@ use pocketmine\tile\Spawnable;
|
||||
use pocketmine\tile\Tile;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\UUID;
|
||||
use raklib\Binary;
|
||||
|
||||
/**
|
||||
@ -161,6 +162,8 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
|
||||
protected $sendIndex = 0;
|
||||
|
||||
private $clientSecret;
|
||||
|
||||
/** @var Vector3 */
|
||||
public $speed = null;
|
||||
|
||||
@ -182,7 +185,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
public $creationTime = 0;
|
||||
|
||||
protected $randomClientId;
|
||||
protected $uuid;
|
||||
|
||||
protected $lastMovement = 0;
|
||||
/** @var Vector3 */
|
||||
@ -253,8 +255,8 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
return $this->randomClientId;
|
||||
}
|
||||
|
||||
public function getUniqueId(){
|
||||
return $this->uuid;
|
||||
public function getClientSecret(){
|
||||
return $this->clientSecretId;
|
||||
}
|
||||
|
||||
public function isBanned(){
|
||||
@ -352,7 +354,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
* @return bool
|
||||
*/
|
||||
public function canSee(Player $player){
|
||||
return !isset($this->hiddenPlayers[$player->getUniqueId()]);
|
||||
return !isset($this->hiddenPlayers[$player->getRawUniqueId()]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -362,7 +364,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
if($player === $this){
|
||||
return;
|
||||
}
|
||||
$this->hiddenPlayers[$player->getUniqueId()] = $player;
|
||||
$this->hiddenPlayers[$player->getRawUniqueId()] = $player;
|
||||
$player->despawnFrom($this);
|
||||
}
|
||||
|
||||
@ -373,7 +375,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
if($player === $this){
|
||||
return;
|
||||
}
|
||||
unset($this->hiddenPlayers[$player->getUniqueId()]);
|
||||
unset($this->hiddenPlayers[$player->getRawUniqueId()]);
|
||||
if($player->isOnline()){
|
||||
$player->spawnTo($this);
|
||||
}
|
||||
@ -510,7 +512,8 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
$this->newPosition = new Vector3(0, 0, 0);
|
||||
$this->boundingBox = new AxisAlignedBB(0, 0, 0, 0, 0, 0);
|
||||
|
||||
$this->uuid = Utils::dataToUUID($ip, $port, $clientID);
|
||||
$this->uuid = null;
|
||||
$this->rawUUID = null;
|
||||
|
||||
$this->creationTime = microtime(true);
|
||||
}
|
||||
@ -560,12 +563,15 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
*/
|
||||
public function setDisplayName($name){
|
||||
$this->displayName = $name;
|
||||
if($this->spawned){
|
||||
$this->server->updatePlayerListData($this->getUniqueId(), $this->getId(), $this->getDisplayName(), $isSlim, $str);
|
||||
}
|
||||
}
|
||||
|
||||
public function setSkin($str, $isSlim = false){
|
||||
parent::setSkin($str, $isSlim);
|
||||
if($this->spawned){
|
||||
$this->respawnToAll();
|
||||
$this->server->updatePlayerListData($this->getUniqueId(), $this->getId(), $this->getDisplayName(), $isSlim, $str);
|
||||
}
|
||||
}
|
||||
|
||||
@ -621,18 +627,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
$entity->despawnFrom($this);
|
||||
}
|
||||
}
|
||||
//TODO HACK: removes tile entities that linger whenever you teleport
|
||||
// to a different world
|
||||
$pk = new UpdateBlockPacket();
|
||||
foreach($level->getChunkTiles($x, $z) as $tile){
|
||||
if($tile instanceof Spawnable){
|
||||
$pk->records[] = [$tile->x, $tile->z, $tile->y, 0, 0, UpdateBlockPacket::FLAG_NONE];
|
||||
}
|
||||
}
|
||||
if(count($pk->records)){
|
||||
$this->dataPacket($pk);
|
||||
}
|
||||
//----
|
||||
|
||||
unset($this->usedChunks[$index]);
|
||||
}
|
||||
@ -1580,6 +1574,192 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
return ($dot1 - $dot) >= -$maxDiff;
|
||||
}
|
||||
|
||||
public function onPlayerPreLogin(){
|
||||
//TODO: implement auth
|
||||
$this->tryAuthenticate();
|
||||
}
|
||||
|
||||
public function tryAuthenticate(){
|
||||
//TODO: implement authentication after it is available
|
||||
$this->authenticateCallback(true);
|
||||
}
|
||||
|
||||
public function authenticateCallback($valid){
|
||||
|
||||
//TODO add more stuff after authentication is available
|
||||
if(!$valid){
|
||||
$this->close("", "disconnectionScreen.invalidSession");
|
||||
return;
|
||||
}
|
||||
|
||||
$this->processLogin();
|
||||
}
|
||||
|
||||
protected function processLogin(){
|
||||
if(!$this->server->isWhitelisted(strtolower($this->getName()))){
|
||||
$this->close($this->getLeaveMessage(), "Server is white-listed");
|
||||
|
||||
return;
|
||||
}elseif($this->server->getNameBans()->isBanned(strtolower($this->getName())) or $this->server->getIPBans()->isBanned($this->getAddress())){
|
||||
$this->close($this->getLeaveMessage(), "You are banned");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if($this->hasPermission(Server::BROADCAST_CHANNEL_USERS)){
|
||||
$this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_USERS, $this);
|
||||
}
|
||||
if($this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)){
|
||||
$this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this);
|
||||
}
|
||||
|
||||
foreach($this->server->getOnlinePlayers() as $p){
|
||||
if($p !== $this and strtolower($p->getName()) === strtolower($this->getName())){
|
||||
if($p->kick("logged in from another location") === false){
|
||||
$this->close($this->getLeaveMessage(), "Logged in from another location");
|
||||
return;
|
||||
}
|
||||
}elseif($p->loggedIn and $this->getUniqueId()->equals($p->getUniqueId())){
|
||||
if($p->kick("logged in from another location") === false){
|
||||
$this->close($this->getLeaveMessage(), "Logged in from another location");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$nbt = $this->server->getOfflinePlayerData($this->username);
|
||||
if(!isset($nbt->NameTag)){
|
||||
$nbt->NameTag = new String("NameTag", $this->username);
|
||||
}else{
|
||||
$nbt["NameTag"] = $this->username;
|
||||
}
|
||||
$this->gamemode = $nbt["playerGameType"] & 0x03;
|
||||
if($this->server->getForceGamemode()){
|
||||
$this->gamemode = $this->server->getGamemode();
|
||||
$nbt->playerGameType = new Int("playerGameType", $this->gamemode);
|
||||
}
|
||||
|
||||
$this->allowFlight = $this->isCreative();
|
||||
|
||||
|
||||
if(($level = $this->server->getLevelByName($nbt["Level"])) === null){
|
||||
$this->setLevel($this->server->getDefaultLevel());
|
||||
$nbt["Level"] = $this->level->getName();
|
||||
$nbt["Pos"][0] = $this->level->getSpawnLocation()->x;
|
||||
$nbt["Pos"][1] = $this->level->getSpawnLocation()->y;
|
||||
$nbt["Pos"][2] = $this->level->getSpawnLocation()->z;
|
||||
}else{
|
||||
$this->setLevel($level);
|
||||
}
|
||||
|
||||
if(!($nbt instanceof Compound)){
|
||||
$this->close($this->getLeaveMessage(), "Invalid data");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->achievements = [];
|
||||
|
||||
/** @var Byte $achievement */
|
||||
foreach($nbt->Achievements as $achievement){
|
||||
$this->achievements[$achievement->getName()] = $achievement->getValue() > 0 ? true : false;
|
||||
}
|
||||
|
||||
$nbt->lastPlayed = new Long("lastPlayed", floor(microtime(true) * 1000));
|
||||
if($this->server->getAutoSave()){
|
||||
$this->server->saveOfflinePlayerData($this->username, $nbt, true);
|
||||
}
|
||||
|
||||
parent::__construct($this->level->getChunk($nbt["Pos"][0] >> 4, $nbt["Pos"][2] >> 4, true), $nbt);
|
||||
$this->loggedIn = true;
|
||||
$this->server->addOnlinePlayer($this);
|
||||
|
||||
$this->server->getPluginManager()->callEvent($ev = new PlayerLoginEvent($this, "Plugin reason"));
|
||||
if($ev->isCancelled()){
|
||||
$this->close($this->getLeaveMessage(), $ev->getKickMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if($this->isCreative()){
|
||||
$this->inventory->setHeldItemSlot(0);
|
||||
}else{
|
||||
$this->inventory->setHeldItemSlot(0);
|
||||
}
|
||||
|
||||
$pk = new PlayStatusPacket();
|
||||
$pk->status = PlayStatusPacket::LOGIN_SUCCESS;
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
|
||||
if($this->spawnPosition === null and isset($this->namedtag->SpawnLevel) and ($level = $this->server->getLevelByName($this->namedtag["SpawnLevel"])) instanceof Level){
|
||||
$this->spawnPosition = new Position($this->namedtag["SpawnX"], $this->namedtag["SpawnY"], $this->namedtag["SpawnZ"], $level);
|
||||
}
|
||||
|
||||
$spawnPosition = $this->getSpawn();
|
||||
|
||||
$pk = new StartGamePacket();
|
||||
$pk->seed = -1;
|
||||
$pk->x = $this->x;
|
||||
$pk->y = $this->y;
|
||||
$pk->z = $this->z;
|
||||
$pk->spawnX = (int) $spawnPosition->x;
|
||||
$pk->spawnY = (int) $spawnPosition->y;
|
||||
$pk->spawnZ = (int) $spawnPosition->z;
|
||||
$pk->generator = 1; //0 old, 1 infinite, 2 flat
|
||||
$pk->gamemode = $this->gamemode & 0x01;
|
||||
$pk->eid = 0; //Always use EntityID as zero for the actual player
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
|
||||
$pk = new SetTimePacket();
|
||||
$pk->time = $this->level->getTime();
|
||||
$pk->started = $this->level->stopTime == false;
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
|
||||
$pk = new SetSpawnPositionPacket();
|
||||
$pk->x = (int) $spawnPosition->x;
|
||||
$pk->y = (int) $spawnPosition->y;
|
||||
$pk->z = (int) $spawnPosition->z;
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
|
||||
$pk = new SetHealthPacket();
|
||||
$pk->health = $this->getHealth();
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
|
||||
$pk = new SetDifficultyPacket();
|
||||
$pk->difficulty = $this->server->getDifficulty();
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
|
||||
$this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("pocketmine.player.logIn", [
|
||||
TextFormat::AQUA . $this->username . TextFormat::WHITE,
|
||||
$this->ip,
|
||||
$this->port,
|
||||
$this->id,
|
||||
$this->level->getName(),
|
||||
round($this->x, 4),
|
||||
round($this->y, 4),
|
||||
round($this->z, 4)
|
||||
]));
|
||||
|
||||
if($this->isOp()){
|
||||
$this->setRemoveFormat(false);
|
||||
}
|
||||
|
||||
if($this->gamemode === Player::SPECTATOR){
|
||||
$pk = new ContainerSetContentPacket();
|
||||
$pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE;
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
}else{
|
||||
$pk = new ContainerSetContentPacket();
|
||||
$pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE;
|
||||
$pk->slots = Item::getCreativeItems();
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
}
|
||||
|
||||
$this->forceMovement = $this->teleportPosition = $this->getPosition();
|
||||
|
||||
$this->server->onPlayerLogin($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a Minecraft packet
|
||||
* TODO: Separate all of this in handlers
|
||||
@ -1624,7 +1804,9 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
$this->randomClientId = $packet->clientId;
|
||||
$this->loginData = ["clientId" => $packet->clientId, "loginData" => null];
|
||||
|
||||
$this->uuid = Utils::dataToUUID($this->randomClientId, $this->iusername, $this->getAddress());
|
||||
$this->uuid = $packet->clientUUID;
|
||||
$this->clientSecret = $packet->clientSecret;
|
||||
$this->rawUUID = $this->uuid->toBinary();
|
||||
|
||||
if(count($this->server->getOnlinePlayers()) > $this->server->getMaxPlayers() and $this->kick("disconnectionScreen.serverFull", false)){
|
||||
break;
|
||||
@ -1687,164 +1869,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
break;
|
||||
}
|
||||
|
||||
if(!$this->server->isWhitelisted(strtolower($this->getName()))){
|
||||
$this->close($this->getLeaveMessage(), "Server is white-listed");
|
||||
|
||||
break;
|
||||
}elseif($this->server->getNameBans()->isBanned(strtolower($this->getName())) or $this->server->getIPBans()->isBanned($this->getAddress())){
|
||||
$this->close($this->getLeaveMessage(), "You are banned");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if($this->hasPermission(Server::BROADCAST_CHANNEL_USERS)){
|
||||
$this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_USERS, $this);
|
||||
}
|
||||
if($this->hasPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE)){
|
||||
$this->server->getPluginManager()->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this);
|
||||
}
|
||||
|
||||
foreach($this->server->getOnlinePlayers() as $p){
|
||||
if($p !== $this and strtolower($p->getName()) === strtolower($this->getName())){
|
||||
if($p->kick("logged in from another location") === false){
|
||||
$this->close($this->getLeaveMessage(), "Logged in from another location");
|
||||
|
||||
$timings->stopTiming();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$nbt = $this->server->getOfflinePlayerData($this->username);
|
||||
if(!isset($nbt->NameTag)){
|
||||
$nbt->NameTag = new String("NameTag", $this->username);
|
||||
}else{
|
||||
$nbt["NameTag"] = $this->username;
|
||||
}
|
||||
$this->gamemode = $nbt["playerGameType"] & 0x03;
|
||||
if($this->server->getForceGamemode()){
|
||||
$this->gamemode = $this->server->getGamemode();
|
||||
$nbt->playerGameType = new Int("playerGameType", $this->gamemode);
|
||||
}
|
||||
|
||||
$this->allowFlight = $this->isCreative();
|
||||
|
||||
|
||||
if(($level = $this->server->getLevelByName($nbt["Level"])) === null){
|
||||
$this->setLevel($this->server->getDefaultLevel());
|
||||
$nbt["Level"] = $this->level->getName();
|
||||
$nbt["Pos"][0] = $this->level->getSpawnLocation()->x;
|
||||
$nbt["Pos"][1] = $this->level->getSpawnLocation()->y;
|
||||
$nbt["Pos"][2] = $this->level->getSpawnLocation()->z;
|
||||
}else{
|
||||
$this->setLevel($level);
|
||||
}
|
||||
|
||||
if(!($nbt instanceof Compound)){
|
||||
$this->close($this->getLeaveMessage(), "Invalid data");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$this->achievements = [];
|
||||
|
||||
/** @var Byte $achievement */
|
||||
foreach($nbt->Achievements as $achievement){
|
||||
$this->achievements[$achievement->getName()] = $achievement->getValue() > 0 ? true : false;
|
||||
}
|
||||
|
||||
$nbt->lastPlayed = new Long("lastPlayed", floor(microtime(true) * 1000));
|
||||
if($this->server->getAutoSave()){
|
||||
$this->server->saveOfflinePlayerData($this->username, $nbt, true);
|
||||
}
|
||||
|
||||
parent::__construct($this->level->getChunk($nbt["Pos"][0] >> 4, $nbt["Pos"][2] >> 4, true), $nbt);
|
||||
$this->loggedIn = true;
|
||||
|
||||
$this->server->getPluginManager()->callEvent($ev = new PlayerLoginEvent($this, "Plugin reason"));
|
||||
if($ev->isCancelled()){
|
||||
$this->close($this->getLeaveMessage(), $ev->getKickMessage());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if($this->isCreative()){
|
||||
$this->inventory->setHeldItemSlot(0);
|
||||
}else{
|
||||
$this->inventory->setHeldItemSlot(0);
|
||||
}
|
||||
|
||||
$pk = new PlayStatusPacket();
|
||||
$pk->status = PlayStatusPacket::LOGIN_SUCCESS;
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
|
||||
if($this->spawnPosition === null and isset($this->namedtag->SpawnLevel) and ($level = $this->server->getLevelByName($this->namedtag["SpawnLevel"])) instanceof Level){
|
||||
$this->spawnPosition = new Position($this->namedtag["SpawnX"], $this->namedtag["SpawnY"], $this->namedtag["SpawnZ"], $level);
|
||||
}
|
||||
|
||||
$spawnPosition = $this->getSpawn();
|
||||
|
||||
$pk = new StartGamePacket();
|
||||
$pk->seed = -1;
|
||||
$pk->x = $this->x;
|
||||
$pk->y = $this->y;
|
||||
$pk->z = $this->z;
|
||||
$pk->spawnX = (int) $spawnPosition->x;
|
||||
$pk->spawnY = (int) $spawnPosition->y;
|
||||
$pk->spawnZ = (int) $spawnPosition->z;
|
||||
$pk->generator = 1; //0 old, 1 infinite, 2 flat
|
||||
$pk->gamemode = $this->gamemode & 0x01;
|
||||
$pk->eid = 0; //Always use EntityID as zero for the actual player
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
|
||||
$pk = new SetTimePacket();
|
||||
$pk->time = $this->level->getTime();
|
||||
$pk->started = $this->level->stopTime == false;
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
|
||||
$pk = new SetSpawnPositionPacket();
|
||||
$pk->x = (int) $spawnPosition->x;
|
||||
$pk->y = (int) $spawnPosition->y;
|
||||
$pk->z = (int) $spawnPosition->z;
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
|
||||
$pk = new SetHealthPacket();
|
||||
$pk->health = $this->getHealth();
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
|
||||
$pk = new SetDifficultyPacket();
|
||||
$pk->difficulty = $this->server->getDifficulty();
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
|
||||
$this->server->getLogger()->info($this->getServer()->getLanguage()->translateString("pocketmine.player.logIn", [
|
||||
TextFormat::AQUA . $this->username . TextFormat::WHITE,
|
||||
$this->ip,
|
||||
$this->port,
|
||||
$this->id,
|
||||
$this->level->getName(),
|
||||
round($this->x, 4),
|
||||
round($this->y, 4),
|
||||
round($this->z, 4)
|
||||
]));
|
||||
|
||||
if($this->isOp()){
|
||||
$this->setRemoveFormat(false);
|
||||
}
|
||||
|
||||
if($this->gamemode === Player::SPECTATOR){
|
||||
$pk = new ContainerSetContentPacket();
|
||||
$pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE;
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
}else{
|
||||
$pk = new ContainerSetContentPacket();
|
||||
$pk->windowid = ContainerSetContentPacket::SPECIAL_CREATIVE;
|
||||
$pk->slots = Item::getCreativeItems();
|
||||
$this->dataPacket($pk->setChannel(Network::CHANNEL_PRIORITY));
|
||||
}
|
||||
|
||||
$this->forceMovement = $this->teleportPosition = $this->getPosition();
|
||||
|
||||
$this->server->onPlayerLogin($this);
|
||||
$this->onPlayerPreLogin();
|
||||
|
||||
break;
|
||||
case ProtocolInfo::MOVE_PLAYER_PACKET:
|
||||
@ -1873,7 +1898,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
}
|
||||
|
||||
break;
|
||||
case ProtocolInfo::PLAYER_EQUIPMENT_PACKET:
|
||||
case ProtocolInfo::MOB_EQUIPMENT_PACKET:
|
||||
if($this->spawned === false or !$this->isAlive()){
|
||||
break;
|
||||
}
|
||||
@ -2243,7 +2268,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
}
|
||||
break;
|
||||
|
||||
case ProtocolInfo::PLAYER_ARMOR_EQUIPMENT_PACKET:
|
||||
case ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET:
|
||||
break;
|
||||
|
||||
case ProtocolInfo::INTERACT_PACKET:
|
||||
@ -2527,136 +2552,138 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
}
|
||||
break;
|
||||
|
||||
case ProtocolInfo::CONTAINER_SET_CONTENT_PACKET:
|
||||
if($packet->windowid === ContainerSetContentPacket::SPECIAL_CRAFTING){
|
||||
if(count($packet->slots) < 9){
|
||||
$this->inventory->sendContents($this);
|
||||
break;
|
||||
case ProtocolInfo::CRAFTING_EVENT_PACKET:
|
||||
//TODO HACK
|
||||
$this->server->getLogger()->warning("CRAFTING NOT YET IMPLEMENTED!");
|
||||
break;
|
||||
if(count($packet->slots) < 9){
|
||||
$this->inventory->sendContents($this);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($packet->slots as $i => $item){
|
||||
/** @var Item $item */
|
||||
if($item->getDamage() === -1 or $item->getDamage() === 0xffff){
|
||||
$item->setDamage(null);
|
||||
}
|
||||
|
||||
foreach($packet->slots as $i => $item){
|
||||
/** @var Item $item */
|
||||
if($item->getDamage() === -1 or $item->getDamage() === 0xffff){
|
||||
$item->setDamage(null);
|
||||
}
|
||||
|
||||
if($i < 9 and $item->getId() > 0){
|
||||
$item->setCount(1);
|
||||
}
|
||||
}
|
||||
|
||||
$result = $packet->slots[9];
|
||||
|
||||
if($this->craftingType === 1 or $this->craftingType === 2){
|
||||
$recipe = new BigShapelessRecipe($result);
|
||||
}else{
|
||||
$recipe = new ShapelessRecipe($result);
|
||||
}
|
||||
|
||||
/** @var Item[] $ingredients */
|
||||
$ingredients = [];
|
||||
for($x = 0; $x < 3; ++$x){
|
||||
for($y = 0; $y < 3; ++$y){
|
||||
$item = $packet->slots[$x * 3 + $y];
|
||||
if($item->getCount() > 0 and $item->getId() > 0){
|
||||
//TODO shaped
|
||||
$recipe->addIngredient($item);
|
||||
$ingredients[$x * 3 + $y] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!Server::getInstance()->getCraftingManager()->matchRecipe($recipe)){
|
||||
$this->server->getLogger()->debug("Unmatched recipe from player ". $this->getName() .": " . $recipe->getResult().", using: " . implode(", ", $recipe->getIngredientList()));
|
||||
$this->inventory->sendContents($this);
|
||||
break;
|
||||
}
|
||||
|
||||
$canCraft = true;
|
||||
|
||||
$used = array_fill(0, $this->inventory->getSize(), 0);
|
||||
|
||||
foreach($ingredients as $ingredient){
|
||||
$slot = -1;
|
||||
$checkDamage = $ingredient->getDamage() === null ? false : true;
|
||||
foreach($this->inventory->getContents() as $index => $i){
|
||||
if($ingredient->equals($i, $checkDamage) and ($i->getCount() - $used[$index]) >= 1){
|
||||
$slot = $index;
|
||||
$used[$index]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($slot === -1){
|
||||
$canCraft = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$canCraft){
|
||||
$this->inventory->sendContents($this);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($used as $slot => $count){
|
||||
if($count === 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = $this->inventory->getItem($slot);
|
||||
|
||||
if($item->getCount() > $count){
|
||||
$newItem = clone $item;
|
||||
$newItem->setCount($item->getCount() - $count);
|
||||
}else{
|
||||
$newItem = Item::get(Item::AIR, 0, 0);
|
||||
}
|
||||
|
||||
$this->inventory->setItem($slot, $newItem);
|
||||
}
|
||||
|
||||
$extraItem = $this->inventory->addItem($recipe->getResult());
|
||||
if(count($extraItem) > 0){
|
||||
foreach($extraItem as $item){
|
||||
$this->level->dropItem($this, $item);
|
||||
}
|
||||
}
|
||||
|
||||
switch($recipe->getResult()->getId()){
|
||||
case Item::WORKBENCH:
|
||||
$this->awardAchievement("buildWorkBench");
|
||||
break;
|
||||
case Item::WOODEN_PICKAXE:
|
||||
$this->awardAchievement("buildPickaxe");
|
||||
break;
|
||||
case Item::FURNACE:
|
||||
$this->awardAchievement("buildFurnace");
|
||||
break;
|
||||
case Item::WOODEN_HOE:
|
||||
$this->awardAchievement("buildHoe");
|
||||
break;
|
||||
case Item::BREAD:
|
||||
$this->awardAchievement("makeBread");
|
||||
break;
|
||||
case Item::CAKE:
|
||||
//TODO: detect complex recipes like cake that leave remains
|
||||
$this->awardAchievement("bakeCake");
|
||||
$this->inventory->addItem(Item::get(Item::BUCKET, 0, 3));
|
||||
break;
|
||||
case Item::STONE_PICKAXE:
|
||||
case Item::GOLD_PICKAXE:
|
||||
case Item::IRON_PICKAXE:
|
||||
case Item::DIAMOND_PICKAXE:
|
||||
$this->awardAchievement("buildBetterPickaxe");
|
||||
break;
|
||||
case Item::WOODEN_SWORD:
|
||||
$this->awardAchievement("buildSword");
|
||||
break;
|
||||
case Item::DIAMOND:
|
||||
$this->awardAchievement("diamond");
|
||||
break;
|
||||
if($i < 9 and $item->getId() > 0){
|
||||
$item->setCount(1);
|
||||
}
|
||||
}
|
||||
|
||||
$result = $packet->slots[9];
|
||||
|
||||
if($this->craftingType === 1 or $this->craftingType === 2){
|
||||
$recipe = new BigShapelessRecipe($result);
|
||||
}else{
|
||||
$recipe = new ShapelessRecipe($result);
|
||||
}
|
||||
|
||||
/** @var Item[] $ingredients */
|
||||
$ingredients = [];
|
||||
for($x = 0; $x < 3; ++$x){
|
||||
for($y = 0; $y < 3; ++$y){
|
||||
$item = $packet->slots[$x * 3 + $y];
|
||||
if($item->getCount() > 0 and $item->getId() > 0){
|
||||
//TODO shaped
|
||||
$recipe->addIngredient($item);
|
||||
$ingredients[$x * 3 + $y] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!Server::getInstance()->getCraftingManager()->matchRecipe($recipe)){
|
||||
$this->server->getLogger()->debug("Unmatched recipe from player ". $this->getName() .": " . $recipe->getResult().", using: " . implode(", ", $recipe->getIngredientList()));
|
||||
$this->inventory->sendContents($this);
|
||||
break;
|
||||
}
|
||||
|
||||
$canCraft = true;
|
||||
|
||||
$used = array_fill(0, $this->inventory->getSize(), 0);
|
||||
|
||||
foreach($ingredients as $ingredient){
|
||||
$slot = -1;
|
||||
$checkDamage = $ingredient->getDamage() === null ? false : true;
|
||||
foreach($this->inventory->getContents() as $index => $i){
|
||||
if($ingredient->equals($i, $checkDamage) and ($i->getCount() - $used[$index]) >= 1){
|
||||
$slot = $index;
|
||||
$used[$index]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($slot === -1){
|
||||
$canCraft = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$canCraft){
|
||||
$this->inventory->sendContents($this);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($used as $slot => $count){
|
||||
if($count === 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = $this->inventory->getItem($slot);
|
||||
|
||||
if($item->getCount() > $count){
|
||||
$newItem = clone $item;
|
||||
$newItem->setCount($item->getCount() - $count);
|
||||
}else{
|
||||
$newItem = Item::get(Item::AIR, 0, 0);
|
||||
}
|
||||
|
||||
$this->inventory->setItem($slot, $newItem);
|
||||
}
|
||||
|
||||
$extraItem = $this->inventory->addItem($recipe->getResult());
|
||||
if(count($extraItem) > 0){
|
||||
foreach($extraItem as $item){
|
||||
$this->level->dropItem($this, $item);
|
||||
}
|
||||
}
|
||||
|
||||
switch($recipe->getResult()->getId()){
|
||||
case Item::WORKBENCH:
|
||||
$this->awardAchievement("buildWorkBench");
|
||||
break;
|
||||
case Item::WOODEN_PICKAXE:
|
||||
$this->awardAchievement("buildPickaxe");
|
||||
break;
|
||||
case Item::FURNACE:
|
||||
$this->awardAchievement("buildFurnace");
|
||||
break;
|
||||
case Item::WOODEN_HOE:
|
||||
$this->awardAchievement("buildHoe");
|
||||
break;
|
||||
case Item::BREAD:
|
||||
$this->awardAchievement("makeBread");
|
||||
break;
|
||||
case Item::CAKE:
|
||||
//TODO: detect complex recipes like cake that leave remains
|
||||
$this->awardAchievement("bakeCake");
|
||||
$this->inventory->addItem(Item::get(Item::BUCKET, 0, 3));
|
||||
break;
|
||||
case Item::STONE_PICKAXE:
|
||||
case Item::GOLD_PICKAXE:
|
||||
case Item::IRON_PICKAXE:
|
||||
case Item::DIAMOND_PICKAXE:
|
||||
$this->awardAchievement("buildBetterPickaxe");
|
||||
break;
|
||||
case Item::WOODEN_SWORD:
|
||||
$this->awardAchievement("buildSword");
|
||||
break;
|
||||
case Item::DIAMOND:
|
||||
$this->awardAchievement("diamond");
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ProtocolInfo::CONTAINER_SET_SLOT_PACKET:
|
||||
@ -2761,7 +2788,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
TextFormat::clean($nbt["Text1"], $this->removeFormat), TextFormat::clean($nbt["Text2"], $this->removeFormat), TextFormat::clean($nbt["Text3"], $this->removeFormat), TextFormat::clean($nbt["Text4"], $this->removeFormat)
|
||||
]);
|
||||
|
||||
if(!isset($t->namedtag->Creator) or $t->namedtag["Creator"] !== $this->getUniqueId()){
|
||||
if(!isset($t->namedtag->Creator) or $t->namedtag["Creator"] !== $this->getRawUniqueId()){
|
||||
$ev->setCancelled();
|
||||
}else{
|
||||
foreach($ev->getLines() as $line){
|
||||
@ -2918,6 +2945,10 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
|
||||
$this->interface->close($this, $notify ? $reason : "");
|
||||
|
||||
if($this->loggedIn){
|
||||
$this->server->removeOnlinePlayer($this);
|
||||
}
|
||||
|
||||
$this->loggedIn = false;
|
||||
|
||||
if(isset($ev) and $this->username != "" and $this->spawned !== false and $ev->getQuitMessage() != ""){
|
||||
@ -3217,12 +3248,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
||||
}
|
||||
}
|
||||
|
||||
if($this->chunk !== null and $this->spawned){
|
||||
//TODO HACK: Minecraft: PE does not like moving a player from old chunks.
|
||||
//Player entities get stuck in unloaded chunks and the client does not accept position updates.
|
||||
$this->sendPosition($this, null, null, MovePlayerPacket::MODE_RESET, Network::CHANNEL_MOVEMENT, $reload);
|
||||
}
|
||||
|
||||
foreach($newChunk as $player){
|
||||
$this->spawnTo($player);
|
||||
}
|
||||
|
@ -53,6 +53,8 @@ use pocketmine\event\TranslationContainer;
|
||||
use pocketmine\inventory\CraftingManager;
|
||||
use pocketmine\inventory\InventoryType;
|
||||
use pocketmine\inventory\Recipe;
|
||||
use pocketmine\inventory\ShapedRecipe;
|
||||
use pocketmine\inventory\ShapelessRecipe;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\lang\BaseLang;
|
||||
use pocketmine\level\format\anvil\Anvil;
|
||||
@ -80,7 +82,9 @@ use pocketmine\nbt\tag\String;
|
||||
use pocketmine\network\CompressBatchedTask;
|
||||
use pocketmine\network\Network;
|
||||
use pocketmine\network\protocol\BatchPacket;
|
||||
use pocketmine\network\protocol\CraftingDataPacket;
|
||||
use pocketmine\network\protocol\DataPacket;
|
||||
use pocketmine\network\protocol\PlayerListPacket;
|
||||
use pocketmine\network\query\QueryHandler;
|
||||
use pocketmine\network\RakLibInterface;
|
||||
use pocketmine\network\rcon\RCON;
|
||||
@ -111,6 +115,7 @@ use pocketmine\utils\Terminal;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\TextWrapper;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\UUID;
|
||||
use pocketmine\utils\VersionString;
|
||||
|
||||
/**
|
||||
@ -249,6 +254,9 @@ class Server{
|
||||
/** @var Player[] */
|
||||
private $players = [];
|
||||
|
||||
/** @var Player[] */
|
||||
private $playerList = [];
|
||||
|
||||
private $identifiers = [];
|
||||
|
||||
/** @var Level[] */
|
||||
@ -705,7 +713,7 @@ class Server{
|
||||
* @return Player[]
|
||||
*/
|
||||
public function getOnlinePlayers(){
|
||||
return $this->players;
|
||||
return $this->playerList;
|
||||
}
|
||||
|
||||
public function addRecipe(Recipe $recipe){
|
||||
@ -2311,8 +2319,11 @@ class Server{
|
||||
|
||||
public function onPlayerLogin(Player $player){
|
||||
if($this->sendUsageTicker > 0){
|
||||
$this->uniquePlayers[$player->getUniqueId()] = $player->getUniqueId();
|
||||
$this->uniquePlayers[$player->getRawUniqueId()] = $player->getRawUniqueId();
|
||||
}
|
||||
|
||||
$this->sendFullPlayerListData($player);
|
||||
$this->sendRecipeList($player);
|
||||
}
|
||||
|
||||
public function addPlayer($identifier, Player $player){
|
||||
@ -2320,6 +2331,66 @@ class Server{
|
||||
$this->identifiers[spl_object_hash($player)] = $identifier;
|
||||
}
|
||||
|
||||
public function addOnlinePlayer(Player $player){
|
||||
$this->playerList[$player->getRawUniqueId()] = $player;
|
||||
|
||||
$this->updatePlayerListData($player->getUniqueId(), $player->getUniqueId(), $player->getDisplayName(), $player->isSkinSlim(), $player->getSkinData());
|
||||
}
|
||||
|
||||
public function removeOnlinePlayer(Player $player){
|
||||
if(isset($this->playerList[$player->getRawUniqueId()])){
|
||||
unset($this->playerList[$player->getRawUniqueId()]);
|
||||
|
||||
$pk = new PlayerListPacket();
|
||||
$pk->type = PlayerListPacket::TYPE_REMOVE;
|
||||
$pk->entries[] = [$player->getUniqueId()];
|
||||
Server::broadcastPacket($this->playerList, $pk->setChannel(Network::CHANNEL_ENTITY_SPAWNING));
|
||||
}
|
||||
}
|
||||
|
||||
public function updatePlayerListData(UUID $uuid, $entityId, $name, $isSlim, $skinData, array $players = null){
|
||||
$pk = new PlayerListPacket();
|
||||
$pk->type = PlayerListPacket::TYPE_ADD;
|
||||
$pk->entries[] = [$uuid, $entityId, $name, $isSlim, $skinData];
|
||||
Server::broadcastPacket($players === null ? $this->playerList : $players, $pk->setChannel(Network::CHANNEL_ENTITY_SPAWNING));
|
||||
}
|
||||
|
||||
public function removePlayerListData(UUID $uuid, array $players = null){
|
||||
$pk = new PlayerListPacket();
|
||||
$pk->type = PlayerListPacket::TYPE_REMOVE;
|
||||
$pk->entries[] = [$uuid];
|
||||
Server::broadcastPacket($players === null ? $this->playerList : $players, $pk->setChannel(Network::CHANNEL_ENTITY_SPAWNING));
|
||||
}
|
||||
|
||||
public function sendFullPlayerListData(Player $p){
|
||||
$pk = new PlayerListPacket();
|
||||
$pk->type = PlayerListPacket::TYPE_ADD;
|
||||
foreach($this->playerList as $player){
|
||||
$pk->entries[] = [$player->getUniqueId(), $player->getUniqueId(), $player->getDisplayName(), $player->isSkinSlim(), $player->getSkinData()];
|
||||
}
|
||||
|
||||
$p->dataPacket($pk->setChannel(Network::CHANNEL_ENTITY_SPAWNING));
|
||||
}
|
||||
|
||||
public function sendRecipeList(Player $p){
|
||||
$pk = new CraftingDataPacket();
|
||||
$pk->cleanRecipes = true;
|
||||
|
||||
foreach($this->getCraftingManager()->getRecipes() as $recipe){
|
||||
if($recipe instanceof ShapedRecipe){
|
||||
$pk->addShapedRecipe($recipe);
|
||||
}elseif($recipe instanceof ShapelessRecipe){
|
||||
$pk->addShapelessRecipe($recipe);
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->getCraftingManager()->getFurnaceRecipes() as $recipe){
|
||||
$pk->addFurnaceRecipe($recipe);
|
||||
}
|
||||
|
||||
$p->dataPacket($pk->setChannel(Network::CHANNEL_WORLD_EVENTS));
|
||||
}
|
||||
|
||||
private function checkTickUpdates($currentTick, $tickTime){
|
||||
foreach($this->players as $p){
|
||||
if(!$p->loggedIn and ($tickTime - $p->creationTime) >= 10){
|
||||
@ -2370,7 +2441,7 @@ class Server{
|
||||
public function doAutoSave(){
|
||||
if($this->getAutoSave()){
|
||||
Timings::$worldSaveTimer->startTiming();
|
||||
foreach($this->getOnlinePlayers() as $index => $player){
|
||||
foreach($this->players as $index => $player){
|
||||
if($player->isOnline()){
|
||||
$player->save(true);
|
||||
}elseif(!$player->isConnected()){
|
||||
|
@ -24,6 +24,7 @@ namespace pocketmine\entity;
|
||||
use pocketmine\inventory\InventoryHolder;
|
||||
use pocketmine\inventory\PlayerInventory;
|
||||
use pocketmine\item\Item as ItemItem;
|
||||
use pocketmine\utils\UUID;
|
||||
use pocketmine\nbt\NBT;
|
||||
use pocketmine\nbt\tag\Byte;
|
||||
use pocketmine\nbt\tag\Compound;
|
||||
@ -46,6 +47,11 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
/** @var PlayerInventory */
|
||||
protected $inventory;
|
||||
|
||||
|
||||
/** @var UUID */
|
||||
protected $uuid;
|
||||
protected $rawUUID;
|
||||
|
||||
public $width = 0.6;
|
||||
public $length = 0.6;
|
||||
public $height = 1.8;
|
||||
@ -62,6 +68,20 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
return $this->isSlim;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UUID|null
|
||||
*/
|
||||
public function getUniqueId(){
|
||||
return $this->uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRawUniqueId(){
|
||||
return $this->rawUUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @param bool $isSlim
|
||||
@ -94,6 +114,8 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
if(isset($this->namedtag->Skin) and $this->namedtag->Skin instanceof Compound){
|
||||
$this->setSkin($this->namedtag->Skin["Data"], $this->namedtag->Skin["Slim"] > 0);
|
||||
}
|
||||
|
||||
$this->uuid = UUID::fromData($this->getId(), $this->getSkinData(), $this->getNameTag());
|
||||
}
|
||||
|
||||
if(isset($this->namedtag->Inventory) and $this->namedtag->Inventory instanceof Enum){
|
||||
@ -198,8 +220,13 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set");
|
||||
}
|
||||
|
||||
|
||||
if(!($this instanceof Player)){
|
||||
$this->server->updatePlayerListData($this->getUniqueId(), $this->getId(), $this->getName(), $this->isSlim, $this->skin, $player);
|
||||
}
|
||||
|
||||
$pk = new AddPlayerPacket();
|
||||
$pk->clientID = $this->getId();
|
||||
$pk->uuid = $this->getUniqueId();
|
||||
$pk->username = $this->getName();
|
||||
$pk->eid = $this->getId();
|
||||
$pk->x = $this->x;
|
||||
@ -219,13 +246,18 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
||||
$player->dataPacket($pk->setChannel(Network::CHANNEL_ENTITY_SPAWNING));
|
||||
|
||||
$this->inventory->sendArmorContents($player);
|
||||
|
||||
if(!($this instanceof Player)){
|
||||
$this->server->removePlayerListData($this->getUniqueId(), $player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function despawnFrom(Player $player){
|
||||
if(isset($this->hasSpawned[$player->getLoaderId()])){
|
||||
|
||||
$pk = new RemovePlayerPacket();
|
||||
$pk->eid = $this->getId();
|
||||
$pk->eid = $this->getUniqueId();
|
||||
$pk->clientID = $this->getId();
|
||||
$player->dataPacket($pk->setChannel(Network::CHANNEL_ENTITY_SPAWNING));
|
||||
unset($this->hasSpawned[$player->getLoaderId()]);
|
||||
|
@ -26,6 +26,7 @@ use pocketmine\block\Stone;
|
||||
use pocketmine\block\Wood;
|
||||
use pocketmine\block\Wood2;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\utils\UUID;
|
||||
|
||||
class CraftingManager{
|
||||
|
||||
@ -38,6 +39,8 @@ class CraftingManager{
|
||||
/** @var FurnaceRecipe[] */
|
||||
public $furnaceRecipes = [];
|
||||
|
||||
private static $RECIPE_COUNT = 0;
|
||||
|
||||
public function __construct(){
|
||||
|
||||
$this->registerStonecutter();
|
||||
@ -519,6 +522,8 @@ class CraftingManager{
|
||||
}elseif($recipe instanceof FurnaceRecipe){
|
||||
$this->registerFurnaceRecipe($recipe);
|
||||
}
|
||||
|
||||
$recipe->setId(UUID::fromData(++self::$RECIPE_COUNT, $recipe->getResult()->getId(), $recipe->getResult()->getDamage(), $recipe->getResult()->getCount(), $recipe->getResult()->getCompoundTag()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,8 +23,12 @@ namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\UUID;
|
||||
|
||||
class FurnaceRecipe implements Recipe{
|
||||
|
||||
private $id = null;
|
||||
|
||||
/** @var Item */
|
||||
private $output;
|
||||
|
||||
@ -40,6 +44,18 @@ class FurnaceRecipe implements Recipe{
|
||||
$this->ingredient = clone $ingredient;
|
||||
}
|
||||
|
||||
public function getId(){
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(UUID $id){
|
||||
if($this->id !== null){
|
||||
throw new \InvalidStateException("Id is already set");
|
||||
}
|
||||
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Item $item
|
||||
*/
|
||||
|
@ -29,8 +29,8 @@ use pocketmine\item\Item;
|
||||
use pocketmine\network\Network;
|
||||
use pocketmine\network\protocol\ContainerSetContentPacket;
|
||||
use pocketmine\network\protocol\ContainerSetSlotPacket;
|
||||
use pocketmine\network\protocol\PlayerArmorEquipmentPacket;
|
||||
use pocketmine\network\protocol\PlayerEquipmentPacket;
|
||||
use pocketmine\network\protocol\MobArmorEquipmentPacket;
|
||||
use pocketmine\network\protocol\MobEquipmentPacket;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
|
||||
@ -126,7 +126,7 @@ class PlayerInventory extends BaseInventory{
|
||||
public function sendHeldItem($target){
|
||||
$item = $this->getItemInHand();
|
||||
|
||||
$pk = new PlayerEquipmentPacket();
|
||||
$pk = new MobEquipmentPacket();
|
||||
$pk->eid = ($target === $this->getHolder() ? 0 : $this->getHolder()->getId());
|
||||
$pk->item = $item->getId();
|
||||
$pk->meta = $item->getDamage();
|
||||
@ -315,7 +315,7 @@ class PlayerInventory extends BaseInventory{
|
||||
}
|
||||
}
|
||||
|
||||
$pk = new PlayerArmorEquipmentPacket();
|
||||
$pk = new MobArmorEquipmentPacket();
|
||||
$pk->eid = $this->getHolder()->getId();
|
||||
$pk->slots = $slots;
|
||||
$pk->encode();
|
||||
@ -372,7 +372,7 @@ class PlayerInventory extends BaseInventory{
|
||||
}
|
||||
}
|
||||
|
||||
$pk = new PlayerArmorEquipmentPacket();
|
||||
$pk = new MobArmorEquipmentPacket();
|
||||
$pk->eid = $this->getHolder()->getId();
|
||||
$pk->slots = $slots;
|
||||
$pk->encode();
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\utils\UUID;
|
||||
|
||||
interface Recipe{
|
||||
|
||||
/**
|
||||
@ -29,4 +31,9 @@ interface Recipe{
|
||||
public function getResult();
|
||||
|
||||
public function registerToCraftingManager();
|
||||
|
||||
/**
|
||||
* @return UUID
|
||||
*/
|
||||
public function getId();
|
||||
}
|
@ -23,11 +23,14 @@ namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\UUID;
|
||||
|
||||
class ShapedRecipe implements Recipe{
|
||||
/** @var Item */
|
||||
private $output;
|
||||
|
||||
private $id = null;
|
||||
|
||||
/** @var string[] */
|
||||
private $rows = [];
|
||||
|
||||
@ -61,6 +64,22 @@ class ShapedRecipe implements Recipe{
|
||||
$this->output = clone $result;
|
||||
}
|
||||
|
||||
public function getResult(){
|
||||
return $this->output;
|
||||
}
|
||||
|
||||
public function getId(){
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(UUID $id){
|
||||
if($this->id !== null){
|
||||
throw new \InvalidStateException("Id is already set");
|
||||
}
|
||||
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param Item $item
|
||||
|
@ -23,11 +23,14 @@ namespace pocketmine\inventory;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\UUID;
|
||||
|
||||
class ShapelessRecipe implements Recipe{
|
||||
/** @var Item */
|
||||
private $output;
|
||||
|
||||
private $id = null;
|
||||
|
||||
/** @var Item[] */
|
||||
private $ingredients = [];
|
||||
|
||||
@ -35,6 +38,18 @@ class ShapelessRecipe implements Recipe{
|
||||
$this->output = clone $result;
|
||||
}
|
||||
|
||||
public function getId(){
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(UUID $id){
|
||||
if($this->id !== null){
|
||||
throw new \InvalidStateException("Id is already set");
|
||||
}
|
||||
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function getResult(){
|
||||
return clone $this->output;
|
||||
}
|
||||
|
@ -1729,7 +1729,7 @@ class Level implements ChunkManager, Metadatable{
|
||||
"Text4" => new String("Text4", "")
|
||||
]));
|
||||
if($player !== null){
|
||||
$tile->namedtag->Creator = new String("Creator", $player->getUniqueId());
|
||||
$tile->namedtag->Creator = new String("Creator", $player->getRawUniqueId());
|
||||
}
|
||||
}
|
||||
$item->setCount($item->getCount() - 1);
|
||||
|
@ -36,6 +36,8 @@ use pocketmine\network\protocol\ContainerOpenPacket;
|
||||
use pocketmine\network\protocol\ContainerSetContentPacket;
|
||||
use pocketmine\network\protocol\ContainerSetDataPacket;
|
||||
use pocketmine\network\protocol\ContainerSetSlotPacket;
|
||||
use pocketmine\network\protocol\CraftingDataPacket;
|
||||
use pocketmine\network\protocol\CraftingEventPacket;
|
||||
use pocketmine\network\protocol\DataPacket;
|
||||
use pocketmine\network\protocol\DropItemPacket;
|
||||
use pocketmine\network\protocol\FullChunkDataPacket;
|
||||
@ -55,8 +57,8 @@ use pocketmine\network\protocol\TextPacket;
|
||||
use pocketmine\network\protocol\MoveEntityPacket;
|
||||
use pocketmine\network\protocol\MovePlayerPacket;
|
||||
use pocketmine\network\protocol\PlayerActionPacket;
|
||||
use pocketmine\network\protocol\PlayerArmorEquipmentPacket;
|
||||
use pocketmine\network\protocol\PlayerEquipmentPacket;
|
||||
use pocketmine\network\protocol\MobArmorEquipmentPacket;
|
||||
use pocketmine\network\protocol\MobEquipmentPacket;
|
||||
use pocketmine\network\protocol\RemoveBlockPacket;
|
||||
use pocketmine\network\protocol\RemoveEntityPacket;
|
||||
use pocketmine\network\protocol\RemovePlayerPacket;
|
||||
@ -72,6 +74,7 @@ use pocketmine\network\protocol\TakeItemEntityPacket;
|
||||
use pocketmine\network\protocol\TileEventPacket;
|
||||
use pocketmine\network\protocol\UpdateBlockPacket;
|
||||
use pocketmine\network\protocol\UseItemPacket;
|
||||
use pocketmine\network\protocol\PlayerListPacket;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\Binary;
|
||||
@ -296,6 +299,7 @@ class Network{
|
||||
$this->registerPacket(ProtocolInfo::LOGIN_PACKET, LoginPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::PLAY_STATUS_PACKET, PlayStatusPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::DISCONNECT_PACKET, DisconnectPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::BATCH_PACKET, BatchPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::TEXT_PACKET, TextPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::SET_TIME_PACKET, SetTimePacket::class);
|
||||
$this->registerPacket(ProtocolInfo::START_GAME_PACKET, StartGamePacket::class);
|
||||
@ -314,8 +318,8 @@ class Network{
|
||||
$this->registerPacket(ProtocolInfo::LEVEL_EVENT_PACKET, LevelEventPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::TILE_EVENT_PACKET, TileEventPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::ENTITY_EVENT_PACKET, EntityEventPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::PLAYER_EQUIPMENT_PACKET, PlayerEquipmentPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::PLAYER_ARMOR_EQUIPMENT_PACKET, PlayerArmorEquipmentPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::MOB_EQUIPMENT_PACKET, MobEquipmentPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET, MobArmorEquipmentPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::INTERACT_PACKET, InteractPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::USE_ITEM_PACKET, UseItemPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::PLAYER_ACTION_PACKET, PlayerActionPacket::class);
|
||||
@ -333,10 +337,12 @@ class Network{
|
||||
$this->registerPacket(ProtocolInfo::CONTAINER_SET_SLOT_PACKET, ContainerSetSlotPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::CONTAINER_SET_DATA_PACKET, ContainerSetDataPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::CONTAINER_SET_CONTENT_PACKET, ContainerSetContentPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::CRAFTING_DATA_PACKET, CraftingDataPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::CRAFTING_EVENT_PACKET, CraftingEventPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::ADVENTURE_SETTINGS_PACKET, AdventureSettingsPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::TILE_ENTITY_DATA_PACKET, TileEntityDataPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::FULL_CHUNK_DATA_PACKET, FullChunkDataPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::SET_DIFFICULTY_PACKET, SetDifficultyPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::BATCH_PACKET, BatchPacket::class);
|
||||
$this->registerPacket(ProtocolInfo::PLAYER_LIST_PACKET, PlayerListPacket::class);
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ use pocketmine\utils\Binary;
|
||||
class AddPlayerPacket extends DataPacket{
|
||||
const NETWORK_ID = Info::ADD_PLAYER_PACKET;
|
||||
|
||||
public $clientID;
|
||||
public $uuid;
|
||||
public $username;
|
||||
public $eid;
|
||||
public $x;
|
||||
@ -43,19 +43,15 @@ class AddPlayerPacket extends DataPacket{
|
||||
public $pitch;
|
||||
public $yaw;
|
||||
public $item;
|
||||
public $meta;
|
||||
public $metadata;
|
||||
|
||||
public $slim = false;
|
||||
public $skin = null;
|
||||
|
||||
public function decode(){
|
||||
|
||||
}
|
||||
|
||||
public function encode(){
|
||||
$this->reset();
|
||||
$this->putLong($this->clientID);
|
||||
$this->putUUID($this->uuid);
|
||||
$this->putString($this->username);
|
||||
$this->putLong($this->eid);
|
||||
$this->putFloat($this->x);
|
||||
@ -67,10 +63,8 @@ class AddPlayerPacket extends DataPacket{
|
||||
$this->putFloat($this->yaw);
|
||||
$this->putFloat($this->yaw); //TODO headrot
|
||||
$this->putFloat($this->pitch);
|
||||
$this->putShort($this->item);
|
||||
$this->putShort($this->meta);
|
||||
$this->putByte($this->slim ? 1 : 0);
|
||||
$this->putString($this->skin);
|
||||
$this->putSlot($this->item);
|
||||
|
||||
$meta = Binary::writeMetadata($this->metadata);
|
||||
$this->put($meta);
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ class ContainerSetContentPacket extends DataPacket{
|
||||
const SPECIAL_INVENTORY = 0;
|
||||
const SPECIAL_ARMOR = 0x78;
|
||||
const SPECIAL_CREATIVE = 0x79;
|
||||
const SPECIAL_CRAFTING = 0x7a;
|
||||
|
||||
public $windowid;
|
||||
public $slots = [];
|
||||
|
122
src/pocketmine/network/protocol/CraftingDataPacket.php
Normal file
122
src/pocketmine/network/protocol/CraftingDataPacket.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\network\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
|
||||
use pocketmine\inventory\FurnaceRecipe;
|
||||
use pocketmine\inventory\ShapedRecipe;
|
||||
use pocketmine\inventory\ShapelessRecipe;
|
||||
use pocketmine\utils\Binary;
|
||||
|
||||
class CraftingDataPacket extends DataPacket{
|
||||
const NETWORK_ID = Info::CRAFTING_DATA_PACKET;
|
||||
|
||||
const ENTRY_SHAPELESS = 0;
|
||||
const ENTRY_SHAPED = 1;
|
||||
const ENTRY_FURNACE = 2;
|
||||
const ENTRY_FURNACE_DATA = 3;
|
||||
const ENTRY_ENCHANT = 4;
|
||||
|
||||
/** @var object[] */
|
||||
public $entries = [];
|
||||
public $cleanRecipes = false;
|
||||
|
||||
public function writeEntry($entry){
|
||||
if($entry instanceof ShapelessRecipe){
|
||||
$this->writeShapelessRecipe($entry);
|
||||
}elseif($entry instanceof ShapedRecipe){
|
||||
$this->writeShapedRecipe($entry);
|
||||
}elseif($entry instanceof FurnaceRecipe){
|
||||
$this->writeFurnaceRecipe($entry);
|
||||
}
|
||||
}
|
||||
|
||||
private function writeShapelessRecipe(ShapelessRecipe $recipe){
|
||||
$this->putInt(CraftingDataPacket::ENTRY_SHAPELESS);
|
||||
|
||||
$this->putInt($recipe->getIngredientCount());
|
||||
foreach($recipe->getIngredientList() as $item){
|
||||
$this->putSlot($item);
|
||||
}
|
||||
|
||||
$this->putInt(1);
|
||||
$this->putSlot($recipe->getResult());
|
||||
}
|
||||
|
||||
private function writeShapedRecipe(ShapedRecipe $recipe){
|
||||
$this->putInt(CraftingDataPacket::ENTRY_SHAPED);
|
||||
}
|
||||
|
||||
private function writeFurnaceRecipe(FurnaceRecipe $recipe){
|
||||
if($recipe->getInput()->getDamage() !== 0){ //Data recipe
|
||||
$this->putInt(CraftingDataPacket::ENTRY_FURNACE_DATA);
|
||||
$this->putInt(($recipe->getInput()->getId() << 16) | ($recipe->getInput()->getDamage()));
|
||||
$this->putSlot($recipe->getResult());
|
||||
}else{
|
||||
$this->putInt(CraftingDataPacket::ENTRY_FURNACE);
|
||||
$this->putInt($recipe->getInput()->getId());
|
||||
$this->putSlot($recipe->getResult());
|
||||
}
|
||||
}
|
||||
|
||||
private function writeEnchant(){
|
||||
$entry = Binary::writeInt(CraftingDataPacket::ENTRY_ENCHANT);
|
||||
//TODO
|
||||
}
|
||||
|
||||
public function addShapelessRecipe(ShapelessRecipe $recipe){
|
||||
$this->entries[] = $recipe;
|
||||
}
|
||||
|
||||
public function addShapedRecipe(ShapedRecipe $recipe){
|
||||
$this->entries[] = $recipe;
|
||||
}
|
||||
|
||||
public function addFurnaceRecipe(FurnaceRecipe $recipe){
|
||||
$this->entries[] = $recipe;
|
||||
}
|
||||
|
||||
public function addEnchant(){
|
||||
//TODO
|
||||
}
|
||||
|
||||
public function clean(){
|
||||
$this->entries = [];
|
||||
return parent::clean();
|
||||
}
|
||||
|
||||
public function decode(){
|
||||
|
||||
}
|
||||
|
||||
public function encode(){
|
||||
$this->reset();
|
||||
$this->putByte($this->type);
|
||||
$this->putInt(count($this->entries));
|
||||
foreach($this->entries as $d){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
62
src/pocketmine/network/protocol/CraftingEventPacket.php
Normal file
62
src/pocketmine/network/protocol/CraftingEventPacket.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\network\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
|
||||
class CraftingEventPacket extends DataPacket{
|
||||
const NETWORK_ID = Info::CRAFTING_EVENT_PACKET;
|
||||
|
||||
public $windowId;
|
||||
public $type;
|
||||
public $id;
|
||||
public $input = [];
|
||||
public $output = [];
|
||||
|
||||
public function clean(){
|
||||
$this->input = [];
|
||||
$this->output = [];
|
||||
return parent::clean();
|
||||
}
|
||||
|
||||
public function decode(){
|
||||
$this->windowId = $this->getByte();
|
||||
$this->type = $this->getInt();
|
||||
$this->id = $this->getUUID();
|
||||
|
||||
$size = $this->getInt();
|
||||
for($i = 0; $i < $size and $i < 128; ++$i){
|
||||
$this->input[] = $this->getSlot();
|
||||
}
|
||||
|
||||
$size = $this->getInt();
|
||||
for($i = 0; $i < $size and $i < 128; ++$i){
|
||||
$this->output[] = $this->getSlot();
|
||||
}
|
||||
}
|
||||
|
||||
public function encode(){
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -28,6 +28,7 @@ use pocketmine\utils\Binary;
|
||||
#endif
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\utils\UUID;
|
||||
|
||||
|
||||
abstract class DataPacket extends \stdClass{
|
||||
@ -162,10 +163,18 @@ abstract class DataPacket extends \stdClass{
|
||||
}
|
||||
}
|
||||
|
||||
protected function getUUID(){
|
||||
return UUID::fromBinary($this->get(16));
|
||||
}
|
||||
|
||||
protected function putUUID(UUID $uuid){
|
||||
$this->put($uuid->toBinary());
|
||||
}
|
||||
|
||||
protected function getSlot(){
|
||||
$id = $this->getShort(false);
|
||||
$id = $this->getShort(true);
|
||||
|
||||
if($id == 0xffff){
|
||||
if($id <= 0){
|
||||
return Item::get(0, 0, 0);
|
||||
}
|
||||
|
||||
@ -191,7 +200,7 @@ abstract class DataPacket extends \stdClass{
|
||||
|
||||
protected function putSlot(Item $item){
|
||||
if($item->getId() === 0){
|
||||
$this->putShort(0xffff);
|
||||
$this->putShort(0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,8 @@ class EntityEventPacket extends DataPacket{
|
||||
const AMBIENT_SOUND = 16;
|
||||
const RESPAWN = 17;
|
||||
|
||||
//TODO add new events
|
||||
|
||||
public $eid;
|
||||
public $event;
|
||||
|
||||
|
@ -30,7 +30,7 @@ interface Info{
|
||||
/**
|
||||
* Actual Minecraft: PE protocol version
|
||||
*/
|
||||
const CURRENT_PROTOCOL = 28;
|
||||
const CURRENT_PROTOCOL = 30;
|
||||
|
||||
const LOGIN_PACKET = 0x82;
|
||||
const PLAY_STATUS_PACKET = 0x83;
|
||||
@ -56,8 +56,8 @@ interface Info{
|
||||
const ENTITY_EVENT_PACKET = 0x97;
|
||||
const MOB_EFFECT_PACKET = 0x98;
|
||||
const UPDATE_ATTRIBUTES_PACKET = 0x99;
|
||||
const PLAYER_EQUIPMENT_PACKET = 0x9a;
|
||||
const PLAYER_ARMOR_EQUIPMENT_PACKET = 0x9b;
|
||||
const MOB_EQUIPMENT_PACKET = 0x9a;
|
||||
const MOB_ARMOR_EQUIPMENT_PACKET = 0x9b;
|
||||
const INTERACT_PACKET = 0x9c;
|
||||
const USE_ITEM_PACKET = 0x9d;
|
||||
const PLAYER_ACTION_PACKET = 0x9e;
|
||||
@ -75,14 +75,17 @@ interface Info{
|
||||
const CONTAINER_SET_SLOT_PACKET = 0xaa;
|
||||
const CONTAINER_SET_DATA_PACKET = 0xab;
|
||||
const CONTAINER_SET_CONTENT_PACKET = 0xac;
|
||||
const ADVENTURE_SETTINGS_PACKET = 0xad;
|
||||
const TILE_ENTITY_DATA_PACKET = 0xae;
|
||||
//const PLAYER_INPUT_PACKET = 0xaf;
|
||||
const FULL_CHUNK_DATA_PACKET = 0xb0;
|
||||
const SET_DIFFICULTY_PACKET = 0xb1;
|
||||
//const CHANGE_DIMENSION_PACKET = 0xb2;
|
||||
//const SET_PLAYER_GAMETYPE_PACKET = 0xb3;
|
||||
//const PLAYER_LIST_PACKET = 0xb4;
|
||||
const CRAFTING_DATA_PACKET = 0xad;
|
||||
const CRAFTING_EVENT_PACKET = 0xae;
|
||||
const ADVENTURE_SETTINGS_PACKET = 0xaf;
|
||||
const TILE_ENTITY_DATA_PACKET = 0xb0;
|
||||
//const PLAYER_INPUT_PACKET = 0xb1;
|
||||
const FULL_CHUNK_DATA_PACKET = 0xb2;
|
||||
const SET_DIFFICULTY_PACKET = 0xb3;
|
||||
//const CHANGE_DIMENSION_PACKET = 0xb4;
|
||||
//const SET_PLAYER_GAMETYPE_PACKET = 0xb5;
|
||||
const PLAYER_LIST_PACKET = 0xb6;
|
||||
//const TELEMETRY_EVENT_PACKET = 0xb7;
|
||||
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,10 @@ class LoginPacket extends DataPacket{
|
||||
public $protocol2;
|
||||
public $clientId;
|
||||
|
||||
public $clientUUID;
|
||||
public $serverAddress;
|
||||
public $clientSecret;
|
||||
|
||||
public $slim = false;
|
||||
public $skin = null;
|
||||
|
||||
@ -39,11 +43,15 @@ class LoginPacket extends DataPacket{
|
||||
$this->username = $this->getString();
|
||||
$this->protocol1 = $this->getInt();
|
||||
$this->protocol2 = $this->getInt();
|
||||
if($this->protocol1 < 22){ //New fields!
|
||||
if($this->protocol1 < Info::CURRENT_PROTOCOL){ //New fields!
|
||||
$this->setBuffer(null, 0); //Skip batch packet handling
|
||||
return;
|
||||
}
|
||||
$this->clientId = $this->getLong();
|
||||
$this->clientUUID = $this->getUUID();
|
||||
$this->serverAddress = $this->getString();
|
||||
$this->clientSecret = $this->getString();
|
||||
|
||||
$this->slim = $this->getByte() > 0;
|
||||
$this->skin = $this->getString();
|
||||
}
|
||||
|
@ -24,27 +24,27 @@ namespace pocketmine\network\protocol;
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
|
||||
class PlayerArmorEquipmentPacket extends DataPacket{
|
||||
const NETWORK_ID = Info::PLAYER_ARMOR_EQUIPMENT_PACKET;
|
||||
class MobArmorEquipmentPacket extends DataPacket{
|
||||
const NETWORK_ID = Info::MOB_ARMOR_EQUIPMENT_PACKET;
|
||||
|
||||
public $eid;
|
||||
public $slots = [];
|
||||
|
||||
public function decode(){
|
||||
$this->eid = $this->getLong();
|
||||
$this->slots[0] = $this->getByte();
|
||||
$this->slots[1] = $this->getByte();
|
||||
$this->slots[2] = $this->getByte();
|
||||
$this->slots[3] = $this->getByte();
|
||||
$this->slots[0] = $this->getSlot();
|
||||
$this->slots[1] = $this->getSlot();
|
||||
$this->slots[2] = $this->getSlot();
|
||||
$this->slots[3] = $this->getSlot();
|
||||
}
|
||||
|
||||
public function encode(){
|
||||
$this->reset();
|
||||
$this->putLong($this->eid);
|
||||
$this->putByte($this->slots[0]);
|
||||
$this->putByte($this->slots[1]);
|
||||
$this->putByte($this->slots[2]);
|
||||
$this->putByte($this->slots[3]);
|
||||
$this->putSlot($this->slots[0]);
|
||||
$this->putSlot($this->slots[1]);
|
||||
$this->putSlot($this->slots[2]);
|
||||
$this->putSlot($this->slots[3]);
|
||||
}
|
||||
|
||||
}
|
@ -24,19 +24,17 @@ namespace pocketmine\network\protocol;
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
|
||||
class PlayerEquipmentPacket extends DataPacket{
|
||||
const NETWORK_ID = Info::PLAYER_EQUIPMENT_PACKET;
|
||||
class MobEquipmentPacket extends DataPacket{
|
||||
const NETWORK_ID = Info::MOB_EQUIPMENT_PACKET;
|
||||
|
||||
public $eid;
|
||||
public $item;
|
||||
public $meta;
|
||||
public $slot;
|
||||
public $selectedSlot;
|
||||
|
||||
public function decode(){
|
||||
$this->eid = $this->getLong();
|
||||
$this->item = $this->getShort();
|
||||
$this->meta = $this->getShort();
|
||||
$this->item = $this->getSlot();
|
||||
$this->slot = $this->getByte();
|
||||
$this->selectedSlot = $this->getByte();
|
||||
}
|
||||
@ -44,8 +42,7 @@ class PlayerEquipmentPacket extends DataPacket{
|
||||
public function encode(){
|
||||
$this->reset();
|
||||
$this->putLong($this->eid);
|
||||
$this->putShort($this->item);
|
||||
$this->putShort($this->meta);
|
||||
$this->putSlot($this->item);
|
||||
$this->putByte($this->slot);
|
||||
$this->putByte($this->selectedSlot);
|
||||
}
|
64
src/pocketmine/network/protocol/PlayerListPacket.php
Normal file
64
src/pocketmine/network/protocol/PlayerListPacket.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\network\protocol;
|
||||
|
||||
#include <rules/DataPacket.h>
|
||||
|
||||
|
||||
class PlayerListPacket extends DataPacket{
|
||||
const NETWORK_ID = Info::PLAYER_LIST_PACKET;
|
||||
|
||||
const TYPE_ADD = 0;
|
||||
const TYPE_REMOVE = 1;
|
||||
|
||||
//REMOVE: UUID, ADD: UUID, entity id, name, isSlim, skin
|
||||
/** @var array[] */
|
||||
public $entries = [];
|
||||
public $type;
|
||||
|
||||
public function clean(){
|
||||
$this->entries = [];
|
||||
return parent::clean();
|
||||
}
|
||||
|
||||
public function decode(){
|
||||
|
||||
}
|
||||
|
||||
public function encode(){
|
||||
$this->reset();
|
||||
$this->putByte($this->type);
|
||||
$this->putInt(count($this->entries));
|
||||
foreach($this->entries as $d){
|
||||
if($this->type === self::TYPE_ADD){
|
||||
$this->putUUID($d[0]);
|
||||
$this->putLong($d[1]);
|
||||
$this->putString($d[2]);
|
||||
$this->putByte($d[3] ? 1 : 0);
|
||||
$this->putString($d[4]);
|
||||
}else{
|
||||
$this->putUUID($d[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -28,7 +28,7 @@ class RemovePlayerPacket extends DataPacket{
|
||||
const NETWORK_ID = Info::REMOVE_PLAYER_PACKET;
|
||||
|
||||
public $eid;
|
||||
public $clientID;
|
||||
public $clientId;
|
||||
|
||||
public function decode(){
|
||||
|
||||
@ -37,7 +37,7 @@ class RemovePlayerPacket extends DataPacket{
|
||||
public function encode(){
|
||||
$this->reset();
|
||||
$this->putLong($this->eid);
|
||||
$this->putLong($this->clientID);
|
||||
$this->putUUID($this->clientId);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -101,13 +101,13 @@ class SendUsageTask extends AsyncTask{
|
||||
|
||||
//This anonymizes the user ids so they cannot be reversed to the original
|
||||
foreach($playerList as $k => $v){
|
||||
$playerList[$k] = Utils::dataToUUID($v);
|
||||
$playerList[$k] = md5($v);
|
||||
}
|
||||
|
||||
$players = [];
|
||||
foreach($server->getOnlinePlayers() as $p){
|
||||
if($p->isOnline()){
|
||||
$players[] = Utils::dataToUUID($p->getUniqueId());
|
||||
$players[] = md5($p->getUniqueId()->toBinary());
|
||||
}
|
||||
}
|
||||
|
||||
|
105
src/pocketmine/utils/UUID.php
Normal file
105
src/pocketmine/utils/UUID.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\utils;
|
||||
|
||||
class UUID{
|
||||
|
||||
private $parts = [0, 0, 0, 0];
|
||||
private $version = null;
|
||||
|
||||
public function __construct($part1 = 0, $part2 = 0, $part3 = 0, $part4 = 0, $version = null){
|
||||
$this->parts[0] = (int) $part1;
|
||||
$this->parts[1] = (int) $part2;
|
||||
$this->parts[2] = (int) $part3;
|
||||
$this->parts[3] = (int) $part4;
|
||||
|
||||
$this->version = $version === null ? ($this->parts[1] & 0xf000) >> 12 : (int) $version;
|
||||
}
|
||||
|
||||
public function getVersion(){
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
public function equals(UUID $uuid){
|
||||
return $uuid->parts[0] === $this->parts[0] and $uuid->parts[1] === $this->parts[1] and $uuid->parts[2] === $this->parts[2] and $uuid->parts[3] === $this->parts[3];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an UUID from an hexadecimal representation
|
||||
*
|
||||
* @param string $uuid
|
||||
* @param int $version
|
||||
* @return UUID
|
||||
*/
|
||||
public static function fromString($uuid, $version = null){
|
||||
return self::fromBinary(hex2bin(str_replace("-", "", trim($uuid))), $version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an UUID from a binary representation
|
||||
*
|
||||
* @param string $uuid
|
||||
* @param int $version
|
||||
* @return UUID
|
||||
*/
|
||||
public static function fromBinary($uuid, $version = null){
|
||||
if(strlen($uuid) !== 16){
|
||||
throw new \InvalidArgumentException("Must have exactly 16 bytes");
|
||||
}
|
||||
|
||||
return new UUID(Binary::readInt(substr($uuid, 0, 4)), Binary::readInt(substr($uuid, 4, 4)), Binary::readInt(substr($uuid, 8, 4)), Binary::readInt(substr($uuid, 12, 4)), $version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an UUIDv3 from binary data or list of binary data
|
||||
*
|
||||
* @param string ...$data
|
||||
* @return UUID
|
||||
*/
|
||||
public static function fromData(...$data){
|
||||
$hash = hash("md5", implode($data), true);
|
||||
|
||||
return self::fromBinary($hash, 3);
|
||||
}
|
||||
|
||||
public static function fromRandom(){
|
||||
return self::fromData(Binary::writeInt(time()), Binary::writeShort(getmypid()), Binary::writeShort(getmyuid()), Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)), Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)));
|
||||
}
|
||||
|
||||
public function toBinary(){
|
||||
return Binary::writeInt($this->parts[0]) . Binary::writeInt($this->parts[1]) . Binary::writeInt($this->parts[2]) . Binary::writeInt($this->parts[3]);
|
||||
}
|
||||
|
||||
public function toString(){
|
||||
$hex = bin2hex(self::toBinary());
|
||||
|
||||
//xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx 8-4-4-12
|
||||
if($this->version !== null){
|
||||
return substr($hex, 0, 8) . "-" . substr($hex, 8, 4) . "-" . hexdec($this->version) . substr($hex, 13, 3) . "-8" . substr($hex, 17, 3) . "-" . substr($hex, 20, 12);
|
||||
}
|
||||
return substr($hex, 0, 8) . "-" . substr($hex, 8, 4) . "-" . substr($hex, 12, 4) . "-" . substr($hex, 16, 4) . "-" . substr($hex, 20, 12);
|
||||
}
|
||||
|
||||
public function __toString(){
|
||||
return $this->toString();
|
||||
}
|
||||
}
|
@ -49,14 +49,23 @@ class Utils{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public static function randomUUID(){
|
||||
return Utils::toUUID(Binary::writeInt(time()) . Binary::writeShort(getmypid()) . Binary::writeShort(getmyuid()) . Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)) . Binary::writeInt(mt_rand(-0x7fffffff, 0x7fffffff)), 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public static function dataToUUID(...$params){
|
||||
return Utils::toUUID(hash("md5", implode($params), true), 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public static function toUUID($data, $version = 2, $fixed = "8"){
|
||||
if(strlen($data) !== 16){
|
||||
throw new \InvalidArgumentException("Data must be 16 bytes");
|
||||
@ -76,7 +85,7 @@ class Utils{
|
||||
*
|
||||
* @param string $extra optional, additional data to identify the machine
|
||||
*
|
||||
* @return string
|
||||
* @return UUID
|
||||
*/
|
||||
public static function getMachineUniqueId($extra = ""){
|
||||
if(self::$serverUniqueId !== null and $extra === ""){
|
||||
@ -127,7 +136,7 @@ class Utils{
|
||||
$data .= $ext . ":" . phpversion($ext);
|
||||
}
|
||||
|
||||
$uuid = Utils::dataToUUID($machine, $data);
|
||||
$uuid = UUID::fromData($machine, $data);
|
||||
|
||||
if($extra === ""){
|
||||
self::$serverUniqueId = $uuid;
|
||||
|
Loading…
x
Reference in New Issue
Block a user