diff --git a/src/API/BanAPI.php b/src/API/BanAPI.php index 5e981cb03..18e44357a 100644 --- a/src/API/BanAPI.php +++ b/src/API/BanAPI.php @@ -133,7 +133,7 @@ class BanAPI{ switch($cmd){ case "sudo": $target = strtolower(array_shift($params)); - $player = $this->server->api->player->get($target); + $player = Player::get($target); if(!($player instanceof Player)){ $output .= "Player not connected.\n"; break; @@ -147,7 +147,7 @@ class BanAPI{ $output .= "Usage: /op \n"; break; } - $player = $this->server->api->player->get($user); + $player = Player::get($user); if(!($player instanceof Player)){ $this->ops->set($user); $this->ops->save(); @@ -161,7 +161,7 @@ class BanAPI{ break; case "deop": $user = strtolower($params[0]); - $player = $this->server->api->player->get($user); + $player = Player::get($user); if(!($player instanceof Player)){ $this->ops->remove($user); $this->ops->save(); @@ -178,7 +178,7 @@ class BanAPI{ $output .= "Usage: /kick [reason ...]\n"; }else{ $name = strtolower(array_shift($params)); - $player = $this->server->api->player->get($name); + $player = Player::get($name); if($player === false){ $output .= "Player \"".$name."\" does not exist\n"; }else{ @@ -246,7 +246,7 @@ class BanAPI{ case "add": case "ban": $ip = strtolower($params[0]); - $player = $this->server->api->player->get($ip); + $player = Player::get($ip); if($player instanceof Player){ $ip = $player->ip; $player->close("banned"); @@ -281,7 +281,7 @@ class BanAPI{ $user = strtolower($params[0]); $this->banned->set($user); $this->banned->save(); - $player = $this->server->api->player->get($user); + $player = Player::get($user); if($player !== false){ $player->close("You have been banned"); } diff --git a/src/API/BlockAPI.php b/src/API/BlockAPI.php index 6889d4ea4..e66f55c29 100644 --- a/src/API/BlockAPI.php +++ b/src/API/BlockAPI.php @@ -287,7 +287,7 @@ class BlockAPI{ $output .= "Usage: /give [amount]\n"; break; } - $player = $this->server->api->player->get($params[0]); + $player = Player::get($params[0]); $item = BlockAPI::fromString($params[1]); if(!isset($params[2])){ diff --git a/src/API/ChatAPI.php b/src/API/ChatAPI.php index 90ce98f66..d82e1e4b0 100644 --- a/src/API/ChatAPI.php +++ b/src/API/ChatAPI.php @@ -77,7 +77,7 @@ class ChatAPI{ $sender = $issuer->username; } $n = array_shift($params); - $target = $this->server->api->player->get($n); + $target = Player::get($n); if($target instanceof Player){ $target = $target->username; }else{ diff --git a/src/API/ConsoleAPI.php b/src/API/ConsoleAPI.php index 30ac63436..7df51187e 100644 --- a/src/API/ConsoleAPI.php +++ b/src/API/ConsoleAPI.php @@ -209,7 +209,7 @@ class ConsoleAPI{ if($issuer instanceof Player){ if($this->server->api->ban->isOp($issuer->username)){ $output = ""; - foreach($this->server->api->player->getAll() as $p){ + foreach(Player::getAll() as $p){ $output .= $this->run($cmd . " ". substr_replace($params, $p->username, $selector[1] + $offsetshift - 1, strlen($selector[0]) + 1), $issuer, $alias); } }else{ @@ -217,7 +217,7 @@ class ConsoleAPI{ } }else{ $output = ""; - foreach($this->server->api->player->getAll() as $p){ + foreach(Player::getAll() as $p){ $output .= $this->run($cmd . " ". substr_replace($params, $p->username, $selector[1] + $offsetshift - 1, strlen($selector[0]) + 1), $issuer, $alias); } } @@ -225,7 +225,7 @@ class ConsoleAPI{ case "r": case "random": $l = array(); - foreach($this->server->api->player->getAll() as $p){ + foreach(Player::getAll() as $p){ if($p !== $issuer){ $l[] = $p; } diff --git a/src/API/LevelAPI.php b/src/API/LevelAPI.php index 170067147..1204f5b6d 100644 --- a/src/API/LevelAPI.php +++ b/src/API/LevelAPI.php @@ -125,7 +125,7 @@ class LevelAPI{ console("[INFO] Unloading level \"".$name."\""); $level->nextSave = PHP_INT_MAX; $level->save(); - foreach($this->server->api->player->getAll($level) as $player){ + foreach($level->getPlayers() as $player){ $player->teleport($this->server->spawn); } /*foreach($this->server->api->entity->getAll($level) as $entity){ diff --git a/src/API/PlayerAPI.php b/src/API/PlayerAPI.php index f0ea1feb8..42fcf501b 100644 --- a/src/API/PlayerAPI.php +++ b/src/API/PlayerAPI.php @@ -132,7 +132,7 @@ class PlayerAPI{ if(count($params) === 3 and substr($tg, 0, 2) === "w:"){ $target = $this->server->api->level->get(substr($tg, 2)); }else{ - $target = $this->server->api->player->get($tg); + $target = Player::get($tg); } }else{ $target = $issuer; @@ -196,18 +196,18 @@ class PlayerAPI{ "v" => VIEW, ); if(isset($params[1])){ - if($this->server->api->player->get($params[1]) instanceof Player){ - $player = $this->server->api->player->get($params[1]); + if(Player::get($params[1]) instanceof Player){ + $player = Player::get($params[1]); $setgm = $params[0]; - }elseif($this->server->api->player->get($params[0]) instanceof Player){ - $player = $this->server->api->player->get($params[0]); + }elseif(Player::get($params[0]) instanceof Player){ + $player = Player::get($params[0]); $setgm = $params[1]; }else{ $output .= "Usage: /$cmd [player] or /$cmd [player] \n"; break; } }elseif(isset($params[0])){ - if(!($this->server->api->player->get($params[0]) instanceof Player)){ + if(!(Player::get($params[0]) instanceof Player)){ if($issuer instanceof Player){ $setgm = $params[0]; $player = $issuer; @@ -277,11 +277,11 @@ class PlayerAPI{ } break; case "list": - $output .= "There are ".count($this->server->clients)."/".$this->server->maxClients." players online:\n"; - if(count($this->server->clients) == 0){ + $output .= "There are ".count(Player::$list)."/".$this->server->maxClients." players online:\n"; + if(count(Player::$list) == 0){ break; } - foreach($this->server->clients as $c){ + foreach(Player::$list as $c){ $output .= $c->username.", "; } $output = substr($output, 0, -2)."\n"; @@ -328,72 +328,15 @@ class PlayerAPI{ return false; } - public function get($name, $alike = true, $multiple = false){ - $name = trim(strtolower($name)); - if($name === ""){ - return false; - } - $query = $this->server->query("SELECT ip,port,name FROM players WHERE name ".($alike === true ? "LIKE '%".$name."%'":"= '".$name."'").";"); - $players = array(); - if($query !== false and $query !== true){ - while(($d = $query->fetchArray(SQLITE3_ASSOC)) !== false){ - $CID = MainServer::clientID($d["ip"], $d["port"]); - if(isset($this->server->clients[$CID])){ - $players[$CID] = $this->server->clients[$CID]; - if($multiple === false and $d["name"] === $name){ - return $players[$CID]; - } - } - } - } - - if($multiple === false){ - if(count($players) > 0){ - return array_shift($players); - }else{ - return false; - } - }else{ - return $players; - } - } - - public function getAll($level = null){ - if($level instanceof Level){ - $clients = array(); - $l = $this->server->query("SELECT EID FROM entities WHERE level = '".$level->getName()."' AND class = '".ENTITY_PLAYER."';"); - if($l !== false and $l !== true){ - while(($e = $l->fetchArray(SQLITE3_ASSOC)) !== false){ - $e = $this->getByEID($e["EID"]); - if($e instanceof Player){ - $clients[$e->CID] = $e; - } - } - } - return $clients; - } - return $this->server->clients; - } - public function broadcastPacket(array $players, RakNetDataPacket $packet){ foreach($players as $p){ $p->dataPacket(clone $packet); } } - public function getByEID($eid){ - $eid = (int) $eid; - $CID = $this->server->query("SELECT ip,port FROM players WHERE EID = '".$eid."';", true); - $CID = MainServer::clientID($CID["ip"], $CID["port"]); - if(isset($this->server->clients[$CID])){ - return $this->server->clients[$CID]; - } - return false; - } - public function online(){ $o = array(); - foreach($this->server->clients as $p){ + foreach(Player::$list as $p){ if($p->auth === true){ $o[] = $p->username; } @@ -401,9 +344,10 @@ class PlayerAPI{ return $o; } + //TODO (remove) public function add($CID){ - if(isset($this->server->clients[$CID])){ - $player = $this->server->clients[$CID]; + if(isset(Player::$list[$CID])){ + $player =Player::$list[$CID]; $player->data = $this->getOffline($player->username); $player->gamemode = $player->data->get("gamemode"); if(($player->level = $this->server->api->level->get($player->data->get("position")["level"])) === false){ @@ -415,43 +359,6 @@ class PlayerAPI{ "z" => $player->level->getSpawn()->z, )); } - $this->server->query("INSERT OR REPLACE INTO players (CID, ip, port, name) VALUES (".$player->CID.", '".$player->ip."', ".$player->port.", '".strtolower($player->username)."');"); - } - } - - public function spawnAllPlayers(Player $player){ - foreach($this->getAll() as $p){ - if($p !== $player and ($p->entity instanceof Entity)){ - $p->entity->spawnTo($player); - if($p->level !== $player->level){ - $pk = new MoveEntityPacket_PosRot; - $pk->eid = $p->entity->eid; - $pk->x = -256; - $pk->y = 128; - $pk->z = -256; - $pk->yaw = 0; - $pk->pitch = 0; - $player->dataPacket($pk); - } - } - } - } - - public function spawnToAllPlayers(Player $player){ - foreach($this->getAll() as $p){ - if($p !== $player and ($p->entity instanceof Entity) and ($player->entity instanceof Entity)){ - $player->entity->spawnTo($p); - if($p->level !== $player->level){ - $pk = new MoveEntityPacket_PosRot; - $pk->eid = $player->entity->eid; - $pk->x = -256; - $pk->y = 128; - $pk->z = -256; - $pk->yaw = 0; - $pk->pitch = 0; - $p->dataPacket($pk); - } - } } } diff --git a/src/API/ServerAPI.php b/src/API/ServerAPI.php index e431d2525..9c5637986 100644 --- a/src/API/ServerAPI.php +++ b/src/API/ServerAPI.php @@ -271,7 +271,7 @@ class ServerAPI{ "version" => MAJOR_VERSION, "mc_version" => CURRENT_MINECRAFT_VERSION, "protocol" => ProtocolInfo::CURRENT_PROTOCOL, - "online" => count($this->server->clients), + "online" => count(Player::$list), "max" => $this->server->maxClients, "plugins" => $plist, ), diff --git a/src/Entity.php b/src/Entity.php index 525c338e5..219ab43b3 100644 --- a/src/Entity.php +++ b/src/Entity.php @@ -29,27 +29,36 @@ abstract class Entity extends Position{ //public $vehicle = null; public $chunkIndex; + public $lastX; public $lastY; public $lastZ; - public $velocity; + + public $motionX; + public $motionY; + public $motionZ; + public $yaw; public $pitch; public $lastYaw; public $lastPitch; + public $boundingBox; public $onGround; public $positionChanged; - public $velocityChanged; + public $motionChanged; public $dead; + public $height; public $width; public $length; + public $fallDistance; public $ticksLived; public $lastUpdate; public $maxFireTicks; public $fireTicks; + public $airTicks; public $namedtag; protected $inWater; @@ -65,7 +74,7 @@ abstract class Entity extends Position{ } public static function getAll(){ - return $this->list; + return Entity::$list; } @@ -92,12 +101,31 @@ abstract class Entity extends Position{ $this->namedtag->Pos[0] = $this->x; $this->namedtag->Pos[1] = $this->y; $this->namedtag->Pos[2] = $this->z; + + $this->namedtag->Motion[0] = $this->motionX; + $this->namedtag->Motion[1] = $this->motionY; + $this->namedtag->Motion[2] = $this->motionZ; + + $this->namedtag->Rotation[0] = $this->yaw; + $this->namedtag->Rotation[1] = $this->pitch; + + $this->namedtag->FallDistance = $this->fallDistance; + $this->namedtag->Fire = $this->fireTicks; + $this->namedtag->Air = $this->airTicks; + $this->namedtag->OnGround = $this->onGround == true ? 1:0; + $this->namedtag->Invulnerable = $this->invulnerable == true ? 1:0; } protected abstract function initEntity(); public abstract function spawnTo(Player $player); + public function despawnFrom(Player $player){ + $pk = new RemoveEntityPacket; + $pk->eid = $this->id; + $player->dataPacket($pk); + } + abstract function attack($damage, $source = "generic"); abstract function heal($amount, $source = "generic"); @@ -209,34 +237,91 @@ abstract class Entity extends Position{ } public function setPositionAndRotation(Vector3 $pos, $yaw, $pitch){ //TODO - $this->x = $pos->x; - $this->y = $pos->y; - $this->z = $pos->z; - $this->yaw = $yaw; - $this->pitch = $pitch; + if($this->setPosition($pos) === true){ + $this->yaw = $yaw; + $this->pitch = $pitch; + return true; + } + return false; } public function onCollideWithPlayer(EntityPlayer $entityPlayer){ } + protected function switchLevel(Level $targetLevel){ + if($this->level instanceof Level){ + if(EventHandler::callEvent(new EntityLevelChangeEvent($this, $this->level, $targetLevel)) === BaseEvent::DENY){ + return false; + } + unset($this->level->entities[$this->id]); + unset($this->level->chunkEntities[$this->chunkIndex][$this->id]); + $this->despawnFromAll(); + if($this instanceof Player){ + foreach($this->chunksLoaded as $index => $boolean){ + $X = null; + $Z = null; + PMFLevel::getXZ($index, $X, $Z); + foreach($this->level->getChunkEntities($X, $Z) as $entity){ + $entity->despawnFrom($this); + } + } + $this->level->freeAllChunks($this); + } + } + $this->level = $targetLevel; + $this->level->entities[$this->id] = $this; + if($this instanceof Player){ + $this->chunksLoaded = array(); + $pk = new SetTimePacket; + $pk->time = $this->level->getTime(); + $this->dataPacket($pk); + } + $this->spawnToAll(); + $this->chunkIndex = false; + } public function getPosition(){ return new Position($this->x, $this->y, $this->z, $this->level); } public function setPosition(Vector3 $pos){ + if($pos instanceof Position and $pos->level instanceof Level and $pos->level !== $this->level){ + if($this->switchLevel($pos->level) === false){ + return false; + } + } + if(EventHandler::callEvent(new EntityMoveEvent($this, $pos)) === BaseEvent::DENY){ + return false; + } $this->x = $pos->x; $this->y = $pos->y; $this->z = $pos->z; + + $radius = $this->width / 2; + if(($index = PMFLevel::getIndex($this->x >> 4, $this->z >> 4)) !== $this->chunkIndex){ + if($this->chunkIndex !== false){ + unset($this->level->chunkEntities[$this->chunkIndex][$this->id]); + } + $this->chunkIndex = $index; + $this->level->loadChunk($this->x >> 4, $this->z >> 4); + $this->level->chunkEntities[$this->chunkIndex][$this->id] = $this; + } + $this->boundingBox->setBounds($pos->x - $radius, $pos->y, $pos->z - $radius, $pos->x + $radius, $pos->y + $this->height, $pos->z + $radius); + return true; } - public function setVelocity(Vector3 $velocity){ - $this->velocity = clone $velocity; + public function getMotion(){ + return new Vector3($this->motionX, $this->motionY, $this->motionZ); } - public function getVelocity(){ - return clone $this->velocity; + public function setMotion(Vector3 $motion){ + if(EventHandler::callEvent(new EntityMotionEvent($this, $motion)) === BaseEvent::DENY){ + return false; + } + $this->motionX = $motion->x; + $this->motionY = $motion->y; + $this->motionZ = $motion->z; } public function isOnGround(){ @@ -251,10 +336,31 @@ abstract class Entity extends Position{ return $this->level; } - public function teleport(Position $pos){ - + public function teleport(Position $pos, $yaw = false, $pitch = false){ + $this->setMotion(new Vector3(0, 0, 0)); + if($this->setPositionAndRotation($pos, $yaw === false ? $this->yaw : $yaw, $pitch === false ? $this->pitch : $pitch) !== false){ + if($this instanceof Player){ + $this->airTicks = 300; + $this->fallDistance = 0; + $this->orderChunks(); + $this->getNextChunk(true); + $this->forceMovement = $pos; + + $pk = new MovePlayerPacket; + $pk->eid = 0; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->bodyYaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->yaw = $this->yaw; + $this->dataPacket($pk); + } + return true; + } + return false; } - + public function getID(){ return $this->id; } @@ -267,23 +373,22 @@ abstract class Entity extends Position{ } } + public function despawnFromAll(){ + foreach($this->level->getPlayers() as $player){ + if($player->eid !== false or $player->spawned !== true){ + $this->despawnFrom($player); + } + } + } + public function close(){ if($this->closed === false){ $this->closed = true; unset(Entity::$needUpdate[$this->id]); - unset($this->level->entities[$this->id]); + unset($this->level->entities[$this->id]); unset($this->level->chunkEntities[$this->chunkIndex][$this->id]); unset(Entity::$list[$this->id]); - if($this instanceof HumanEntity){ - $pk = new RemovePlayerPacket; - $pk->eid = $this->id; - $pk->clientID = 0; - $this->server->api->player->broadcastPacket($this->level->getPlayers(), $pk); - }else{ - $pk = new RemoveEntityPacket; - $pk->eid = $this->id; - $this->server->api->player->broadcastPacket($this->level->getPlayers(), $pk); - } + $this->despawnFromAll(); $this->server->api->dhandle("entity.remove", $this); } } diff --git a/src/EntityOLD.php b/src/EntityOLD.php index dc02a6c77..5bca5d1fa 100644 --- a/src/EntityOLD.php +++ b/src/EntityOLD.php @@ -577,7 +577,7 @@ class EntityOLD extends Position{ } }else{ $this->updateLast(); - $players = $this->server->api->player->getAll($this->level); + $players = $this->level->getPlayers(); if($this->player instanceof Player){ unset($players[$this->player->CID]); $pk = new MovePlayerPacket; @@ -659,7 +659,7 @@ class EntityOLD extends Position{ public function spawn($player){ if(!($player instanceof Player)){ - $player = $this->server->api->player->get($player); + $player = Player::get($player); } if($player->eid === $this->eid or $this->closed !== false or ($player->level !== $this->level and $this->class !== ENTITY_PLAYER)){ return false; diff --git a/src/MainServer.php b/src/MainServer.php index 95dba4906..7536d414a 100644 --- a/src/MainServer.php +++ b/src/MainServer.php @@ -21,7 +21,7 @@ class MainServer{ public $tCnt; - public $serverID, $interface, $database, $version, $invisible, $tickMeasure, $preparedSQL, $spawn, $whitelist, $seed, $stop, $gamemode, $difficulty, $name, $maxClients, $clients, $eidCnt, $custom, $description, $motd, $port, $saveEnabled; + public $serverID, $interface, $database, $version, $invisible, $tickMeasure, $preparedSQL, $spawn, $whitelist, $seed, $stop, $gamemode, $difficulty, $name, $maxClients, $eidCnt, $custom, $description, $motd, $port, $saveEnabled; private $serverip, $evCnt, $handCnt, $events, $eventsID, $handlers, $serverType, $lastTick, $doTick, $ticks, $memoryStats, $schedule, $asyncThread, $async = array(), $asyncID = 0; /** @@ -55,7 +55,6 @@ class MainServer{ $this->scheduleCnt = 1; $this->description = ""; $this->memoryStats = array(); - $this->clients = array(); $this->spawn = false; $this->saveEnabled = true; $this->whitelist = false; @@ -93,7 +92,7 @@ class MainServer{ public function titleTick(){ $time = microtime(true); if(defined("DEBUG") and DEBUG >= 0 and ENABLE_ANSI === true){ - echo "\x1b]0;PocketMine-MP ".MAJOR_VERSION." | Online ". count($this->clients)."/".$this->maxClients." | RAM ".round((memory_get_usage() / 1024) / 1024, 2)."MB | U ".round(($this->interface->bandwidth[1] / max(1, $time - $this->interface->bandwidth[2])) / 1024, 2)." D ".round(($this->interface->bandwidth[0] / max(1, $time - $this->interface->bandwidth[2])) / 1024, 2)." kB/s | TPS ".$this->getTPS()."\x07"; + echo "\x1b]0;PocketMine-MP ".MAJOR_VERSION." | Online ". count(Player::$list)."/".$this->maxClients." | RAM ".round((memory_get_usage() / 1024) / 1024, 2)."MB | U ".round(($this->interface->bandwidth[1] / max(1, $time - $this->interface->bandwidth[2])) / 1024, 2)." D ".round(($this->interface->bandwidth[0] / max(1, $time - $this->interface->bandwidth[2])) / 1024, 2)." kB/s | TPS ".$this->getTPS()."\x07"; } $this->interface->bandwidth = array(0, 0, $time); } @@ -492,12 +491,9 @@ class MainServer{ public function packetHandler(Packet $packet){ $data =& $packet; $CID = MainServer::clientID($packet->ip, $packet->port); - if(isset($this->clients[$CID])){ - $this->clients[$CID]->handlePacket($packet); + if(isset(Player::$list[$CID])){ + Player::$list[$CID]->handlePacket($packet); }else{ - if($this->handle("server.noauthpacket.".$packet->pid(), $packet) === false){ - return; - } switch($packet->pid()){ case RakNetInfo::UNCONNECTED_PING: case RakNetInfo::UNCONNECTED_PING_OPEN_CONNECTIONS: @@ -523,7 +519,7 @@ class MainServer{ $pk = new RakNetPacket(RakNetInfo::UNCONNECTED_PONG); $pk->pingID = $packet->pingID; $pk->serverID = $this->serverID; - $pk->serverType = $this->serverType . $this->name . " [".count($this->clients)."/".$this->maxClients."] ".$txt; + $pk->serverType = $this->serverType . $this->name . " [".count(Player::$list)."/".$this->maxClients."] ".$txt; $pk->ip = $packet->ip; $pk->port = $packet->port; $this->send($pk); @@ -551,7 +547,7 @@ class MainServer{ break; } - $this->clients[$CID] = new Player($packet->clientID, $packet->ip, $packet->port, $packet->mtuSize); //New Session! + 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->port = $this->port; diff --git a/src/Player.php b/src/Player.php index 6f34287c3..9f38c8c62 100644 --- a/src/Player.php +++ b/src/Player.php @@ -24,6 +24,8 @@ require_once("Entity.php"); /***REM_END***/ class Player extends PlayerEntity{ + public static $list = array(); + private $recoveryQueue = array(); private $receiveQueue = array(); private $resendQueue = array(); @@ -33,18 +35,18 @@ class Player extends PlayerEntity{ private $bufferLen = 0; private $nextBuffer = 0; private $evid = array(); - private $lastMovement = 0; - private $forceMovement = false; + protected $lastMovement = 0; + protected $forceMovement = false; private $timeout; - private $connected = true; - private $clientID; - private $ip; - private $port; + protected $connected = true; + protected $clientID; + protected $ip; + protected $port; private $counter = array(0, 0, 0, 0); private $username; private $iusername; private $startAction = false; - private $isSleeping = false; + protected $isSleeping = false; public $auth = false; public $CID; public $MTU; @@ -71,6 +73,7 @@ class Player extends PlayerEntity{ private $spawnPosition; private $packetLoss = 0; private $lastChunk = false; + private $hunkScheduled = 0; public $lastCorrect; private $bigCnt; private $packetStats; @@ -87,6 +90,35 @@ class Player extends PlayerEntity{ } return null; } + + public static function get($name, $alike = true, $multiple = false){ + $name = trim(strtolower($name)); + if($name === ""){ + return false; + } + $players = array(); + foreach(Player::$list as $player){ + if($multiple === false and $player->iusername === $name){ + return $player; + }elseif(strpos($player->iusername, $name) !== false){ + $players[$player->CID] = $player; + } + } + + if($multiple === false){ + if(count($players) > 0){ + return array_shift($players); + }else{ + return false; + } + }else{ + return $players; + } + } + + public static function getAll(){ + return Player::$list; + } /** * @param integer $clientID @@ -101,6 +133,7 @@ class Player extends PlayerEntity{ $this->lastBreak = microtime(true); $this->clientID = $clientID; $this->CID = MainServer::clientID($ip, $port); + Player::$list[$this->CID] = $this; $this->ip = $ip; $this->port = $port; $this->spawnPosition = $this->server->spawn; @@ -177,14 +210,24 @@ class Player extends PlayerEntity{ } } - public function getNextChunk(){ + public function getNextChunk($force = false, $ev = null){ if($this->connected === false){ return false; } + if($ev === "server.schedule"){ + --$this->chunkScheduled; + if($this->chunkScheduled < 0){ + $this->chunkScheduled = 0; + } + } + foreach($this->chunkCount as $count => $t){ if(isset($this->recoveryQueue[$count]) or isset($this->resendQueue[$count])){ - $this->server->schedule(MAX_CHUNK_RATE, array($this, "getNextChunk")); + if($this->chunkScheduled === 0){ + $this->server->schedule(MAX_CHUNK_RATE, array($this, "getNextChunk")); + ++$this->chunkScheduled; + } return; }else{ unset($this->chunkCount[$count]); @@ -203,7 +246,9 @@ class Player extends PlayerEntity{ $c = key($this->chunksOrder); $d = @$this->chunksOrder[$c]; if($c === null or $d === null){ - $this->server->schedule(40, array($this, "getNextChunk")); + if($this->chunkScheduled === 0){ + $this->server->schedule(40, array($this, "getNextChunk")); + } return false; } unset($this->chunksOrder[$c]); @@ -236,7 +281,10 @@ class Player extends PlayerEntity{ $this->lastChunk = array($X, $Z); - $this->server->schedule(MAX_CHUNK_RATE, array($this, "getNextChunk")); + if($this->chunkScheduled === 0 or $force === true){ + $this->server->schedule(MAX_CHUNK_RATE, array($this, "getNextChunk")); + ++$this->chunkScheduled; + } } public function save(){ @@ -296,6 +344,7 @@ class Player extends PlayerEntity{ $this->sendChat("You have been kicked. Reason: ".$reason."\n"); $this->sendBuffer(); $this->directDataPacket(new DisconnectPacket); + unset(Player::$list[$this->CID]); $this->connected = false; $this->level->freeAllChunks($this); $this->loggedIn = false; @@ -305,7 +354,6 @@ class Player extends PlayerEntity{ $this->receiveQueue = array(); $this->resendQueue = array(); $this->ackQueue = array(); - unset($this->server->clients[$this->CID]); if($this->username != "" and ($this->data instanceof Config)){ //TODO //$this->saveOffline($player->data); @@ -333,7 +381,7 @@ class Player extends PlayerEntity{ * @return boolean */ public function sleepOn(Vector3 $pos){ - foreach($this->server->api->player->getAll($this->level) as $p){ + foreach($this->level->getPlayers() as $p){ if($p->isSleeping instanceof Vector3){ if($pos->distance($p->isSleeping) <= 0.1){ return false; @@ -341,7 +389,7 @@ class Player extends PlayerEntity{ } } $this->isSleeping = $pos; - $this->teleport(new Position($pos->x + 0.5, $pos->y + 1, $pos->z + 0.5, $this->level), false, false, false, false); + $this->teleport(new Position($pos->x + 0.5, $pos->y + 1, $pos->z + 0.5, $this->level)); if($this->entity instanceof Entity){ $this->entity->updateMetadata(); } @@ -360,13 +408,13 @@ class Player extends PlayerEntity{ public function checkSleep(){ if($this->isSleeping !== false){ if($this->server->api->time->getPhase($this->level) === "night"){ - foreach($this->server->api->player->getAll($this->level) as $p){ + foreach($this->level->getPlayers() as $p){ if($p->isSleeping === false){ return false; } } $this->server->api->time->set("day", $this->level); - foreach($this->server->api->player->getAll($this->level) as $p){ + foreach($this->level->getPlayers() as $p){ $p->stopSleep(); } } @@ -899,121 +947,6 @@ class Player extends PlayerEntity{ * * @return boolean */ - public function teleport(Vector3 $pos, $yaw = false, $pitch = false, $terrain = true, $force = true){ - if($this->level instanceof Level){ - if($yaw === false){ - $yaw = $this->yaw; - } - if($pitch === false){ - $pitch = $this->pitch; - } - if($this->server->api->dhandle("player.teleport", array("player" => $this, "target" => $pos)) === false){ - return false; - } - - /*if($pos instanceof Position and $pos->level instanceof Level and $pos->level !== $this->level){ - if($this->server->api->dhandle("player.teleport.level", array("player" => $this, "origin" => $this->level, "target" => $pos->level)) === false){ - return false; - } - - foreach($this->level->getEntities() as $e){ - if($e !== $this->entity){ - if($e->player instanceof Player){ - $pk = new MoveEntityPacket_PosRot; - $pk->eid = $this->entity->eid; - $pk->x = -256; - $pk->y = 128; - $pk->z = -256; - $pk->yaw = 0; - $pk->pitch = 0; - $e->player->dataPacket($pk); - - $pk = new MoveEntityPacket_PosRot; - $pk->eid = $e->eid; - $pk->x = -256; - $pk->y = 128; - $pk->z = -256; - $pk->yaw = 0; - $pk->pitch = 0; - $this->dataPacket($pk); - }else{ - $pk = new RemoveEntityPacket; - $pk->eid = $e->eid; - $this->dataPacket($pk); - } - } - } - - - $this->level->freeAllChunks($this); - $this->level = $pos->level; - $this->chunksLoaded = array(); - $this->entity->spawnToAll(); - //TODO - $this->server->api->entity->spawnAll($this); - - $pk = new SetTimePacket; - $pk->time = $this->level->getTime(); - $this->dataPacket($pk); - $terrain = true; - - foreach($this->level->getPlayers() as $player){ - if($player !== $this and $player->entity instanceof Entity){ - $pk = new MoveEntityPacket_PosRot; - $pk->eid = $player->entity->eid; - $pk->x = $player->entity->x; - $pk->y = $player->entity->y; - $pk->z = $player->entity->z; - $pk->yaw = $player->entity->yaw; - $pk->pitch = $player->entity->pitch; - $this->dataPacket($pk); - - $pk = new PlayerEquipmentPacket; - $pk->eid = $this->eid; - $pk->item = $this->getSlot($this->slot)->getID(); - $pk->meta = $this->getSlot($this->slot)->getMetadata(); - $pk->slot = 0; - $player->dataPacket($pk); - $this->sendArmor($player); - - $pk = new PlayerEquipmentPacket; - $pk->eid = $player->eid; - $pk->item = $player->getSlot($player->slot)->getID(); - $pk->meta = $player->getSlot($player->slot)->getMetadata(); - $pk->slot = 0; - $this->dataPacket($pk); - $player->sendArmor($this); - } - } - }*/ - - $this->lastCorrect = $pos; - /*$this->entity->fallY = false; - $this->entity->fallStart = false;*/ - $this->setPosition($pos, $yaw, $pitch); - /*$this->entity->resetSpeed(); - $this->entity->updateLast(); - $this->entity->calculateVelocity();*/ - if($terrain === true){ - $this->orderChunks(); - $this->getNextChunk(); - } - //$this->entity->check = true; - if($force === true){ - $this->forceMovement = $pos; - } - } - - $pk = new MovePlayerPacket; - $pk->eid = 0; - $pk->x = $pos->x; - $pk->y = $pos->y; - $pk->z = $pos->z; - $pk->bodyYaw = $yaw; - $pk->pitch = $pitch; - $pk->yaw = $yaw; - $this->dataPacket($pk); - } public function getGamemode(){ switch($this->gamemode){ @@ -1300,7 +1233,7 @@ class Player extends PlayerEntity{ $this->username = $packet->username; $this->iusername = strtolower($this->username); $this->loginData = array("clientId" => $packet->clientId, "loginData" => $packet->loginData); - if(count($this->server->clients) > $this->server->maxClients and !$this->server->api->ban->isOp($this->iusername)){ + if(count(Player::$list) > $this->server->maxClients and !$this->server->api->ban->isOp($this->iusername)){ $this->close("server is full!", false); return; } @@ -1335,13 +1268,13 @@ class Player extends PlayerEntity{ } $this->loggedIn = true; - $u = $this->server->api->player->get($this->iusername, false); - if($u !== false){ - $u->close("logged in from another location"); - } - if(!isset($this->CID) or $this->CID == null){ - console("[DEBUG] Player ".$this->username." does not have a CID", true, true, 2); - $this->CID = Utils::readLong(Utils::getRandomBytes(8, false)); + $u = Player::get($this->iusername, false, true); + if(count($u) > 0){ + foreach($u as $p){ + if($p !== $this){ + $p->close("logged in from another location"); + } + } } $this->server->api->player->add($this->CID); @@ -1423,9 +1356,26 @@ class Player extends PlayerEntity{ 1 => new NBTTag_Double(1, $this->data->get("position")["y"]), 2 => new NBTTag_Double(2, $this->data->get("position")["z"]) )), - "NameTag" => new NBTTag_String("NameTag", $this->username), + "Motion" => new NBTTag_List("Motion", array( + 0 => new NBTTag_Double(0, 0.0), + 1 => new NBTTag_Double(1, 0.0), + 2 => new NBTTag_Double(2, 0.0) + )), + "Rotation" => new NBTTag_List("Rotation", array( + 0 => new NBTTag_Float(0, 0.0), + 1 => new NBTTag_Float(1, 0.0) + )), + "FallDistance" => new NBTTag_Float("FallDistance", 0.0), + "Fire" => new NBTTag_Short("Fire", 0), + "Air" => new NBTTag_Short("Air", 0), + "OnGround" => new NBTTag_Byte("OnGround", 1), + "Invulnerable" => new NBTTag_Byte("Invulnerable", 0), + + "NameTag" => new NBTTag_String("NameTag", $this->username), ))); $this->namedtag->Pos->setTagType(NBTTag::TAG_Double); + $this->namedtag->Motion->setTagType(NBTTag::TAG_Double); + $this->namedtag->Rotation->setTagType(NBTTag::TAG_Float); if(($level = $this->server->api->level->get($this->data->get("spawn")["level"])) !== false){ $this->spawnPosition = new Position($this->data->get("spawn")["x"], $this->data->get("spawn")["y"], $this->data->get("spawn")["z"], $level); @@ -1513,13 +1463,13 @@ class Player extends PlayerEntity{ 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 instanceof Vector3){ if($this->forceMovement->distance($newPos) <= 0.7){ $this->forceMovement = false; }else{ - $this->teleport($this->forceMovement, $this->entity->yaw, $this->entity->pitch, false); + $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){ @@ -1529,7 +1479,7 @@ class Player extends PlayerEntity{ console("[WARNING] ".$this->username." moved too quickly!"); } }else{*/ - $this->setPosition($newPos, $packet->yaw, $packet->pitch); + $this->setPositionAndRotation($newPos, $packet->yaw, $packet->pitch); //} } break; @@ -2427,14 +2377,4 @@ class Player extends PlayerEntity{ return array(); } - /** - * @return string - */ - function __toString(){ - if($this->username != ""){ - return $this->username; - } - return $this->clientID; - } - } diff --git a/src/entity/HumanEntity.php b/src/entity/HumanEntity.php index 57d438614..ef4f661e6 100644 --- a/src/entity/HumanEntity.php +++ b/src/entity/HumanEntity.php @@ -27,6 +27,8 @@ class HumanEntity extends CreatureEntity implements ProjectileSourceEntity{ if(isset($this->namedtag->NameTag)){ $this->nameTag = $this->namedtag->NameTag; } + $this->height = 1.8; //Or 1.62? + $this->width = 0.6; } public function spawnTo(Player $player){ @@ -67,6 +69,13 @@ class HumanEntity extends CreatureEntity implements ProjectileSourceEntity{ $this->sendArmor($player); } + public function despawnTo(Player $player){ + $pk = new RemovePlayerPacket; + $pk->eid = $this->id; + $pk->clientID = 0; + $player->dataPacket($pk); + } + public function getMetadata(){ return array(); } diff --git a/src/event/EntityEvent.php b/src/event/EntityEvent.php new file mode 100644 index 000000000..3fee3e1b8 --- /dev/null +++ b/src/event/EntityEvent.php @@ -0,0 +1,32 @@ +entity = $entity; + } + + public function getEntity(){ + return $this->entity; + } +} \ No newline at end of file diff --git a/src/event/entity/EntityLevelChangeEvent.php b/src/event/entity/EntityLevelChangeEvent.php new file mode 100644 index 000000000..7ac26f15e --- /dev/null +++ b/src/event/entity/EntityLevelChangeEvent.php @@ -0,0 +1,42 @@ +entity = $entity; + $this->originLevel = $originLevel; + $this->targetLevel = $targetLevel; + } + + public function getOrigin(){ + return $this->originLevel; + } + + public function getTarget(){ + return $this->targetLevel; + } +} \ No newline at end of file diff --git a/src/event/entity/EntityMotionEvent.php b/src/event/entity/EntityMotionEvent.php new file mode 100644 index 000000000..72ad7aab0 --- /dev/null +++ b/src/event/entity/EntityMotionEvent.php @@ -0,0 +1,38 @@ +entity = $entity; + $this->mot = $mot; + } + + public function getVector(){ + return $this->mot; + } + + +} \ No newline at end of file diff --git a/src/event/entity/EntityMoveEvent.php b/src/event/entity/EntityMoveEvent.php new file mode 100644 index 000000000..e2a57e857 --- /dev/null +++ b/src/event/entity/EntityMoveEvent.php @@ -0,0 +1,38 @@ +entity = $entity; + $this->pos = $pos; + } + + public function getVector(){ + return $this->pos; + } + + +} \ No newline at end of file diff --git a/src/nbt/NBT.php b/src/nbt/NBT.php index fadd82594..1c5a942fd 100644 --- a/src/nbt/NBT.php +++ b/src/nbt/NBT.php @@ -138,11 +138,11 @@ class NBT implements ArrayAccess{ } public function getByte(){ - return Utils::readByte($this->get(1), true); + return ord($this->get(1)); } public function putByte($v){ - $this->buffer .= Utils::writeByte($v); + $this->buffer .= chr($v); } public function getShort(){ diff --git a/src/network/query/QueryHandler.php b/src/network/query/QueryHandler.php index bc7286443..422063d1b 100644 --- a/src/network/query/QueryHandler.php +++ b/src/network/query/QueryHandler.php @@ -69,7 +69,7 @@ class QueryHandler{ "server_engine" => "PocketMine-MP ".MAJOR_VERSION, "plugins" => $plist, "map" => $this->server->api->level->getDefault()->getName(), - "numplayers" => count($this->server->clients), + "numplayers" => count(Player::$list), "maxplayers" => $this->server->maxClients, "whitelist" => $this->server->api->getProperty("white-list") === true ? "on":"off", "hostport" => $this->server->api->getProperty("server-port"), @@ -79,7 +79,7 @@ class QueryHandler{ $str .= $key."\x00".$value."\x00"; } $str .= "\x00\x01player_\x00\x00"; - foreach($this->server->clients as $player){ + foreach(Player::$list as $player){ if($player->username != ""){ $str .= $player->username."\x00"; } @@ -127,7 +127,7 @@ class QueryHandler{ } $pk->payload = $this->longData; }else{ - $pk->payload = $this->server->name."\x00".(($this->server->gamemode & 0x01) === 0 ? "SMP":"CMP")."\x00".$this->server->api->level->getDefault()->getName()."\x00".count($this->server->clients)."\x00".$this->server->maxClients."\x00".Utils::writeLShort($this->server->api->getProperty("server-port")).$this->server->api->getProperty("server-ip", "0.0.0.0")."\x00"; + $pk->payload = $this->server->name."\x00".(($this->server->gamemode & 0x01) === 0 ? "SMP":"CMP")."\x00".$this->server->api->level->getDefault()->getName()."\x00".count(Player::$list)."\x00".$this->server->maxClients."\x00".Utils::writeLShort($this->server->api->getProperty("server-port")).$this->server->api->getProperty("server-ip", "0.0.0.0")."\x00"; } $pk->encode(); $this->server->send($pk); diff --git a/src/tile/ContainerTileTrait.php b/src/tile/ContainerTileTrait.php index 8873a6746..d40ec178c 100644 --- a/src/tile/ContainerTileTrait.php +++ b/src/tile/ContainerTileTrait.php @@ -51,7 +51,7 @@ trait ContainerTileTrait{ $slots = array(); if(is_array($player->windows[$id])){ - $all = $this->server->api->player->getAll($this->level); + $all = $this->level->getPlayers(); foreach($player->windows[$id] as $ob){ $pk = new TileEventPacket; $pk->x = $ob->x; @@ -76,7 +76,7 @@ trait ContainerTileTrait{ $pk->z = $this->z; $pk->case1 = 1; $pk->case2 = 2; - $this->server->api->player->broadcastPacket($this->server->api->player->getAll($this->level), $pk); + $this->server->api->player->broadcastPacket($this->level->getPlayers(), $pk); for($s = 0; $s < ChestTile::SLOTS; ++$s){ $slot = $this->getSlot($s); if($slot->getID() > AIR and $slot->count > 0){