mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-07 12:18:46 +00:00
Implemented RakLib
This commit is contained in:
parent
cce9499a61
commit
99a0117a33
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -1,8 +1,8 @@
|
||||
[submodule "src/pocketmine/gui"]
|
||||
path = src/pocketmine/gui
|
||||
url = git://github.com/PocketMine/PocketMine-MP-GUI.git
|
||||
url = https://github.com/PocketMine/PocketMine-MP-GUI.git
|
||||
branch = master
|
||||
[submodule "src/raklib"]
|
||||
path = src/raklib
|
||||
url = git://github.com/PocketMine/RakLib.git
|
||||
url = https://github.com/PocketMine/RakLib.git
|
||||
branch = master
|
||||
|
@ -74,6 +74,7 @@ use pocketmine\network\protocol\UnknownPacket;
|
||||
use pocketmine\network\protocol\UpdateBlockPacket;
|
||||
use pocketmine\network\raknet\Info;
|
||||
use pocketmine\network\raknet\Packet;
|
||||
use pocketmine\network\SourceInterface;
|
||||
use pocketmine\permission\PermissibleBase;
|
||||
use pocketmine\permission\PermissionAttachment;
|
||||
use pocketmine\plugin\Plugin;
|
||||
@ -100,8 +101,9 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
const SURVIVAL_SLOTS = 36;
|
||||
const CREATIVE_SLOTS = 112;
|
||||
|
||||
public $CID;
|
||||
public $MTU;
|
||||
/** @var SourceInterface */
|
||||
protected $interface;
|
||||
|
||||
public $spawned = false;
|
||||
public $loggedIn = false;
|
||||
public $gamemode;
|
||||
@ -113,6 +115,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
/** @var Inventory[] */
|
||||
protected $windowIndex = [];
|
||||
|
||||
protected $sendIndex = 0;
|
||||
|
||||
public $blocked = true;
|
||||
public $achievements = [];
|
||||
public $chunksLoaded = [];
|
||||
@ -137,32 +141,13 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
protected $chunksOrder = [];
|
||||
/** @var Player[] */
|
||||
protected $hiddenPlayers = [];
|
||||
private $recoveryQueue = [];
|
||||
private $receiveQueue = [];
|
||||
private $resendQueue = [];
|
||||
private $ackQueue = [];
|
||||
private $receiveCount = -1;
|
||||
/** @var \pocketmine\network\raknet\Packet */
|
||||
private $buffer;
|
||||
private $bufferLen = 0;
|
||||
private $nextBuffer = 0;
|
||||
private $timeout;
|
||||
private $counter = array(0, 0, 0, 0);
|
||||
|
||||
private $viewDistance;
|
||||
private $lastMeasure = 0;
|
||||
private $bandwidthRaw = 0;
|
||||
private $bandwidthStats = array(0, 0, 0);
|
||||
private $lag = [];
|
||||
private $lagStat = 0;
|
||||
private $spawnPosition;
|
||||
private $packetLoss = 0;
|
||||
|
||||
private $lastChunk = false;
|
||||
private $chunkScheduled = 0;
|
||||
private $inAction = false;
|
||||
private $bigCnt;
|
||||
private $packetStats;
|
||||
private $chunkCount = [];
|
||||
private $received = [];
|
||||
|
||||
/**
|
||||
* @var \pocketmine\scheduler\TaskHandler[]
|
||||
@ -213,7 +198,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
}
|
||||
|
||||
protected function initEntity(){
|
||||
$this->getLevel()->players[$this->CID] = $this;
|
||||
$this->getLevel()->players[spl_object_hash($this)] = $this;
|
||||
parent::initEntity();
|
||||
}
|
||||
|
||||
@ -363,21 +348,19 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
|
||||
|
||||
/**
|
||||
* @param integer $clientID
|
||||
* @param string $ip
|
||||
* @param integer $port
|
||||
* @param integer $MTU
|
||||
* @param SourceInterface $interface
|
||||
* @param integer $clientID
|
||||
* @param string $ip
|
||||
* @param integer $port
|
||||
*/
|
||||
public function __construct($clientID, $ip, $port, $MTU){
|
||||
public function __construct(SourceInterface $interface, $clientID, $ip, $port){
|
||||
$this->interface = $interface;
|
||||
$this->windows = new \SplObjectStorage();
|
||||
$this->perm = new PermissibleBase($this);
|
||||
$this->namedtag = new Compound();
|
||||
$this->bigCnt = 0;
|
||||
$this->MTU = $MTU;
|
||||
$this->server = Server::getInstance();
|
||||
$this->lastBreak = microtime(true);
|
||||
$this->clientID = $clientID;
|
||||
$this->CID = $ip . ":" . $port;
|
||||
$this->ip = $ip;
|
||||
$this->port = $port;
|
||||
$this->spawnPosition = $this->server->getDefaultLevel()->getSafeSpawn();
|
||||
@ -387,13 +370,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
$this->viewDistance = $this->server->getViewDistance();
|
||||
$this->slot = 0;
|
||||
$this->hotbar = array(0, -1, -1, -1, -1, -1, -1, -1, -1);
|
||||
$this->packetStats = array(0, 0);
|
||||
$this->buffer = new Packet(Info::DATA_PACKET_0);
|
||||
$this->buffer->data = [];
|
||||
$this->tasks[] = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "handlePacketQueues")), 1);
|
||||
$this->tasks[] = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "clearQueue")), 20 * 60);
|
||||
|
||||
$this->server->getLogger()->debug("New Session started with " . $ip . ":" . $port . ". MTU " . $this->MTU . ", Client ID " . $this->clientID);
|
||||
$this->server->getLogger()->debug("New Session started with " . $ip . ":" . $port . ", Client ID " . $this->clientID);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -515,19 +493,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->chunkCount as $count => $t){
|
||||
if(isset($this->recoveryQueue[$count]) or isset($this->resendQueue[$count])){
|
||||
if($this->chunkScheduled === 0){
|
||||
$this->server->getScheduler()->scheduleDelayedTask(new CallbackTask(array($this, "getNextChunk"), array(false, true)), MAX_CHUNK_RATE);
|
||||
++$this->chunkScheduled;
|
||||
}
|
||||
|
||||
return;
|
||||
}else{
|
||||
unset($this->chunkCount[$count]);
|
||||
}
|
||||
}
|
||||
|
||||
if(is_array($this->lastChunk)){
|
||||
foreach($this->getLevel()->getChunkEntities($this->lastChunk[0], $this->lastChunk[1]) as $entity){
|
||||
if($entity !== $this){
|
||||
@ -578,10 +543,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
if($cnt === false){
|
||||
return false;
|
||||
}
|
||||
$this->chunkCount = [];
|
||||
foreach($cnt as $count){
|
||||
$this->chunkCount[$count] = true;
|
||||
}
|
||||
|
||||
$this->lastChunk = array($X, $Z);
|
||||
|
||||
@ -669,95 +630,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
return false;
|
||||
}
|
||||
|
||||
$packet->encode();
|
||||
$len = strlen($packet->buffer) + 1;
|
||||
$MTU = $this->MTU - 24;
|
||||
if($len > $MTU){
|
||||
return $this->directBigRawPacket($packet);
|
||||
}
|
||||
|
||||
if(($this->bufferLen + $len) >= $MTU){
|
||||
$this->sendBuffer();
|
||||
}
|
||||
|
||||
$packet->messageIndex = $this->counter[3]++;
|
||||
$packet->reliability = 2;
|
||||
@$this->buffer->data[] = $packet;
|
||||
$this->bufferLen += 6 + $len;
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private function directBigRawPacket(DataPacket $packet){
|
||||
if($this->connected === false){
|
||||
return false;
|
||||
}
|
||||
|
||||
$sendtime = microtime(true);
|
||||
|
||||
$size = $this->MTU - 34;
|
||||
$buffer = str_split($packet->buffer, $size);
|
||||
$bigCnt = $this->bigCnt;
|
||||
$this->bigCnt = ($this->bigCnt + 1) % 0x10000;
|
||||
$cnts = [];
|
||||
$bufCount = count($buffer);
|
||||
foreach($buffer as $i => $buf){
|
||||
$cnts[] = $count = $this->counter[0]++;
|
||||
|
||||
$pk = new UnknownPacket;
|
||||
$pk->packetID = $packet->pid();
|
||||
$pk->reliability = 2;
|
||||
$pk->hasSplit = true;
|
||||
$pk->splitCount = $bufCount;
|
||||
$pk->splitID = $bigCnt;
|
||||
$pk->splitIndex = $i;
|
||||
$pk->buffer = $buf;
|
||||
$pk->messageIndex = $this->counter[3]++;
|
||||
|
||||
$rk = new Packet(Info::DATA_PACKET_0);
|
||||
$rk->data[] = $pk;
|
||||
$rk->seqNumber = $count;
|
||||
$rk->sendtime = $sendtime;
|
||||
$this->recoveryQueue[$count] = $rk;
|
||||
$this->send($rk);
|
||||
}
|
||||
|
||||
return $cnts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a raw Packet to the conection
|
||||
*
|
||||
* WARNING: Do not use this, it's only for internal use.
|
||||
* Changes to this function won't be recorded on the version.
|
||||
*
|
||||
* @param Packet $packet
|
||||
*/
|
||||
public function send(Packet $packet){
|
||||
if($this->connected === true){
|
||||
$packet->ip = $this->ip;
|
||||
$packet->port = $this->port;
|
||||
$this->bandwidthRaw += $this->server->sendPacket($packet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces sending the buffer
|
||||
*
|
||||
* WARNING: Do not use this, it's only for internal use.
|
||||
* Changes to this function won't be recorded on the version.
|
||||
*/
|
||||
public function sendBuffer(){
|
||||
if($this->connected === true){
|
||||
if($this->bufferLen > 0 and $this->buffer instanceof Packet){
|
||||
$this->buffer->seqNumber = $this->counter[0]++;
|
||||
$this->send($this->buffer);
|
||||
}
|
||||
$this->bufferLen = 0;
|
||||
$this->buffer = new Packet(Info::DATA_PACKET_0);
|
||||
$this->buffer->data = [];
|
||||
$this->nextBuffer = microtime(true) + 0.1;
|
||||
}
|
||||
$this->interface->putPacket($this, $packet);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1032,40 +905,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
$this->dataPacket($pk);
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: Do not use this, it's only for internal use.
|
||||
* Changes to this function won't be recorded on the version.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function measureLag(){
|
||||
if($this->connected === false){
|
||||
return false;
|
||||
}
|
||||
if($this->packetStats[1] > 2){
|
||||
$this->packetLoss = $this->packetStats[1] / max(1, $this->packetStats[0] + $this->packetStats[1]);
|
||||
}else{
|
||||
$this->packetLoss = 0;
|
||||
}
|
||||
$this->packetStats = array(0, 0);
|
||||
array_shift($this->bandwidthStats);
|
||||
$this->bandwidthStats[] = $this->bandwidthRaw / max(0.00001, microtime(true) - $this->lastMeasure);
|
||||
$this->bandwidthRaw = 0;
|
||||
$this->lagStat = array_sum($this->lag) / max(1, count($this->lag));
|
||||
$this->lag = [];
|
||||
$this->sendBuffer();
|
||||
$this->lastMeasure = microtime(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: Experimental method
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getLag(){
|
||||
return $this->lagStat * 1000;
|
||||
}
|
||||
|
||||
protected function getCreativeBlock(Item $item){
|
||||
foreach(Block::$creative as $i => $d){
|
||||
if($d[0] === $item->getID() and $d[1] === $item->getDamage()){
|
||||
@ -1075,139 +914,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: Experimental method
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPacketLoss(){
|
||||
return $this->packetLoss;
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: Experimental method
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getBandwidth(){
|
||||
return array_sum($this->bandwidthStats) / max(1, count($this->bandwidthStats));
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: Do not use this, it's only for internal use.
|
||||
* Changes to this function won't be recorded on the version.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function clearQueue(){
|
||||
if($this->connected === false){
|
||||
return false;
|
||||
}
|
||||
ksort($this->received);
|
||||
if(($cnt = count($this->received)) > self::MAX_QUEUE){
|
||||
foreach($this->received as $c => $t){
|
||||
unset($this->received[$c]);
|
||||
--$cnt;
|
||||
if($cnt <= self::MAX_QUEUE){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: Do not use this, it's only for internal use.
|
||||
* Changes to this function won't be recorded on the version.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handlePacketQueues(){
|
||||
if($this->connected === false){
|
||||
return false;
|
||||
}
|
||||
$time = microtime(true);
|
||||
if($time > $this->timeout){
|
||||
$this->close($this->username . " has left the game", "timeout");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if(($ackCnt = count($this->ackQueue)) > 0){
|
||||
rsort($this->ackQueue);
|
||||
$safeCount = (int) (($this->MTU - 1) / 4);
|
||||
$packetCnt = (int) ($ackCnt / $safeCount + 1);
|
||||
for($p = 0; $p < $packetCnt; ++$p){
|
||||
$pk = new Packet(Info::ACK);
|
||||
$pk->packets = [];
|
||||
for($c = 0; $c < $safeCount; ++$c){
|
||||
if(($k = array_pop($this->ackQueue)) === null){
|
||||
break;
|
||||
}
|
||||
$pk->packets[] = $k;
|
||||
}
|
||||
$this->send($pk);
|
||||
}
|
||||
$this->ackQueue = [];
|
||||
}
|
||||
|
||||
if(($receiveCnt = count($this->receiveQueue)) > 0){
|
||||
ksort($this->receiveQueue);
|
||||
foreach($this->receiveQueue as $count => $packets){
|
||||
unset($this->receiveQueue[$count]);
|
||||
foreach($packets as $p){
|
||||
if($p instanceof DataPacket and $p->hasSplit === false){
|
||||
if(isset($p->messageIndex) and $p->messageIndex !== false){
|
||||
if($p->messageIndex > $this->receiveCount){
|
||||
$this->receiveCount = $p->messageIndex;
|
||||
}elseif($p->messageIndex !== 0){
|
||||
if(isset($this->received[$p->messageIndex])){
|
||||
continue;
|
||||
}
|
||||
switch($p->pid()){
|
||||
case 0x01:
|
||||
case ProtocolInfo::PING_PACKET:
|
||||
case ProtocolInfo::PONG_PACKET:
|
||||
case ProtocolInfo::MOVE_PLAYER_PACKET:
|
||||
case ProtocolInfo::REQUEST_CHUNK_PACKET:
|
||||
case ProtocolInfo::ANIMATE_PACKET:
|
||||
case ProtocolInfo::SET_HEALTH_PACKET:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$this->received[$p->messageIndex] = true;
|
||||
}
|
||||
$p->decode();
|
||||
$this->handleDataPacket($p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($this->nextBuffer <= $time and $this->bufferLen > 0){
|
||||
$this->sendBuffer();
|
||||
}
|
||||
|
||||
$limit = $time - 5; //max lag
|
||||
foreach($this->recoveryQueue as $count => $data){
|
||||
if($data->sendtime > $limit){
|
||||
break;
|
||||
}
|
||||
unset($this->recoveryQueue[$count]);
|
||||
$this->resendQueue[$count] = $data;
|
||||
}
|
||||
|
||||
if(($resendCnt = count($this->resendQueue)) > 0){
|
||||
foreach($this->resendQueue as $count => $data){
|
||||
unset($this->resendQueue[$count]);
|
||||
$this->packetStats[1]++;
|
||||
$this->lag[] = microtime(true) - $data->sendtime;
|
||||
$data->sendtime = microtime(true);
|
||||
$this->send($data);
|
||||
$this->recoveryQueue[$count] = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function onUpdate(){
|
||||
if($this->spawned === false){
|
||||
return true;
|
||||
@ -1267,6 +973,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
if($this->connected === false){
|
||||
return;
|
||||
}
|
||||
$packet->decode();
|
||||
|
||||
$this->server->getPluginManager()->callEvent($ev = new DataPacketReceiveEvent($this, $packet));
|
||||
if($ev->isCancelled()){
|
||||
@ -1274,34 +981,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
}
|
||||
|
||||
switch($packet->pid()){
|
||||
case 0x01:
|
||||
break;
|
||||
case ProtocolInfo::PONG_PACKET:
|
||||
break;
|
||||
case ProtocolInfo::PING_PACKET:
|
||||
$pk = new PongPacket;
|
||||
$pk->ptime = $packet->time;
|
||||
$pk->time = abs(microtime(true) * 1000);
|
||||
$this->directDataPacket($pk);
|
||||
break;
|
||||
case ProtocolInfo::DISCONNECT_PACKET:
|
||||
$this->close($this->username . " has left the game", "client disconnect");
|
||||
break;
|
||||
case ProtocolInfo::CLIENT_CONNECT_PACKET:
|
||||
if($this->loggedIn === true){
|
||||
break;
|
||||
}
|
||||
$pk = new ServerHandshakePacket;
|
||||
$pk->port = $this->port;
|
||||
$pk->session = $packet->session;
|
||||
$pk->session2 = Binary::readLong("\x00\x00\x00\x00\x04\x44\x0b\xa9");
|
||||
$this->dataPacket($pk);
|
||||
break;
|
||||
case ProtocolInfo::CLIENT_HANDSHAKE_PACKET:
|
||||
if($this->loggedIn === true){
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ProtocolInfo::LOGIN_PACKET:
|
||||
if($this->loggedIn === true){
|
||||
break;
|
||||
@ -1321,11 +1000,11 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
if($packet->protocol1 < ProtocolInfo::CURRENT_PROTOCOL){
|
||||
$pk = new LoginStatusPacket;
|
||||
$pk->status = 1;
|
||||
$this->directDataPacket($pk);
|
||||
$this->dataPacket($pk);
|
||||
}else{
|
||||
$pk = new LoginStatusPacket;
|
||||
$pk->status = 2;
|
||||
$this->directDataPacket($pk);
|
||||
$this->dataPacket($pk);
|
||||
}
|
||||
$this->close("", "Incorrect protocol #" . $packet->protocol1, false);
|
||||
|
||||
@ -1454,7 +1133,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
//$this->evid[] = $this->server->event("tile.container.slot", array($this, "eventHandler"));
|
||||
//$this->evid[] = $this->server->event("tile.update", array($this, "eventHandler"));
|
||||
$this->lastMeasure = microtime(true);
|
||||
$this->tasks[] = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "measureLag")), 50);
|
||||
|
||||
$this->server->getLogger()->info(TextFormat::AQUA . $this->username . TextFormat::WHITE . "[/" . $this->ip . ":" . $this->port . "] logged in with entity id " . $this->id . " at (" . $this->getLevel()->getName() . ", " . round($this->x, 4) . ", " . round($this->y, 4) . ", " . round($this->z, 4) . ")");
|
||||
|
||||
@ -1492,7 +1170,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
|
||||
$this->teleport($ev->getRespawnPosition());
|
||||
$this->spawnToAll();
|
||||
$this->sendBuffer();
|
||||
|
||||
break;
|
||||
case 2: //Chunk loaded?
|
||||
@ -1509,28 +1186,27 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
if($this->spawned === false){
|
||||
break;
|
||||
}
|
||||
if($packet->messageIndex > $this->lastMovement){
|
||||
$this->lastMovement = $packet->messageIndex;
|
||||
$newPos = new Vector3($packet->x, $packet->y, $packet->z);
|
||||
if($this->forceMovement instanceof Vector3){
|
||||
if($this->forceMovement->distance($newPos) <= 0.7){
|
||||
$this->forceMovement = false;
|
||||
}else{
|
||||
$this->setPosition($this->forceMovement);
|
||||
}
|
||||
|
||||
$newPos = new Vector3($packet->x, $packet->y, $packet->z);
|
||||
if($this->forceMovement instanceof Vector3){
|
||||
if($this->forceMovement->distance($newPos) <= 0.7){
|
||||
$this->forceMovement = false;
|
||||
}else{
|
||||
$this->setPosition($this->forceMovement);
|
||||
}
|
||||
/*$speed = $this->entity->getSpeedMeasure();
|
||||
if($this->blocked === true or ($this->server->api->getProperty("allow-flight") !== true and (($speed > 9 and ($this->gamemode & 0x01) === 0x00) or $speed > 20 or $this->entity->distance($newPos) > 7)) or $this->server->api->handle("player.move", $this->entity) === false){
|
||||
if($this->lastCorrect instanceof Vector3){
|
||||
$this->teleport($this->lastCorrect, $this->entity->yaw, $this->entity->pitch, false);
|
||||
}
|
||||
if($this->blocked !== true){
|
||||
$this->server->getLogger()->warning($this->username." moved too quickly!");
|
||||
}
|
||||
}else{*/
|
||||
$this->setPositionAndRotation($newPos, $packet->yaw, $packet->pitch);
|
||||
//}
|
||||
}
|
||||
/*$speed = $this->entity->getSpeedMeasure();
|
||||
if($this->blocked === true or ($this->server->api->getProperty("allow-flight") !== true and (($speed > 9 and ($this->gamemode & 0x01) === 0x00) or $speed > 20 or $this->entity->distance($newPos) > 7)) or $this->server->api->handle("player.move", $this->entity) === false){
|
||||
if($this->lastCorrect instanceof Vector3){
|
||||
$this->teleport($this->lastCorrect, $this->entity->yaw, $this->entity->pitch, false);
|
||||
}
|
||||
if($this->blocked !== true){
|
||||
$this->server->getLogger()->warning($this->username." moved too quickly!");
|
||||
}
|
||||
}else{*/
|
||||
$this->setPositionAndRotation($newPos, $packet->yaw, $packet->pitch);
|
||||
//}
|
||||
|
||||
break;
|
||||
case ProtocolInfo::PLAYER_EQUIPMENT_PACKET:
|
||||
if($this->spawned === false){
|
||||
@ -1754,7 +1430,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
$pk->z = $target->z;
|
||||
$pk->block = $target->getID();
|
||||
$pk->meta = $target->getDamage();
|
||||
$this->directDataPacket($pk);
|
||||
$this->dataPacket($pk);
|
||||
//TODO: priority
|
||||
if($tile instanceof Spawnable){
|
||||
$tile->spawnTo($this);
|
||||
}
|
||||
@ -2228,7 +1905,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
*/
|
||||
public function close($message = "", $reason = "generic reason"){
|
||||
if($this->connected === true){
|
||||
unset($this->getLevel()->players[$this->CID]);
|
||||
unset($this->getLevel()->players[spl_object_hash($this)]);
|
||||
if($this->username != ""){
|
||||
$this->server->getPluginManager()->callEvent($ev = new PlayerQuitEvent($this, $message));
|
||||
if($this->loggedIn === true){
|
||||
@ -2237,8 +1914,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
}
|
||||
}
|
||||
|
||||
$this->sendBuffer();
|
||||
$this->directDataPacket(new DisconnectPacket);
|
||||
$this->interface->close($this, $reason);
|
||||
$this->connected = false;
|
||||
$this->server->removePlayer($this);
|
||||
$this->getLevel()->freeAllChunks($this);
|
||||
@ -2247,10 +1923,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
$task->cancel();
|
||||
}
|
||||
$this->tasks = [];
|
||||
$this->recoveryQueue = [];
|
||||
$this->receiveQueue = [];
|
||||
$this->resendQueue = [];
|
||||
$this->ackQueue = [];
|
||||
|
||||
if(isset($ev) and $this->username != "" and $this->spawned !== false and $ev->getQuitMessage() != ""){
|
||||
$this->server->broadcastMessage($ev->getQuitMessage());
|
||||
@ -2262,9 +1934,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
$this->windowIndex = [];
|
||||
$this->chunksLoaded = [];
|
||||
$this->chunksOrder = [];
|
||||
$this->chunkCount = [];
|
||||
$this->received = [];
|
||||
$this->buffer = null;
|
||||
unset($this->buffer);
|
||||
}
|
||||
}
|
||||
@ -2294,37 +1963,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a Minecraft packet directly, bypassing the send buffers
|
||||
*
|
||||
* @param DataPacket $packet
|
||||
* @param bool $recover
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function directDataPacket(DataPacket $packet, $recover = true){
|
||||
if($this->connected === false){
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->server->getPluginManager()->callEvent($ev = new DataPacketSendEvent($this, $packet));
|
||||
if($ev->isCancelled()){
|
||||
return [];
|
||||
}
|
||||
$packet->encode();
|
||||
$pk = new Packet(Info::DATA_PACKET_0);
|
||||
$pk->data[] = $packet;
|
||||
$pk->seqNumber = $this->counter[0]++;
|
||||
$pk->sendtime = microtime(true);
|
||||
if($recover !== false){
|
||||
$this->recoveryQueue[$pk->seqNumber] = $pk;
|
||||
}
|
||||
|
||||
$this->send($pk);
|
||||
|
||||
return array($pk->seqNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the username
|
||||
*
|
||||
@ -2402,63 +2040,6 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
|
||||
$this->server->getPlayerMetadata()->removeMetadata($this, $metadataKey, $plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a RakNet Packet
|
||||
*
|
||||
* @param Packet $packet
|
||||
*/
|
||||
public function handlePacket(Packet $packet){
|
||||
if($this->connected === true){
|
||||
$this->timeout = microtime(true) + 20;
|
||||
switch($packet->pid()){
|
||||
case Info::NACK:
|
||||
foreach($packet->packets as $count){
|
||||
if(isset($this->recoveryQueue[$count])){
|
||||
$this->resendQueue[$count] =& $this->recoveryQueue[$count];
|
||||
$this->lag[] = microtime(true) - $this->recoveryQueue[$count]->sendtime;
|
||||
unset($this->recoveryQueue[$count]);
|
||||
}
|
||||
++$this->packetStats[1];
|
||||
}
|
||||
break;
|
||||
|
||||
case Info::ACK:
|
||||
foreach($packet->packets as $count){
|
||||
if(isset($this->recoveryQueue[$count])){
|
||||
$this->lag[] = microtime(true) - $this->recoveryQueue[$count]->sendtime;
|
||||
unset($this->recoveryQueue[$count]);
|
||||
unset($this->resendQueue[$count]);
|
||||
}
|
||||
++$this->packetStats[0];
|
||||
}
|
||||
break;
|
||||
|
||||
case Info::DATA_PACKET_0:
|
||||
case Info::DATA_PACKET_1:
|
||||
case Info::DATA_PACKET_2:
|
||||
case Info::DATA_PACKET_3:
|
||||
case Info::DATA_PACKET_4:
|
||||
case Info::DATA_PACKET_5:
|
||||
case Info::DATA_PACKET_6:
|
||||
case Info::DATA_PACKET_7:
|
||||
case Info::DATA_PACKET_8:
|
||||
case Info::DATA_PACKET_9:
|
||||
case Info::DATA_PACKET_A:
|
||||
case Info::DATA_PACKET_B:
|
||||
case Info::DATA_PACKET_C:
|
||||
case Info::DATA_PACKET_D:
|
||||
case Info::DATA_PACKET_E:
|
||||
case Info::DATA_PACKET_F:
|
||||
$this->ackQueue[] = $packet->seqNumber;
|
||||
$this->receiveQueue[$packet->seqNumber] = [];
|
||||
foreach($packet->data as $pk){
|
||||
$this->receiveQueue[$packet->seqNumber][] = $pk;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,7 @@ namespace pocketmine {
|
||||
use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\wizard\Installer;
|
||||
use raklib\RakLib;
|
||||
|
||||
const VERSION = "Alpha_1.4dev";
|
||||
const API_VERSION = "1.0.0";
|
||||
@ -101,7 +102,12 @@ namespace pocketmine {
|
||||
$autoloader->add("pocketmine", array(
|
||||
\pocketmine\PATH . "src"
|
||||
));
|
||||
|
||||
$autoloader->register(true);
|
||||
if(!class_exists("raklib\\RakLib", false)){
|
||||
require(\pocketmine\PATH . "src/raklib/raklib/RakLib.php");
|
||||
}
|
||||
RakLib::bootstrap($autoloader);
|
||||
|
||||
//Startup code. Do not look at it, it can harm you. Most of them are hacks to fix date-related bugs, or basic functions used after this
|
||||
|
||||
|
@ -35,8 +35,6 @@ use pocketmine\command\PluginIdentifiableCommand;
|
||||
use pocketmine\command\SimpleCommandMap;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\HandlerList;
|
||||
use pocketmine\event\server\PacketReceiveEvent;
|
||||
use pocketmine\event\server\PacketSendEvent;
|
||||
use pocketmine\event\server\ServerCommandEvent;
|
||||
use pocketmine\inventory\CraftingManager;
|
||||
use pocketmine\inventory\InventoryType;
|
||||
@ -62,14 +60,11 @@ use pocketmine\nbt\tag\Int;
|
||||
use pocketmine\nbt\tag\Long;
|
||||
use pocketmine\nbt\tag\Short;
|
||||
use pocketmine\nbt\tag\String;
|
||||
use pocketmine\network\Packet;
|
||||
use pocketmine\network\protocol\DataPacket;
|
||||
use pocketmine\network\query\QueryHandler;
|
||||
use pocketmine\network\query\QueryPacket;
|
||||
use pocketmine\network\raknet\Info as RakNetInfo;
|
||||
use pocketmine\network\raknet\Packet as RakNetPacket;
|
||||
use pocketmine\network\RakLibInterface;
|
||||
use pocketmine\network\rcon\RCON;
|
||||
use pocketmine\network\ThreadedHandler;
|
||||
use pocketmine\network\upnp\UPnP;
|
||||
use pocketmine\permission\BanList;
|
||||
use pocketmine\permission\DefaultPermissions;
|
||||
@ -88,6 +83,7 @@ use pocketmine\utils\MainLogger;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\VersionString;
|
||||
use pocketmine\network\SourceInterface;
|
||||
|
||||
/**
|
||||
* The class that manages everything
|
||||
@ -161,8 +157,8 @@ class Server{
|
||||
private $tickCounter;
|
||||
private $inTick = false;
|
||||
|
||||
/** @var ThreadedHandler */
|
||||
private $interface;
|
||||
/** @var SourceInterface[] */
|
||||
private $interfaces = [];
|
||||
|
||||
private $serverID;
|
||||
|
||||
@ -449,7 +445,7 @@ class Server{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Logger
|
||||
* @return \ThreadedLogger
|
||||
*/
|
||||
public function getLogger(){
|
||||
return $this->logger;
|
||||
@ -514,10 +510,17 @@ class Server{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ThreadedHandler
|
||||
* @return SourceInterface[]
|
||||
*/
|
||||
public function getNetwork(){
|
||||
return $this->interface;
|
||||
public function getInterfaces(){
|
||||
return $this->interfaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SourceInterface $interface
|
||||
*/
|
||||
public function addInterface(SourceInterface $interface){
|
||||
$this->interfaces[] = $interface;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -829,7 +832,7 @@ class Server{
|
||||
$this->logger->info("Preparing level \"" . $name . "\"");
|
||||
$level = new LevelFormat($path . "level.pmf");
|
||||
if(!$level->isLoaded){
|
||||
console("[ERROR] Could not load level \"" . $name . "\"");
|
||||
$this->logger->error("Could not load level \"" . $name . "\"");
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -1186,12 +1189,12 @@ class Server{
|
||||
|
||||
/**
|
||||
* @param \SplClassLoader $autoloader
|
||||
* @param \Logger $logger
|
||||
* @param \ThreadedLogger $logger
|
||||
* @param string $filePath
|
||||
* @param string $dataPath
|
||||
* @param string $pluginPath
|
||||
*/
|
||||
public function __construct(\SplClassLoader $autoloader, \Logger $logger, $filePath, $dataPath, $pluginPath){
|
||||
public function __construct(\SplClassLoader $autoloader, \ThreadedLogger $logger, $filePath, $dataPath, $pluginPath){
|
||||
self::$instance = $this;
|
||||
|
||||
$this->autoloader = $autoloader;
|
||||
@ -1279,7 +1282,7 @@ class Server{
|
||||
$this->logger->setLogDebug(\pocketmine\DEBUG > 1);
|
||||
}
|
||||
define("ADVANCED_CACHE", $this->getConfigBoolean("enable-advanced-cache", false));
|
||||
define("MAX_CHUNK_RATE", 20 / $this->getConfigInt("max-chunks-per-second", 7)); //Default rate ~448 kB/s
|
||||
define("MAX_CHUNK_RATE", 20 / $this->getConfigInt("max-chunks-per-second", 3)); //Default rate ~144 kB/s, TODO: increment this, add backwards notification of packets
|
||||
if(ADVANCED_CACHE == true){
|
||||
$this->logger->info("Advanced cache enabled");
|
||||
}
|
||||
@ -1291,7 +1294,8 @@ class Server{
|
||||
$this->logger->info("Starting Minecraft PE server on " . ($this->getIp() === "" ? "*" : $this->getIp()) . ":" . $this->getPort());
|
||||
define("BOOTUP_RANDOM", Utils::getRandomBytes(16));
|
||||
$this->serverID = Binary::readLong(substr(Utils::getUniqueID(true, $this->getIp() . $this->getPort()), 0, 8));
|
||||
$this->interface = new ThreadedHandler("255.255.255.255", $this->getPort(), $this->getIp() === "" ? "0.0.0.0" : $this->getIp());
|
||||
|
||||
$this->interfaces[] = new RakLibInterface($this);
|
||||
|
||||
$this->logger->info("This server is running PocketMine-MP version " . ($version->isDev() ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET . " \"" . $this->getCodename() . "\" (API " . $this->getApiVersion() . ")", true, true, 0);
|
||||
$this->logger->info("PocketMine-MP is distributed under the LGPL License", true, true, 0);
|
||||
@ -1575,7 +1579,8 @@ class Server{
|
||||
public function start(){
|
||||
|
||||
if($this->getConfigBoolean("enable-query", true) === true){
|
||||
$this->queryHandler = new QueryHandler();
|
||||
//$this->queryHandler = new QueryHandler();
|
||||
//TODO: query
|
||||
}
|
||||
|
||||
|
||||
@ -1614,13 +1619,12 @@ class Server{
|
||||
private function tickProcessorWindows(){
|
||||
$lastLoop = 0;
|
||||
while($this->isRunning){
|
||||
if(($packet = $this->interface->readPacket()) instanceof Packet){
|
||||
$this->pluginManager->callEvent($ev = new PacketReceiveEvent($packet));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->handlePacket($packet);
|
||||
foreach($this->interfaces as $interface){
|
||||
if($interface->process()){
|
||||
$lastLoop = 0;
|
||||
}
|
||||
$lastLoop = 0;
|
||||
}
|
||||
|
||||
if(($ticks = $this->tick()) !== true){
|
||||
++$lastLoop;
|
||||
if($lastLoop > 128){
|
||||
@ -1729,20 +1733,20 @@ class Server{
|
||||
ob_end_clean();
|
||||
$dump .= "\r\n```";
|
||||
$name = "Error_Dump_" . date("D_M_j-H.i.s-T_Y");
|
||||
log($dump, $name, true, 0, true);
|
||||
//log($dump, $name, true, 0, true);
|
||||
$this->logger->emergency("Please submit the \"{$name}.log\" file to the Bug Reporting page. Give as much info as you can.", true, true, 0);
|
||||
}
|
||||
|
||||
private function tickProcessor(){
|
||||
$lastLoop = 0;
|
||||
while($this->isRunning){
|
||||
if(($packet = $this->interface->readPacket()) instanceof Packet){
|
||||
$this->pluginManager->callEvent($ev = new PacketReceiveEvent($packet));
|
||||
if(!$ev->isCancelled()){
|
||||
$this->handlePacket($packet);
|
||||
|
||||
foreach($this->interfaces as $interface){
|
||||
if($interface->process()){
|
||||
$lastLoop = 0;
|
||||
}
|
||||
$lastLoop = 0;
|
||||
}
|
||||
|
||||
if(($ticks = $this->tick()) !== true){
|
||||
++$lastLoop;
|
||||
if($lastLoop > 16 and $lastLoop < 128){
|
||||
@ -1761,68 +1765,11 @@ class Server{
|
||||
public function handlePacket(Packet $packet){
|
||||
if($packet instanceof QueryPacket and isset($this->queryHandler)){
|
||||
$this->queryHandler->handle($packet);
|
||||
}elseif($packet instanceof RakNetPacket){
|
||||
$CID = $packet->ip . ":" . $packet->port;
|
||||
if(isset($this->players[$CID])){
|
||||
$this->players[$CID]->handlePacket($packet);
|
||||
}else{
|
||||
switch($packet->pid()){
|
||||
case RakNetInfo::UNCONNECTED_PING:
|
||||
case RakNetInfo::UNCONNECTED_PING_OPEN_CONNECTIONS:
|
||||
$pk = new RakNetPacket(RakNetInfo::UNCONNECTED_PONG);
|
||||
$pk->pingID = $packet->pingID;
|
||||
$pk->serverID = $this->serverID;
|
||||
$pk->serverType = "MCCPP;Demo;" . $this->getMotd() . " [" . count($this->players) . "/" . $this->getMaxPlayers() . "]";
|
||||
$pk->ip = $packet->ip;
|
||||
$pk->port = $packet->port;
|
||||
$this->sendPacket($pk);
|
||||
break;
|
||||
case RakNetInfo::OPEN_CONNECTION_REQUEST_1:
|
||||
if($packet->structure !== RakNetInfo::STRUCTURE){
|
||||
$this->logger->debug("Incorrect structure #" . $packet->structure . " from " . $packet->ip . ":" . $packet->port);
|
||||
$pk = new RakNetPacket(RakNetInfo::INCOMPATIBLE_PROTOCOL_VERSION);
|
||||
$pk->serverID = $this->serverID;
|
||||
$pk->ip = $packet->ip;
|
||||
$pk->port = $packet->port;
|
||||
$this->sendPacket($pk);
|
||||
}else{
|
||||
$pk = new RakNetPacket(RakNetInfo::OPEN_CONNECTION_REPLY_1);
|
||||
$pk->serverID = $this->serverID;
|
||||
$pk->mtuSize = strlen($packet->buffer);
|
||||
$pk->ip = $packet->ip;
|
||||
$pk->port = $packet->port;
|
||||
$this->sendPacket($pk);
|
||||
}
|
||||
break;
|
||||
case RakNetInfo::OPEN_CONNECTION_REQUEST_2:
|
||||
$this->players[$CID] = new Player($packet->clientID, $packet->ip, $packet->port, $packet->mtuSize); //New Session!
|
||||
$pk = new RakNetPacket(RakNetInfo::OPEN_CONNECTION_REPLY_2);
|
||||
$pk->serverID = $this->serverID;
|
||||
$pk->serverPort = $this->getPort();
|
||||
$pk->mtuSize = $packet->mtuSize;
|
||||
$pk->ip = $packet->ip;
|
||||
$pk->port = $packet->port;
|
||||
$this->sendPacket($pk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to the processing queue. Returns the number of bytes
|
||||
*
|
||||
* @param Packet $packet
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function sendPacket(Packet $packet){
|
||||
$this->pluginManager->callEvent($ev = new PacketSendEvent($packet));
|
||||
if(!$ev->isCancelled()){
|
||||
return $this->interface->writePacket($packet);
|
||||
}
|
||||
|
||||
return 0;
|
||||
public function addPlayer($identifier, Player $player){
|
||||
$this->players[$identifier] = $player;
|
||||
}
|
||||
|
||||
private function checkTickUpdates($currentTick){
|
||||
@ -1895,7 +1842,7 @@ class Server{
|
||||
|
||||
public function titleTick(){
|
||||
if(defined("pocketmine\\DEBUG") and \pocketmine\DEBUG >= 0 and \pocketmine\ANSI === true){
|
||||
echo "\x1b]0;PocketMine-MP " . $this->getPocketMineVersion() . " | Online " . count($this->players) . "/" . $this->getMaxPlayers() . " | RAM " . round((memory_get_usage() / 1024) / 1024, 2) . "/" . round((memory_get_usage(true) / 1024) / 1024, 2) . " MB | U " . round($this->interface->getUploadSpeed() / 1024, 2) . " D " . round($this->interface->getDownloadSpeed() / 1024, 2) . " kB/s | TPS " . $this->getTicksPerSecond() . "\x07";
|
||||
echo "\x1b]0;PocketMine-MP " . $this->getPocketMineVersion() . " | Online " . count($this->players) . "/" . $this->getMaxPlayers() . " | RAM " . round((memory_get_usage() / 1024) / 1024, 2) . "/" . round((memory_get_usage(true) / 1024) / 1024, 2) . " MB | U -1 D -1 kB/s | TPS " . $this->getTicksPerSecond() . "\x07";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,47 +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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
//Entities
|
||||
const ENTITY_PLAYER = 1;
|
||||
|
||||
const ENTITY_MOB = 2;
|
||||
const MOB_CHICKEN = 10;
|
||||
const MOB_COW = 11;
|
||||
const MOB_PIG = 12;
|
||||
const MOB_SHEEP = 13;
|
||||
|
||||
const MOB_ZOMBIE = 32;
|
||||
const MOB_CREEPER = 33;
|
||||
const MOB_SKELETON = 34;
|
||||
const MOB_SPIDER = 35;
|
||||
const MOB_PIGMAN = 36;
|
||||
|
||||
const ENTITY_OBJECT = 3;
|
||||
const OBJECT_PRIMEDTNT = 65;
|
||||
const OBJECT_ARROW = 80;
|
||||
const OBJECT_PAINTING = 83;
|
||||
|
||||
const ENTITY_ITEM = 4;
|
||||
|
||||
const ENTITY_FALLING = 5;
|
||||
const FALLING_SAND = 66;
|
@ -1,41 +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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\event\server;
|
||||
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\Event;
|
||||
use pocketmine\network\Packet;
|
||||
|
||||
class PacketReceiveEvent extends ServerEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
private $packet;
|
||||
|
||||
|
||||
public function __construct(Packet $packet){
|
||||
$this->packet = $packet;
|
||||
}
|
||||
|
||||
public function getPacket(){
|
||||
return $this->packet;
|
||||
}
|
||||
}
|
@ -1,41 +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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\event\server;
|
||||
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\Event;
|
||||
use pocketmine\network\Packet;
|
||||
|
||||
class PacketSendEvent extends ServerEvent implements Cancellable{
|
||||
public static $handlerList = null;
|
||||
|
||||
private $packet;
|
||||
|
||||
|
||||
public function __construct(Packet $packet){
|
||||
$this->packet = $packet;
|
||||
}
|
||||
|
||||
public function getPacket(){
|
||||
return $this->packet;
|
||||
}
|
||||
}
|
@ -2,11 +2,11 @@
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* 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
|
||||
@ -15,7 +15,7 @@
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
@ -204,7 +204,7 @@ class Level{
|
||||
public function useChunk($X, $Z, Player $player){
|
||||
$index = LevelFormat::getIndex($X, $Z);
|
||||
$this->loadChunk($X, $Z);
|
||||
$this->usedChunks[$index][$player->CID] = $player;
|
||||
$this->usedChunks[$index][spl_object_hash($player)] = $player;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -215,7 +215,7 @@ class Level{
|
||||
*/
|
||||
public function freeAllChunks(Player $player){
|
||||
foreach($this->usedChunks as $i => $c){
|
||||
unset($this->usedChunks[$i][$player->CID]);
|
||||
unset($this->usedChunks[$i][spl_object_hash($player)]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,7 +228,7 @@ class Level{
|
||||
* @param Player $player
|
||||
*/
|
||||
public function freeChunk($X, $Z, Player $player){
|
||||
unset($this->usedChunks[LevelFormat::getIndex($X, $Z)][$player->CID]);
|
||||
unset($this->usedChunks[LevelFormat::getIndex($X, $Z)][spl_object_hash($player)]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,30 +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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\network;
|
||||
|
||||
|
||||
class Packet extends \stdClass{
|
||||
public $ip;
|
||||
public $port;
|
||||
public $buffer;
|
||||
|
||||
}
|
316
src/pocketmine/network/RakLibInterface.php
Normal file
316
src/pocketmine/network/RakLibInterface.php
Normal file
@ -0,0 +1,316 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Network-related classes
|
||||
*/
|
||||
namespace pocketmine\network;
|
||||
|
||||
use pocketmine\network\protocol\AddEntityPacket;
|
||||
use pocketmine\network\protocol\AddItemEntityPacket;
|
||||
use pocketmine\network\protocol\AddMobPacket;
|
||||
use pocketmine\network\protocol\AddPaintingPacket;
|
||||
use pocketmine\network\protocol\AddPlayerPacket;
|
||||
use pocketmine\network\protocol\AdventureSettingsPacket;
|
||||
use pocketmine\network\protocol\AnimatePacket;
|
||||
use pocketmine\network\protocol\ChatPacket;
|
||||
use pocketmine\network\protocol\ChunkDataPacket;
|
||||
use pocketmine\network\protocol\ContainerClosePacket;
|
||||
use pocketmine\network\protocol\ContainerOpenPacket;
|
||||
use pocketmine\network\protocol\ContainerSetContentPacket;
|
||||
use pocketmine\network\protocol\ContainerSetDataPacket;
|
||||
use pocketmine\network\protocol\ContainerSetSlotPacket;
|
||||
use pocketmine\network\protocol\DataPacket;
|
||||
use pocketmine\network\protocol\DropItemPacket;
|
||||
use pocketmine\network\protocol\EntityDataPacket;
|
||||
use pocketmine\network\protocol\EntityEventPacket;
|
||||
use pocketmine\network\protocol\ExplodePacket;
|
||||
use pocketmine\network\protocol\HurtArmorPacket;
|
||||
use pocketmine\network\protocol\Info as ProtocolInfo;
|
||||
use pocketmine\network\protocol\InteractPacket;
|
||||
use pocketmine\network\protocol\LevelEventPacket;
|
||||
use pocketmine\network\protocol\LoginPacket;
|
||||
use pocketmine\network\protocol\LoginStatusPacket;
|
||||
use pocketmine\network\protocol\MessagePacket;
|
||||
use pocketmine\network\protocol\MoveEntityPacket;
|
||||
use pocketmine\network\protocol\MoveEntityPacket_PosRot;
|
||||
use pocketmine\network\protocol\MovePlayerPacket;
|
||||
use pocketmine\network\protocol\PlayerActionPacket;
|
||||
use pocketmine\network\protocol\PlayerArmorEquipmentPacket;
|
||||
use pocketmine\network\protocol\PlayerEquipmentPacket;
|
||||
use pocketmine\network\protocol\ReadyPacket;
|
||||
use pocketmine\network\protocol\RemoveBlockPacket;
|
||||
use pocketmine\network\protocol\RemoveEntityPacket;
|
||||
use pocketmine\network\protocol\RemovePlayerPacket;
|
||||
use pocketmine\network\protocol\RequestChunkPacket;
|
||||
use pocketmine\network\protocol\RespawnPacket;
|
||||
use pocketmine\network\protocol\RotateHeadPacket;
|
||||
use pocketmine\network\protocol\SendInventoryPacket;
|
||||
use pocketmine\network\protocol\SetEntityDataPacket;
|
||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||
use pocketmine\network\protocol\SetHealthPacket;
|
||||
use pocketmine\network\protocol\SetSpawnPositionPacket;
|
||||
use pocketmine\network\protocol\SetTimePacket;
|
||||
use pocketmine\network\protocol\StartGamePacket;
|
||||
use pocketmine\network\protocol\TakeItemEntityPacket;
|
||||
use pocketmine\network\protocol\TileEventPacket;
|
||||
use pocketmine\network\protocol\UnknownPacket;
|
||||
use pocketmine\network\protocol\UpdateBlockPacket;
|
||||
use pocketmine\network\protocol\UseItemPacket;
|
||||
use pocketmine\Player;
|
||||
use pocketmine\Server;
|
||||
use raklib\protocol\EncapsulatedPacket;
|
||||
use raklib\RakLib;
|
||||
use raklib\server\RakLibServer;
|
||||
use raklib\server\ServerHandler;
|
||||
use raklib\server\ServerInstance;
|
||||
|
||||
class RakLibInterface implements ServerInstance, SourceInterface{
|
||||
|
||||
private $server;
|
||||
/** @var Player[] */
|
||||
private $players = [];
|
||||
|
||||
/** @var \SplObjectStorage */
|
||||
private $identifers;
|
||||
|
||||
/** @var ServerHandler */
|
||||
private $interface;
|
||||
|
||||
public function __construct(Server $server){
|
||||
$this->server = $server;
|
||||
$this->identifers = new \SplObjectStorage();
|
||||
|
||||
$server = new RakLibServer($this->server->getLogger(), $this->server->getLoader(), $this->server->getPort(), $this->server->getIp() === "" ? "0.0.0.0" : $this->server->getIp());
|
||||
$this->interface = new ServerHandler($server, $this);
|
||||
|
||||
}
|
||||
|
||||
public function process(){
|
||||
$this->interface->handlePacket();
|
||||
}
|
||||
|
||||
public function closeSession($identifier, $reason){
|
||||
if(isset($this->players[$identifier])){
|
||||
$player = $this->players[$identifier];
|
||||
$this->identifers->detach($player);
|
||||
unset($this->players[$identifier]);
|
||||
$player->close($player->getName() . " has left the game", $reason);
|
||||
}
|
||||
}
|
||||
|
||||
public function close(Player $player, $reason = "unknown reason"){
|
||||
if(isset($this->identifers[$player])){
|
||||
unset($this->players[$this->identifers[$player]]);
|
||||
$this->interface->closeSession($this->identifers[$player], $reason);
|
||||
$this->identifers->detach($player);
|
||||
}
|
||||
}
|
||||
|
||||
public function shutdown(){
|
||||
$this->interface->shutdown();
|
||||
}
|
||||
|
||||
public function emergencyShutdown(){
|
||||
$this->interface->emergencyShutdown();
|
||||
}
|
||||
|
||||
public function openSession($identifier, $address, $port, $clientID){
|
||||
$player = new Player($this, $clientID, $address, $port);
|
||||
$this->players[$identifier] = $player;
|
||||
$this->identifers->attach($player, $identifier);
|
||||
$this->server->addPlayer($identifier, $player);
|
||||
}
|
||||
|
||||
public function handleEncapsulated($identifier, EncapsulatedPacket $packet){
|
||||
if(isset($this->players[$identifier])){
|
||||
$this->players[$identifier]->handleDataPacket($this->getPacket($packet->buffer));
|
||||
}
|
||||
}
|
||||
|
||||
public function putPacket(Player $player, DataPacket $packet){
|
||||
if(isset($this->identifers[$player])){
|
||||
$packet->encode();
|
||||
$pk = new EncapsulatedPacket();
|
||||
$pk->buffer = $packet->buffer;
|
||||
$pk->reliability = 2;
|
||||
$this->interface->sendEncapsulated($this->identifers[$player], $pk);
|
||||
}
|
||||
}
|
||||
|
||||
private function getPacket($buffer){
|
||||
$pid = ord($buffer{0});
|
||||
switch($pid){ //TODO: more efficient selection based on range
|
||||
case ProtocolInfo::LOGIN_PACKET:
|
||||
$data = new LoginPacket();
|
||||
break;
|
||||
case ProtocolInfo::LOGIN_STATUS_PACKET:
|
||||
$data = new LoginStatusPacket();
|
||||
break;
|
||||
case ProtocolInfo::READY_PACKET:
|
||||
$data = new ReadyPacket();
|
||||
break;
|
||||
case ProtocolInfo::MESSAGE_PACKET:
|
||||
$data = new MessagePacket();
|
||||
break;
|
||||
case ProtocolInfo::SET_TIME_PACKET:
|
||||
$data = new SetTimePacket();
|
||||
break;
|
||||
case ProtocolInfo::START_GAME_PACKET:
|
||||
$data = new StartGamePacket();
|
||||
break;
|
||||
case ProtocolInfo::ADD_MOB_PACKET:
|
||||
$data = new AddMobPacket();
|
||||
break;
|
||||
case ProtocolInfo::ADD_PLAYER_PACKET:
|
||||
$data = new AddPlayerPacket();
|
||||
break;
|
||||
case ProtocolInfo::REMOVE_PLAYER_PACKET:
|
||||
$data = new RemovePlayerPacket();
|
||||
break;
|
||||
case ProtocolInfo::ADD_ENTITY_PACKET:
|
||||
$data = new AddEntityPacket();
|
||||
break;
|
||||
case ProtocolInfo::REMOVE_ENTITY_PACKET:
|
||||
$data = new RemoveEntityPacket();
|
||||
break;
|
||||
case ProtocolInfo::ADD_ITEM_ENTITY_PACKET:
|
||||
$data = new AddItemEntityPacket();
|
||||
break;
|
||||
case ProtocolInfo::TAKE_ITEM_ENTITY_PACKET:
|
||||
$data = new TakeItemEntityPacket();
|
||||
break;
|
||||
case ProtocolInfo::MOVE_ENTITY_PACKET:
|
||||
$data = new MoveEntityPacket();
|
||||
break;
|
||||
case ProtocolInfo::MOVE_ENTITY_PACKET_POSROT:
|
||||
$data = new MoveEntityPacket_PosRot();
|
||||
break;
|
||||
case ProtocolInfo::ROTATE_HEAD_PACKET:
|
||||
$data = new RotateHeadPacket();
|
||||
break;
|
||||
case ProtocolInfo::MOVE_PLAYER_PACKET:
|
||||
$data = new MovePlayerPacket();
|
||||
break;
|
||||
case ProtocolInfo::REMOVE_BLOCK_PACKET:
|
||||
$data = new RemoveBlockPacket();
|
||||
break;
|
||||
case ProtocolInfo::UPDATE_BLOCK_PACKET:
|
||||
$data = new UpdateBlockPacket();
|
||||
break;
|
||||
case ProtocolInfo::ADD_PAINTING_PACKET:
|
||||
$data = new AddPaintingPacket();
|
||||
break;
|
||||
case ProtocolInfo::EXPLODE_PACKET:
|
||||
$data = new ExplodePacket();
|
||||
break;
|
||||
case ProtocolInfo::LEVEL_EVENT_PACKET:
|
||||
$data = new LevelEventPacket();
|
||||
break;
|
||||
case ProtocolInfo::TILE_EVENT_PACKET:
|
||||
$data = new TileEventPacket();
|
||||
break;
|
||||
case ProtocolInfo::ENTITY_EVENT_PACKET:
|
||||
$data = new EntityEventPacket();
|
||||
break;
|
||||
case ProtocolInfo::REQUEST_CHUNK_PACKET:
|
||||
$data = new RequestChunkPacket();
|
||||
break;
|
||||
case ProtocolInfo::CHUNK_DATA_PACKET:
|
||||
$data = new ChunkDataPacket();
|
||||
break;
|
||||
case ProtocolInfo::PLAYER_EQUIPMENT_PACKET:
|
||||
$data = new PlayerEquipmentPacket();
|
||||
break;
|
||||
case ProtocolInfo::PLAYER_ARMOR_EQUIPMENT_PACKET:
|
||||
$data = new PlayerArmorEquipmentPacket();
|
||||
break;
|
||||
case ProtocolInfo::INTERACT_PACKET:
|
||||
$data = new InteractPacket();
|
||||
break;
|
||||
case ProtocolInfo::USE_ITEM_PACKET:
|
||||
$data = new UseItemPacket();
|
||||
break;
|
||||
case ProtocolInfo::PLAYER_ACTION_PACKET:
|
||||
$data = new PlayerActionPacket();
|
||||
break;
|
||||
case ProtocolInfo::HURT_ARMOR_PACKET:
|
||||
$data = new HurtArmorPacket();
|
||||
break;
|
||||
case ProtocolInfo::SET_ENTITY_DATA_PACKET:
|
||||
$data = new SetEntityDataPacket();
|
||||
break;
|
||||
case ProtocolInfo::SET_ENTITY_MOTION_PACKET:
|
||||
$data = new SetEntityMotionPacket();
|
||||
break;
|
||||
case ProtocolInfo::SET_HEALTH_PACKET:
|
||||
$data = new SetHealthPacket();
|
||||
break;
|
||||
case ProtocolInfo::SET_SPAWN_POSITION_PACKET:
|
||||
$data = new SetSpawnPositionPacket();
|
||||
break;
|
||||
case ProtocolInfo::ANIMATE_PACKET:
|
||||
$data = new AnimatePacket();
|
||||
break;
|
||||
case ProtocolInfo::RESPAWN_PACKET:
|
||||
$data = new RespawnPacket();
|
||||
break;
|
||||
case ProtocolInfo::SEND_INVENTORY_PACKET:
|
||||
$data = new SendInventoryPacket();
|
||||
break;
|
||||
case ProtocolInfo::DROP_ITEM_PACKET:
|
||||
$data = new DropItemPacket();
|
||||
break;
|
||||
case ProtocolInfo::CONTAINER_OPEN_PACKET:
|
||||
$data = new ContainerOpenPacket();
|
||||
break;
|
||||
case ProtocolInfo::CONTAINER_CLOSE_PACKET:
|
||||
$data = new ContainerClosePacket();
|
||||
break;
|
||||
case ProtocolInfo::CONTAINER_SET_SLOT_PACKET:
|
||||
$data = new ContainerSetSlotPacket();
|
||||
break;
|
||||
case ProtocolInfo::CONTAINER_SET_DATA_PACKET:
|
||||
$data = new ContainerSetDataPacket();
|
||||
break;
|
||||
case ProtocolInfo::CONTAINER_SET_CONTENT_PACKET:
|
||||
$data = new ContainerSetContentPacket();
|
||||
break;
|
||||
case ProtocolInfo::CHAT_PACKET:
|
||||
$data = new ChatPacket();
|
||||
break;
|
||||
case ProtocolInfo::ADVENTURE_SETTINGS_PACKET:
|
||||
$data = new AdventureSettingsPacket();
|
||||
break;
|
||||
case ProtocolInfo::ENTITY_DATA_PACKET:
|
||||
$data = new EntityDataPacket();
|
||||
break;
|
||||
default:
|
||||
$data = new UnknownPacket();
|
||||
$data->packetID = $pid;
|
||||
break;
|
||||
}
|
||||
|
||||
$data->setBuffer(substr($buffer, 1));
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@
|
||||
namespace pocketmine\network;
|
||||
|
||||
use pocketmine\network\protocol\DataPacket;
|
||||
use pocketmine\Player;
|
||||
|
||||
/**
|
||||
* Classes that implement this interface will be able to be attached to players
|
||||
@ -34,20 +35,27 @@ interface SourceInterface{
|
||||
/**
|
||||
* Sends a DataPacket to the interface
|
||||
*
|
||||
* @param Player $player
|
||||
* @param DataPacket $packet
|
||||
*/
|
||||
public function putPacket(DataPacket $packet);
|
||||
|
||||
/**
|
||||
* Gets the next data packet to handle, null if none
|
||||
*
|
||||
* @return DataPacket
|
||||
*/
|
||||
public function getPacket();
|
||||
public function putPacket(Player $player, DataPacket $packet);
|
||||
|
||||
/**
|
||||
* Terminates the connection
|
||||
*
|
||||
* @param Player $player
|
||||
* @param string $reason
|
||||
*
|
||||
*/
|
||||
public function close();
|
||||
public function close(Player $player, $reason = "unknown reason");
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function process();
|
||||
|
||||
public function shutdown();
|
||||
|
||||
public function emergencyShutdown();
|
||||
|
||||
}
|
@ -1,194 +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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Network-related classes
|
||||
*/
|
||||
namespace pocketmine\network;
|
||||
|
||||
use pocketmine\network\query\QueryPacket;
|
||||
use pocketmine\network\raknet\Info;
|
||||
use pocketmine\network\raknet\Packet as RakNetPacket;
|
||||
use pocketmine\utils\MainLogger;
|
||||
|
||||
class ThreadedHandler extends \Thread{
|
||||
protected $bandwidthUp;
|
||||
protected $bandwidthDown;
|
||||
protected $bandwidthTime;
|
||||
private $socket;
|
||||
protected $packets;
|
||||
protected $queue;
|
||||
protected $stop;
|
||||
protected $server;
|
||||
protected $port;
|
||||
protected $serverip;
|
||||
protected $recvIn;
|
||||
protected $recvOut;
|
||||
protected $sendIn;
|
||||
|
||||
public $path;
|
||||
|
||||
function __construct($server, $port = 19132, $serverip = "0.0.0.0"){
|
||||
$this->server = $server;
|
||||
$this->port = $port;
|
||||
$this->serverip = $serverip;
|
||||
$this->bandwidthUp = 0;
|
||||
$this->bandwidthDown = 0;
|
||||
$this->bandwidthTime = microtime(true);
|
||||
$this->packets = new \Threaded();
|
||||
$this->queue = new \Threaded();
|
||||
$this->stop = false;
|
||||
|
||||
//Load the classes so the Thread gets them
|
||||
Info::isValid(0);
|
||||
new Packet(0);
|
||||
new QueryPacket();
|
||||
new RakNetPacket(0);
|
||||
$this->path = \pocketmine\PATH;
|
||||
$this->start(PTHREADS_INHERIT_ALL & ~PTHREADS_INHERIT_CLASSES);
|
||||
}
|
||||
|
||||
public function close(){
|
||||
$this->synchronized(function (){
|
||||
$this->stop = true;
|
||||
socket_close($this->socket);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload speed in bytes/s
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getUploadSpeed(){
|
||||
return $this->bandwidthUp / max(1, microtime(true) - $this->bandwidthTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download speed in bytes/s
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getDownloadSpeed(){
|
||||
return $this->bandwidthDown / max(1, microtime(true) - $this->bandwidthTime);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Packet
|
||||
*/
|
||||
public function readPacket(){
|
||||
return $this->packets->shift();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Packet $packet
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function writePacket(Packet $packet){
|
||||
$this->queue[] = $packet;
|
||||
|
||||
return strlen($packet->buffer);
|
||||
}
|
||||
|
||||
public function run(){
|
||||
require($this->path . "src/spl/SplClassLoader.php");
|
||||
$autoloader = new \SplClassLoader();
|
||||
$autoloader->add("pocketmine", array(
|
||||
$this->path . "src"
|
||||
));
|
||||
$autoloader->register(true);
|
||||
|
||||
$this->socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
|
||||
socket_set_option($this->socket, SOL_SOCKET, SO_BROADCAST, 1); //Allow sending broadcast messages
|
||||
if(@socket_bind($this->socket, $this->serverip, $this->port) === true){
|
||||
socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 0);
|
||||
@socket_set_option($this->socket, SOL_SOCKET, SO_SNDBUF, 1024 * 1024 * 2); //2MB
|
||||
@socket_set_option($this->socket, SOL_SOCKET, SO_RCVBUF, 1024 * 1024); //1MB
|
||||
}else{
|
||||
MainLogger::getLogger()->critical("**** FAILED TO BIND TO " . $this->serverip . ":" . $this->port . "!", true, true, 0);
|
||||
MainLogger::getLogger()->critical("Perhaps a server is already running on that port?", true, true, 0);
|
||||
exit(1);
|
||||
}
|
||||
socket_set_nonblock($this->socket);
|
||||
|
||||
$count = 0;
|
||||
while($this->stop === false){
|
||||
if($this->getPacket() === false and $this->putPacket() === false){
|
||||
++$count;
|
||||
}else{
|
||||
$count = 0;
|
||||
}
|
||||
if($count > 128){
|
||||
$this->wait(100000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function putPacket(){
|
||||
if(($packet = $this->queue->shift()) instanceof Packet){
|
||||
if($packet instanceof RakNetPacket){
|
||||
$packet->encode();
|
||||
}
|
||||
$this->bandwidthUp += @socket_sendto($this->socket, $packet->buffer, strlen($packet->buffer), 0, $packet->ip, $packet->port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getPacket(){
|
||||
$buffer = null;
|
||||
$source = null;
|
||||
$port = null;
|
||||
$len = @socket_recvfrom($this->socket, $buffer, 65535, 0, $source, $port);
|
||||
if($len === false or $len == 0){
|
||||
return false;
|
||||
}
|
||||
$this->bandwidthDown += $len;
|
||||
$pid = ord($buffer{0});
|
||||
if(Info::isValid($pid)){
|
||||
$packet = new RakNetPacket($pid);
|
||||
$packet->buffer =& $buffer;
|
||||
$packet->ip = $source;
|
||||
$packet->port = $port;
|
||||
$packet->decode();
|
||||
}elseif($pid === 0xfe and $buffer{1} === "\xfd"){
|
||||
$packet = new QueryPacket;
|
||||
$packet->ip = $source;
|
||||
$packet->port = $port;
|
||||
$packet->buffer =& $buffer;
|
||||
}else{
|
||||
$packet = new Packet($pid);
|
||||
$packet->ip = $source;
|
||||
$packet->port = $port;
|
||||
$packet->buffer =& $buffer;
|
||||
}
|
||||
$this->packets[] = $packet;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -1,99 +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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* RakNet UDP library implementation
|
||||
*/
|
||||
namespace pocketmine\network\raknet;
|
||||
|
||||
|
||||
abstract class Info{
|
||||
const STRUCTURE = 5;
|
||||
const MAGIC = "\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78";
|
||||
const UNCONNECTED_PING = 0x01;
|
||||
const UNCONNECTED_PING_OPEN_CONNECTIONS = 0x02;
|
||||
|
||||
const OPEN_CONNECTION_REQUEST_1 = 0x05;
|
||||
const OPEN_CONNECTION_REPLY_1 = 0x06;
|
||||
const OPEN_CONNECTION_REQUEST_2 = 0x07;
|
||||
const OPEN_CONNECTION_REPLY_2 = 0x08;
|
||||
|
||||
const INCOMPATIBLE_PROTOCOL_VERSION = 0x1a; //CHECK THIS
|
||||
|
||||
const UNCONNECTED_PONG = 0x1c;
|
||||
const ADVERTISE_SYSTEM = 0x1d;
|
||||
|
||||
const DATA_PACKET_0 = 0x80;
|
||||
const DATA_PACKET_1 = 0x81;
|
||||
const DATA_PACKET_2 = 0x82;
|
||||
const DATA_PACKET_3 = 0x83;
|
||||
const DATA_PACKET_4 = 0x84;
|
||||
const DATA_PACKET_5 = 0x85;
|
||||
const DATA_PACKET_6 = 0x86;
|
||||
const DATA_PACKET_7 = 0x87;
|
||||
const DATA_PACKET_8 = 0x88;
|
||||
const DATA_PACKET_9 = 0x89;
|
||||
const DATA_PACKET_A = 0x8a;
|
||||
const DATA_PACKET_B = 0x8b;
|
||||
const DATA_PACKET_C = 0x8c;
|
||||
const DATA_PACKET_D = 0x8d;
|
||||
const DATA_PACKET_E = 0x8e;
|
||||
const DATA_PACKET_F = 0x8f;
|
||||
|
||||
const NACK = 0xa0;
|
||||
const ACK = 0xc0;
|
||||
|
||||
|
||||
public static function isValid($pid){
|
||||
switch((int) $pid){
|
||||
case self::UNCONNECTED_PING:
|
||||
case self::UNCONNECTED_PING_OPEN_CONNECTIONS:
|
||||
case self::OPEN_CONNECTION_REQUEST_1:
|
||||
case self::OPEN_CONNECTION_REPLY_1:
|
||||
case self::OPEN_CONNECTION_REQUEST_2:
|
||||
case self::OPEN_CONNECTION_REPLY_2:
|
||||
case self::INCOMPATIBLE_PROTOCOL_VERSION:
|
||||
case self::UNCONNECTED_PONG:
|
||||
case self::ADVERTISE_SYSTEM:
|
||||
case self::DATA_PACKET_0:
|
||||
case self::DATA_PACKET_1:
|
||||
case self::DATA_PACKET_2:
|
||||
case self::DATA_PACKET_3:
|
||||
case self::DATA_PACKET_4:
|
||||
case self::DATA_PACKET_5:
|
||||
case self::DATA_PACKET_6:
|
||||
case self::DATA_PACKET_7:
|
||||
case self::DATA_PACKET_8:
|
||||
case self::DATA_PACKET_9:
|
||||
case self::DATA_PACKET_A:
|
||||
case self::DATA_PACKET_B:
|
||||
case self::DATA_PACKET_C:
|
||||
case self::DATA_PACKET_D:
|
||||
case self::DATA_PACKET_E:
|
||||
case self::DATA_PACKET_F:
|
||||
case self::NACK:
|
||||
case self::ACK:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,591 +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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
namespace pocketmine\network\raknet;
|
||||
|
||||
use pocketmine\network\Packet as NetworkPacket;
|
||||
use pocketmine\network\protocol\AddEntityPacket;
|
||||
use pocketmine\network\protocol\AddItemEntityPacket;
|
||||
use pocketmine\network\protocol\AddMobPacket;
|
||||
use pocketmine\network\protocol\AddPaintingPacket;
|
||||
use pocketmine\network\protocol\AddPlayerPacket;
|
||||
use pocketmine\network\protocol\AdventureSettingsPacket;
|
||||
use pocketmine\network\protocol\AnimatePacket;
|
||||
use pocketmine\network\protocol\ChatPacket;
|
||||
use pocketmine\network\protocol\ChunkDataPacket;
|
||||
use pocketmine\network\protocol\ClientConnectPacket;
|
||||
use pocketmine\network\protocol\ContainerClosePacket;
|
||||
use pocketmine\network\protocol\ContainerOpenPacket;
|
||||
use pocketmine\network\protocol\ContainerSetContentPacket;
|
||||
use pocketmine\network\protocol\ContainerSetDataPacket;
|
||||
use pocketmine\network\protocol\ContainerSetSlotPacket;
|
||||
use pocketmine\network\protocol\DataPacket;
|
||||
use pocketmine\network\protocol\DisconnectPacket;
|
||||
use pocketmine\network\protocol\DropItemPacket;
|
||||
use pocketmine\network\protocol\EntityDataPacket;
|
||||
use pocketmine\network\protocol\EntityEventPacket;
|
||||
use pocketmine\network\protocol\ExplodePacket;
|
||||
use pocketmine\network\protocol\HurtArmorPacket;
|
||||
use pocketmine\network\protocol\Info as ProtocolInfo;
|
||||
use pocketmine\network\protocol\InteractPacket;
|
||||
use pocketmine\network\protocol\LevelEventPacket;
|
||||
use pocketmine\network\protocol\LoginPacket;
|
||||
use pocketmine\network\protocol\LoginStatusPacket;
|
||||
use pocketmine\network\protocol\MessagePacket;
|
||||
use pocketmine\network\protocol\MoveEntityPacket;
|
||||
use pocketmine\network\protocol\MoveEntityPacket_PosRot;
|
||||
use pocketmine\network\protocol\MovePlayerPacket;
|
||||
use pocketmine\network\protocol\PingPacket;
|
||||
use pocketmine\network\protocol\PlayerActionPacket;
|
||||
use pocketmine\network\protocol\PlayerArmorEquipmentPacket;
|
||||
use pocketmine\network\protocol\PlayerEquipmentPacket;
|
||||
use pocketmine\network\protocol\PongPacket;
|
||||
use pocketmine\network\protocol\ReadyPacket;
|
||||
use pocketmine\network\protocol\RemoveBlockPacket;
|
||||
use pocketmine\network\protocol\RemoveEntityPacket;
|
||||
use pocketmine\network\protocol\RemovePlayerPacket;
|
||||
use pocketmine\network\protocol\RequestChunkPacket;
|
||||
use pocketmine\network\protocol\RespawnPacket;
|
||||
use pocketmine\network\protocol\RotateHeadPacket;
|
||||
use pocketmine\network\protocol\SendInventoryPacket;
|
||||
use pocketmine\network\protocol\ServerHandshakePacket;
|
||||
use pocketmine\network\protocol\SetEntityDataPacket;
|
||||
use pocketmine\network\protocol\SetEntityMotionPacket;
|
||||
use pocketmine\network\protocol\SetHealthPacket;
|
||||
use pocketmine\network\protocol\SetSpawnPositionPacket;
|
||||
use pocketmine\network\protocol\SetTimePacket;
|
||||
use pocketmine\network\protocol\StartGamePacket;
|
||||
use pocketmine\network\protocol\TakeItemEntityPacket;
|
||||
use pocketmine\network\protocol\TileEventPacket;
|
||||
use pocketmine\network\protocol\UnknownPacket;
|
||||
use pocketmine\network\protocol\UpdateBlockPacket;
|
||||
use pocketmine\network\protocol\UseItemPacket;
|
||||
use pocketmine\utils\Binary;
|
||||
|
||||
class Packet extends NetworkPacket{
|
||||
private $packetID;
|
||||
private $offset = 1;
|
||||
public $data = [];
|
||||
|
||||
public function __construct($packetID){
|
||||
$this->packetID = (int) $packetID;
|
||||
}
|
||||
|
||||
public function pid(){
|
||||
return $this->packetID;
|
||||
}
|
||||
|
||||
protected function get($len){
|
||||
if($len < 0){
|
||||
$this->offset = strlen($this->buffer) - 1;
|
||||
|
||||
return "";
|
||||
}elseif($len === true){
|
||||
return substr($this->buffer, $this->offset);
|
||||
}
|
||||
|
||||
$buffer = "";
|
||||
for(; $len > 0; --$len, ++$this->offset){
|
||||
$buffer .= @$this->buffer{$this->offset};
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
private function getLong($unsigned = false){
|
||||
return Binary::readLong($this->get(8), $unsigned);
|
||||
}
|
||||
|
||||
private function getInt(){
|
||||
return Binary::readInt($this->get(4));
|
||||
}
|
||||
|
||||
private function getShort($unsigned = false){
|
||||
return Binary::readShort($this->get(2), $unsigned);
|
||||
}
|
||||
|
||||
private function getLTriad(){
|
||||
return Binary::readTriad(strrev($this->get(3)));
|
||||
}
|
||||
|
||||
private function getByte(){
|
||||
return ord($this->buffer{$this->offset++});
|
||||
}
|
||||
|
||||
private function feof(){
|
||||
return !isset($this->buffer{$this->offset});
|
||||
}
|
||||
|
||||
public function decode(){
|
||||
$this->offset = 1;
|
||||
switch($this->packetID){
|
||||
case Info::UNCONNECTED_PING:
|
||||
case Info::UNCONNECTED_PING_OPEN_CONNECTIONS:
|
||||
$this->pingID = $this->getLong();
|
||||
$this->offset += 16; //Magic
|
||||
break;
|
||||
case Info::OPEN_CONNECTION_REQUEST_1:
|
||||
$this->offset += 16; //Magic
|
||||
$this->structure = $this->getByte();
|
||||
$this->mtuSize = strlen($this->get(true));
|
||||
break;
|
||||
case Info::OPEN_CONNECTION_REQUEST_2:
|
||||
$this->offset += 16; //Magic
|
||||
$this->security = $this->get(5);
|
||||
$this->clientPort = $this->getShort(false);
|
||||
$this->mtuSize = $this->getShort(false);
|
||||
$this->clientID = $this->getLong();
|
||||
break;
|
||||
case Info::DATA_PACKET_0:
|
||||
case Info::DATA_PACKET_1:
|
||||
case Info::DATA_PACKET_2:
|
||||
case Info::DATA_PACKET_3:
|
||||
case Info::DATA_PACKET_4:
|
||||
case Info::DATA_PACKET_5:
|
||||
case Info::DATA_PACKET_6:
|
||||
case Info::DATA_PACKET_7:
|
||||
case Info::DATA_PACKET_8:
|
||||
case Info::DATA_PACKET_9:
|
||||
case Info::DATA_PACKET_A:
|
||||
case Info::DATA_PACKET_B:
|
||||
case Info::DATA_PACKET_C:
|
||||
case Info::DATA_PACKET_D:
|
||||
case Info::DATA_PACKET_E:
|
||||
case Info::DATA_PACKET_F:
|
||||
$this->seqNumber = $this->getLTriad();
|
||||
$this->data = [];
|
||||
while(!$this->feof() and $this->parseDataPacket() !== false){
|
||||
|
||||
}
|
||||
break;
|
||||
case Info::NACK:
|
||||
case Info::ACK:
|
||||
$count = $this->getShort();
|
||||
$this->packets = [];
|
||||
for($i = 0; $i < $count and !$this->feof(); ++$i){
|
||||
if($this->getByte() === 0){
|
||||
$start = $this->getLTriad();
|
||||
$end = $this->getLTriad();
|
||||
if(($end - $start) > 4096){
|
||||
$end = $start + 4096;
|
||||
}
|
||||
for($c = $start; $c <= $end; ++$c){
|
||||
$this->packets[] = $c;
|
||||
}
|
||||
}else{
|
||||
$this->packets[] = $this->getLTriad();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function parseDataPacket(){
|
||||
$packetFlags = $this->getByte();
|
||||
$reliability = ($packetFlags & 0b11100000) >> 5;
|
||||
$hasSplit = ($packetFlags & 0b00010000) > 0;
|
||||
$length = (int) ceil($this->getShort() / 8);
|
||||
if($reliability === 2
|
||||
or $reliability === 3
|
||||
or $reliability === 4
|
||||
or $reliability === 6
|
||||
or $reliability === 7
|
||||
){
|
||||
$messageIndex = $this->getLTriad();
|
||||
}else{
|
||||
$messageIndex = false;
|
||||
}
|
||||
|
||||
if($reliability === 1
|
||||
or $reliability === 3
|
||||
or $reliability === 4
|
||||
or $reliability === 7
|
||||
){
|
||||
$orderIndex = $this->getLTriad();
|
||||
$orderChannel = $this->getByte();
|
||||
}else{
|
||||
$orderIndex = false;
|
||||
$orderChannel = false;
|
||||
}
|
||||
|
||||
if($hasSplit == true){
|
||||
$splitCount = $this->getInt();
|
||||
$splitID = $this->getShort();
|
||||
$splitIndex = $this->getInt();
|
||||
}else{
|
||||
$splitCount = false;
|
||||
$splitID = false;
|
||||
$splitIndex = false;
|
||||
}
|
||||
|
||||
if($length <= 0
|
||||
or $orderChannel >= 32
|
||||
or ($hasSplit === true and $splitIndex >= $splitCount)
|
||||
){
|
||||
return false;
|
||||
}else{
|
||||
$pid = $this->getByte();
|
||||
$buffer = $this->get($length - 1);
|
||||
if(strlen($buffer) < ($length - 1)){
|
||||
return false;
|
||||
}
|
||||
switch($pid){
|
||||
case ProtocolInfo::PING_PACKET:
|
||||
$data = new PingPacket();
|
||||
break;
|
||||
case ProtocolInfo::PONG_PACKET:
|
||||
$data = new PongPacket();
|
||||
break;
|
||||
case ProtocolInfo::CLIENT_CONNECT_PACKET:
|
||||
$data = new ClientConnectPacket();
|
||||
break;
|
||||
case ProtocolInfo::SERVER_HANDSHAKE_PACKET:
|
||||
$data = new ServerHandshakePacket();
|
||||
break;
|
||||
case ProtocolInfo::DISCONNECT_PACKET:
|
||||
$data = new DisconnectPacket();
|
||||
break;
|
||||
case ProtocolInfo::LOGIN_PACKET:
|
||||
$data = new LoginPacket();
|
||||
break;
|
||||
case ProtocolInfo::LOGIN_STATUS_PACKET:
|
||||
$data = new LoginStatusPacket();
|
||||
break;
|
||||
case ProtocolInfo::READY_PACKET:
|
||||
$data = new ReadyPacket();
|
||||
break;
|
||||
case ProtocolInfo::MESSAGE_PACKET:
|
||||
$data = new MessagePacket();
|
||||
break;
|
||||
case ProtocolInfo::SET_TIME_PACKET:
|
||||
$data = new SetTimePacket();
|
||||
break;
|
||||
case ProtocolInfo::START_GAME_PACKET:
|
||||
$data = new StartGamePacket();
|
||||
break;
|
||||
case ProtocolInfo::ADD_MOB_PACKET:
|
||||
$data = new AddMobPacket();
|
||||
break;
|
||||
case ProtocolInfo::ADD_PLAYER_PACKET:
|
||||
$data = new AddPlayerPacket();
|
||||
break;
|
||||
case ProtocolInfo::REMOVE_PLAYER_PACKET:
|
||||
$data = new RemovePlayerPacket();
|
||||
break;
|
||||
case ProtocolInfo::ADD_ENTITY_PACKET:
|
||||
$data = new AddEntityPacket();
|
||||
break;
|
||||
case ProtocolInfo::REMOVE_ENTITY_PACKET:
|
||||
$data = new RemoveEntityPacket();
|
||||
break;
|
||||
case ProtocolInfo::ADD_ITEM_ENTITY_PACKET:
|
||||
$data = new AddItemEntityPacket();
|
||||
break;
|
||||
case ProtocolInfo::TAKE_ITEM_ENTITY_PACKET:
|
||||
$data = new TakeItemEntityPacket();
|
||||
break;
|
||||
case ProtocolInfo::MOVE_ENTITY_PACKET:
|
||||
$data = new MoveEntityPacket();
|
||||
break;
|
||||
case ProtocolInfo::MOVE_ENTITY_PACKET_POSROT:
|
||||
$data = new MoveEntityPacket_PosRot();
|
||||
break;
|
||||
case ProtocolInfo::ROTATE_HEAD_PACKET:
|
||||
$data = new RotateHeadPacket();
|
||||
break;
|
||||
case ProtocolInfo::MOVE_PLAYER_PACKET:
|
||||
$data = new MovePlayerPacket();
|
||||
break;
|
||||
case ProtocolInfo::REMOVE_BLOCK_PACKET:
|
||||
$data = new RemoveBlockPacket();
|
||||
break;
|
||||
case ProtocolInfo::UPDATE_BLOCK_PACKET:
|
||||
$data = new UpdateBlockPacket();
|
||||
break;
|
||||
case ProtocolInfo::ADD_PAINTING_PACKET:
|
||||
$data = new AddPaintingPacket();
|
||||
break;
|
||||
case ProtocolInfo::EXPLODE_PACKET:
|
||||
$data = new ExplodePacket();
|
||||
break;
|
||||
case ProtocolInfo::LEVEL_EVENT_PACKET:
|
||||
$data = new LevelEventPacket();
|
||||
break;
|
||||
case ProtocolInfo::TILE_EVENT_PACKET:
|
||||
$data = new TileEventPacket();
|
||||
break;
|
||||
case ProtocolInfo::ENTITY_EVENT_PACKET:
|
||||
$data = new EntityEventPacket();
|
||||
break;
|
||||
case ProtocolInfo::REQUEST_CHUNK_PACKET:
|
||||
$data = new RequestChunkPacket();
|
||||
break;
|
||||
case ProtocolInfo::CHUNK_DATA_PACKET:
|
||||
$data = new ChunkDataPacket();
|
||||
break;
|
||||
case ProtocolInfo::PLAYER_EQUIPMENT_PACKET:
|
||||
$data = new PlayerEquipmentPacket();
|
||||
break;
|
||||
case ProtocolInfo::PLAYER_ARMOR_EQUIPMENT_PACKET:
|
||||
$data = new PlayerArmorEquipmentPacket();
|
||||
break;
|
||||
case ProtocolInfo::INTERACT_PACKET:
|
||||
$data = new InteractPacket();
|
||||
break;
|
||||
case ProtocolInfo::USE_ITEM_PACKET:
|
||||
$data = new UseItemPacket();
|
||||
break;
|
||||
case ProtocolInfo::PLAYER_ACTION_PACKET:
|
||||
$data = new PlayerActionPacket();
|
||||
break;
|
||||
case ProtocolInfo::HURT_ARMOR_PACKET:
|
||||
$data = new HurtArmorPacket();
|
||||
break;
|
||||
case ProtocolInfo::SET_ENTITY_DATA_PACKET:
|
||||
$data = new SetEntityDataPacket();
|
||||
break;
|
||||
case ProtocolInfo::SET_ENTITY_MOTION_PACKET:
|
||||
$data = new SetEntityMotionPacket();
|
||||
break;
|
||||
case ProtocolInfo::SET_HEALTH_PACKET:
|
||||
$data = new SetHealthPacket();
|
||||
break;
|
||||
case ProtocolInfo::SET_SPAWN_POSITION_PACKET:
|
||||
$data = new SetSpawnPositionPacket();
|
||||
break;
|
||||
case ProtocolInfo::ANIMATE_PACKET:
|
||||
$data = new AnimatePacket();
|
||||
break;
|
||||
case ProtocolInfo::RESPAWN_PACKET:
|
||||
$data = new RespawnPacket();
|
||||
break;
|
||||
case ProtocolInfo::SEND_INVENTORY_PACKET:
|
||||
$data = new SendInventoryPacket();
|
||||
break;
|
||||
case ProtocolInfo::DROP_ITEM_PACKET:
|
||||
$data = new DropItemPacket();
|
||||
break;
|
||||
case ProtocolInfo::CONTAINER_OPEN_PACKET:
|
||||
$data = new ContainerOpenPacket();
|
||||
break;
|
||||
case ProtocolInfo::CONTAINER_CLOSE_PACKET:
|
||||
$data = new ContainerClosePacket();
|
||||
break;
|
||||
case ProtocolInfo::CONTAINER_SET_SLOT_PACKET:
|
||||
$data = new ContainerSetSlotPacket();
|
||||
break;
|
||||
case ProtocolInfo::CONTAINER_SET_DATA_PACKET:
|
||||
$data = new ContainerSetDataPacket();
|
||||
break;
|
||||
case ProtocolInfo::CONTAINER_SET_CONTENT_PACKET:
|
||||
$data = new ContainerSetContentPacket();
|
||||
break;
|
||||
case ProtocolInfo::CHAT_PACKET:
|
||||
$data = new ChatPacket();
|
||||
break;
|
||||
case ProtocolInfo::ADVENTURE_SETTINGS_PACKET:
|
||||
$data = new AdventureSettingsPacket();
|
||||
break;
|
||||
case ProtocolInfo::ENTITY_DATA_PACKET:
|
||||
$data = new EntityDataPacket();
|
||||
break;
|
||||
default:
|
||||
$data = new UnknownPacket();
|
||||
$data->packetID = $pid;
|
||||
break;
|
||||
}
|
||||
$data->reliability = $reliability;
|
||||
$data->hasSplit = $hasSplit;
|
||||
$data->messageIndex = $messageIndex;
|
||||
$data->orderIndex = $orderIndex;
|
||||
$data->orderChannel = $orderChannel;
|
||||
$data->splitCount = $splitCount;
|
||||
$data->splitID = $splitID;
|
||||
$data->splitIndex = $splitIndex;
|
||||
$data->setBuffer($buffer);
|
||||
$this->data[] = $data;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function encode(){
|
||||
if(strlen($this->buffer) > 0){
|
||||
return;
|
||||
}
|
||||
$this->buffer = chr($this->packetID);
|
||||
|
||||
switch($this->packetID){
|
||||
case Info::OPEN_CONNECTION_REPLY_1:
|
||||
$this->buffer .= Info::MAGIC;
|
||||
$this->putLong($this->serverID);
|
||||
$this->putByte(0); //server security
|
||||
$this->putShort($this->mtuSize);
|
||||
break;
|
||||
case Info::OPEN_CONNECTION_REPLY_2:
|
||||
$this->buffer .= Info::MAGIC;
|
||||
$this->putLong($this->serverID);
|
||||
$this->putShort($this->serverPort);
|
||||
$this->putShort($this->mtuSize);
|
||||
$this->putByte(0); //Server security
|
||||
break;
|
||||
case Info::INCOMPATIBLE_PROTOCOL_VERSION:
|
||||
$this->putByte(Info::STRUCTURE);
|
||||
$this->buffer .= Info::MAGIC;
|
||||
$this->putLong($this->serverID);
|
||||
break;
|
||||
case Info::UNCONNECTED_PONG:
|
||||
case Info::ADVERTISE_SYSTEM:
|
||||
$this->putLong($this->pingID);
|
||||
$this->putLong($this->serverID);
|
||||
$this->buffer .= Info::MAGIC;
|
||||
$this->putString($this->serverType);
|
||||
break;
|
||||
case Info::DATA_PACKET_0:
|
||||
case Info::DATA_PACKET_1:
|
||||
case Info::DATA_PACKET_2:
|
||||
case Info::DATA_PACKET_3:
|
||||
case Info::DATA_PACKET_4:
|
||||
case Info::DATA_PACKET_5:
|
||||
case Info::DATA_PACKET_6:
|
||||
case Info::DATA_PACKET_7:
|
||||
case Info::DATA_PACKET_8:
|
||||
case Info::DATA_PACKET_9:
|
||||
case Info::DATA_PACKET_A:
|
||||
case Info::DATA_PACKET_B:
|
||||
case Info::DATA_PACKET_C:
|
||||
case Info::DATA_PACKET_D:
|
||||
case Info::DATA_PACKET_E:
|
||||
case Info::DATA_PACKET_F:
|
||||
$this->putLTriad($this->seqNumber);
|
||||
foreach($this->data as $pk){
|
||||
$this->encodeDataPacket($pk);
|
||||
}
|
||||
break;
|
||||
case Info::NACK:
|
||||
case Info::ACK:
|
||||
$payload = "";
|
||||
$records = 0;
|
||||
$pointer = 0;
|
||||
sort($this->packets, SORT_NUMERIC);
|
||||
$max = count($this->packets);
|
||||
|
||||
while($pointer < $max){
|
||||
$type = true;
|
||||
$curr = $start = $this->packets[$pointer];
|
||||
for($i = $start + 1; $i < $max; ++$i){
|
||||
$n = $this->packets[$i];
|
||||
if(($n - $curr) === 1){
|
||||
$curr = $end = $n;
|
||||
$type = false;
|
||||
$pointer = $i + 1;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
++$pointer;
|
||||
if($type === false){
|
||||
$payload .= "\x00";
|
||||
$payload .= strrev(Binary::writeTriad($start));
|
||||
$payload .= strrev(Binary::writeTriad($end));
|
||||
}else{
|
||||
$payload .= Binary::writeBool(true);
|
||||
$payload .= strrev(Binary::writeTriad($start));
|
||||
}
|
||||
++$records;
|
||||
}
|
||||
$this->putShort($records);
|
||||
$this->buffer .= $payload;
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function encodeDataPacket(DataPacket $pk){
|
||||
$this->putByte(($pk->reliability << 5) | ($pk->hasSplit > 0 ? 0b00010000 : 0));
|
||||
$this->putShort(strlen($pk->buffer) << 3);
|
||||
if($pk->reliability === 2
|
||||
or $pk->reliability === 3
|
||||
or $pk->reliability === 4
|
||||
or $pk->reliability === 6
|
||||
or $pk->reliability === 7
|
||||
){
|
||||
$this->putLTriad($pk->messageIndex);
|
||||
}
|
||||
|
||||
if($pk->reliability === 1
|
||||
or $pk->reliability === 3
|
||||
or $pk->reliability === 4
|
||||
or $pk->reliability === 7
|
||||
){
|
||||
$this->putLTriad($pk->orderIndex);
|
||||
$this->putByte($pk->orderChannel);
|
||||
}
|
||||
|
||||
if($pk->hasSplit === true){
|
||||
$this->putInt($pk->splitCount);
|
||||
$this->putShort($pk->splitID);
|
||||
$this->putInt($pk->splitIndex);
|
||||
}
|
||||
|
||||
$this->buffer .= $pk->buffer;
|
||||
}
|
||||
|
||||
protected function put($str){
|
||||
$this->buffer .= $str;
|
||||
}
|
||||
|
||||
protected function putLong($v){
|
||||
$this->buffer .= Binary::writeLong($v);
|
||||
}
|
||||
|
||||
protected function putInt($v){
|
||||
$this->buffer .= Binary::writeInt($v);
|
||||
}
|
||||
|
||||
protected function putShort($v){
|
||||
$this->buffer .= Binary::writeShort($v);
|
||||
}
|
||||
|
||||
protected function putTriad($v){
|
||||
$this->buffer .= Binary::writeTriad($v);
|
||||
}
|
||||
|
||||
protected function putLTriad($v){
|
||||
$this->buffer .= strrev(Binary::writeTriad($v));
|
||||
}
|
||||
|
||||
protected function putByte($v){
|
||||
$this->buffer .= chr($v);
|
||||
}
|
||||
|
||||
protected function putString($v){
|
||||
$this->putShort(strlen($v));
|
||||
$this->put($v);
|
||||
}
|
||||
|
||||
public function __destruct(){
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
Subproject commit bf180fdfa72ed4893c16054768d9564487c36d26
|
||||
Subproject commit bb63be60432e7078b81f3681030e5bbb4f9f9004
|
Loading…
x
Reference in New Issue
Block a user