diff --git a/src/API/BlockAPI.php b/src/API/BlockAPI.php index 58e2ae6e7..e162ac1fe 100644 --- a/src/API/BlockAPI.php +++ b/src/API/BlockAPI.php @@ -317,13 +317,13 @@ class BlockAPI{ } private function cancelAction(Block $block, Player $player, $send = true){ - $player->dataPacket(MC_UPDATE_BLOCK, array( - "x" => $block->x, - "y" => $block->y, - "z" => $block->z, - "block" => $block->getID(), - "meta" => $block->getMetadata() - )); + $pk = new UpdateBlockPacket; + $pk->x = $block->x; + $pk->y = $block->y; + $pk->z = $block->z; + $pk->block = $block->getID(); + $pk->meta = $block->getMetadata(); + $player->dataPacket($pk); if($send === true){ $player->sendInventorySlot($player->slot); } @@ -459,363 +459,6 @@ class BlockAPI{ return false; } - /* - - public function flowLavaOn($source, $face){ - $down = 0; - if($face === BlockFace::BOTTOM){ - $level = 0; - $down = 1; - }else{ - $level = ($source[1] & 0x07) + 2; - if($level > 0x07){ - return false; - } - } - $spread = $this->server->api->level->getBlockFace($source, $face); - if(($source[0] === 10 or $source[0] === 11) and $spread[0] === 10){ - if($level < ($spread[1] & 0x07)){ - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $spread[2][0], - "y" => $spread[2][1], - "z" => $spread[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $spread[0], $level | $down, false); - return true; - } - }elseif($spread[0] === 9 or $spread[0] === 8){ - if($source[0] === 11){ - $this->server->api->level->setBlock($source[2][0], $source[2][1], $source[2][2], 49, 0); - }elseif($face === 0){ - $this->server->api->level->setBlock($source[2][0], $source[2][1], $source[2][2], 1, 0); - }else{ - $this->server->api->level->setBlock($source[2][0], $source[2][1], $source[2][2], 4, 0); - } - return true; - }elseif(isset(Material::$flowable[$spread[0]])){ - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $spread[2][0], - "y" => $spread[2][1], - "z" => $spread[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], 10, $level | $down, false); - return true; - }elseif(($source[1] & 0x08) === 0x08){ - $this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $source[0], $source[1] & 0x07, false); - return true; - } - return false; - } - - public function flowWaterOn($source, $face, &$spread = null){ - $down = 0; - if($face === BlockFace::BOTTOM){ - $level = 0; - $down = 1; - }else{ - $level = ($source[1] & 0x07) + 1; - if($level > 0x07){ - return false; - } - } - $spread = $this->server->api->level->getBlockFace($source, $face); - if(($source[0] === 8 or $source[0] === 9) and $spread[0] === 8){ - if($level < ($spread[1] & 0x07)){ - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $spread[2][0], - "y" => $spread[2][1], - "z" => $spread[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $spread[0], $level | $down, false); - return true; - } - }elseif($spread[0] === 11){ - $this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], 49, 0, true); - return true; - }elseif($spread[0] === 10){ - if($face === 0 or ($spread[1] & 0x08) === 0){ - $this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], 4, 0, true); - return true; - } - }elseif(isset(Material::$flowable[$spread[0]])){ - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $spread[2][0], - "y" => $spread[2][1], - "z" => $spread[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], 8, $level | $down, false); - return true; - }elseif(($source[1] & 0x08) === 0x08){ - $this->server->api->level->setBlock($spread[2][0], $spread[2][1], $spread[2][2], $source[0], $source[1] & 0x07, false); - return true; - } - return false; - } - - public function updateBlock($x, $y, $z, $type = BLOCK_UPDATE_NORMAL){ - $block = $this->server->api->level->getBlock($x, $y, $z); - $changed = false; - - switch($block[0]){ - case 8: - case 9: - $faces = array(); - if(!$this->flowWaterOn($block, 0, $floor) or $block[0] === 9){ - $this->flowWaterOn($block, 2, $faces[0]); - $this->flowWaterOn($block, 3, $faces[1]); - $this->flowWaterOn($block, 4, $faces[2]); - $this->flowWaterOn($block, 5, $faces[3]); - } - if($block[0] === 8){ - //Source creation - if(!isset(Material::$flowable[$floor[0]])){ - $sources = 0; - foreach($faces as $i => $b){ - if($b[0] === 9){ - ++$sources; - } - } - if($sources >= 2){ - $this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], 9, 0, false); - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1], - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - break; - } - } - - $drained = true; - $level = $block[1] & 0x07; - $up = $this->server->api->level->getBlockFace($block, BlockFace::UP); - if($up[0] === 8 or $up[0] === 9){ - $drained = false; - }else{ - $b = $this->server->api->level->getBlockFace($block, BlockFace::NORTH); - if($b[0] === 9 or ($b[0] === 8 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){ - $drained = false; - }else{ - $b = $this->server->api->level->getBlockFace($block, BlockFace::SOUTH); - if($b[0] === 9 or ($b[0] === 8 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){ - $drained = false; - }else{ - $b = $this->server->api->level->getBlockFace($block, BlockFace::EAST); - if($b[0] === 9 or ($b[0] === 8 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){ - $drained = false; - }else{ - $b = $this->server->api->level->getBlockFace($block, BlockFace::WEST); - if($b[0] === 9 or ($b[0] === 8 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){ - $drained = false; - } - } - } - } - } - if($drained === true){ - ++$level; - if($level > 0x07){ - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $block[2][0] + 1, - "y" => $block[2][1], - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $block[2][0] - 1, - "y" => $block[2][1], - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1], - "z" => $block[2][2] + 1, - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1], - "z" => $block[2][2] - 1, - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1] - 1, - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], 0, 0, false); - }else{ - $block[1] = ($block[1] & 0x08) | $level; - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $block[2][0] + 1, - "y" => $block[2][1], - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $block[2][0] - 1, - "y" => $block[2][1], - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1], - "z" => $block[2][2] + 1, - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1], - "z" => $block[2][2] - 1, - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1] - 1, - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(10, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1], - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], $block[0], $block[1], false); - } - } - } - break; - case 10: - case 11: - if(!$this->flowLavaOn($block, 0) or $block[0] === 11){ - $this->flowLavaOn($block, 2); - $this->flowLavaOn($block, 3); - $this->flowLavaOn($block, 4); - $this->flowLavaOn($block, 5); - } - if($block[0] === 10){ - $drained = true; - $level = $block[1] & 0x07; - $up = $this->server->api->level->getBlockFace($block, BlockFace::UP); - if($up[0] === 10 or $up[0] === 11){ - $drained = false; - }else{ - $b = $this->server->api->level->getBlockFace($block, BlockFace::NORTH); - if($b[0] === 11 or ($b[0] === 10 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){ - $drained = false; - }else{ - $b = $this->server->api->level->getBlockFace($block, BlockFace::SOUTH); - if($b[0] === 11 or ($b[0] === 10 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){ - $drained = false; - }else{ - $b = $this->server->api->level->getBlockFace($block, BlockFace::EAST); - if($b[0] === 11 or ($b[0] === 10 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){ - $drained = false; - }else{ - $b = $this->server->api->level->getBlockFace($block, BlockFace::WEST); - if($b[0] === 11 or ($b[0] === 10 and ($b[1] & 0x08) === 0 and ($b[1] & 0x07) < $level)){ - $drained = false; - } - } - } - } - } - if($drained === true){ - ++$level; - if($level > 0x07){ - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $block[2][0] + 1, - "y" => $block[2][1], - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $block[2][0] - 1, - "y" => $block[2][1], - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1], - "z" => $block[2][2] + 1, - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1], - "z" => $block[2][2] - 1, - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1] - 1, - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], 0, 0, false); - }else{ - $block[1] = ($block[1] & 0x08) | $level; - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $block[2][0] + 1, - "y" => $block[2][1], - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $block[2][0] - 1, - "y" => $block[2][1], - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1], - "z" => $block[2][2] + 1, - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1], - "z" => $block[2][2] - 1, - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1] - 1, - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->schedule(20, array($this, "blockScheduler"), array( - "x" => $block[2][0], - "y" => $block[2][1], - "z" => $block[2][2], - "type" => BLOCK_UPDATE_NORMAL, - )); - $this->server->api->level->setBlock($block[2][0], $block[2][1], $block[2][2], $block[0], $block[1], false); - } - } - } - - break; - } - if($type === BLOCK_TYPE_SCHEDULED){ - $type = BLOCK_UPDATE_WEAK; - } - if($changed === true){ - $this->updateBlocksAround($x, $y, $z, $type); - } - }*/ - public function blockUpdateAround(Position $pos, $type = BLOCK_UPDATE_NORMAL, $delay = false){ if($delay !== false){ $this->scheduleBlockUpdate($pos->getSide(0), $delay, $type); diff --git a/src/API/EntityAPI.php b/src/API/EntityAPI.php index 55bff773a..3c3ec38e8 100644 --- a/src/API/EntityAPI.php +++ b/src/API/EntityAPI.php @@ -157,14 +157,14 @@ class EntityAPI{ $entity->closed = true; $this->server->query("DELETE FROM entities WHERE EID = ".$eid.";"); if($entity->class === ENTITY_PLAYER){ - $this->server->api->player->broadcastPacket($this->server->api->player->getAll(), MC_REMOVE_PLAYER, array( - "clientID" => 0, - "eid" => $entity->eid, - )); + $pk = new RemovePlayerPacket; + $pk->eid = $entity->eid; + $pk->clientID = 0; + $this->server->api->player->broadcastPacket($this->server->api->player->getAll(), $pk); }else{ - $this->server->api->player->broadcastPacket($this->server->api->player->getAll($entity->level), MC_REMOVE_ENTITY, array( - "eid" => $entity->eid, - )); + $pk = new RemoveEntityPacket; + $pk->eid = $entity->eid; + $this->server->api->player->broadcastPacket($this->server->api->player->getAll($entity->level), $pk); } $this->server->api->dhandle("entity.remove", $entity); $entity = null; diff --git a/src/API/PlayerAPI.php b/src/API/PlayerAPI.php index 38a88c153..2a3a2bb1a 100644 --- a/src/API/PlayerAPI.php +++ b/src/API/PlayerAPI.php @@ -353,11 +353,9 @@ class PlayerAPI{ return $this->server->clients; } - public function broadcastPacket(array $players, $id, $data = array()){ - $data = new CustomPacketHandler($id, "", $data, true); - $packet = array("raw" => chr($id).$data->raw); + public function broadcastPacket(array $players, RakNetDataPacket $packet){ foreach($players as $p){ - $p->dataPacket(false, $packet); + $p->dataPacket(clone $packet); } } @@ -404,14 +402,14 @@ class PlayerAPI{ if($p !== $player and ($p->entity instanceof Entity)){ $p->entity->spawn($player); if($p->level !== $player->level){ - $player->dataPacket(MC_MOVE_ENTITY_POSROT, array( - "eid" => $p->entity->eid, - "x" => -256, - "y" => 128, - "z" => -256, - "yaw" => 0, - "pitch" => 0, - )); + $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); } } } @@ -422,14 +420,14 @@ class PlayerAPI{ if($p !== $player and ($p->entity instanceof Entity) and ($player->entity instanceof Entity)){ $player->entity->spawn($p); if($p->level !== $player->level){ - $p->dataPacket(MC_MOVE_ENTITY_POSROT, array( - "eid" => $player->entity->eid, - "x" => -256, - "y" => 128, - "z" => -256, - "yaw" => 0, - "pitch" => 0, - )); + $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 603ab2fee..9aa7c7289 100644 --- a/src/API/ServerAPI.php +++ b/src/API/ServerAPI.php @@ -28,7 +28,8 @@ class ServerAPI{ private $apiList = array(); private $asyncCnt = 0; private $rcon; - private $query; + + public $query; //TODO: Instead of hard-coding functions, use PHPDoc-compatible methods to load APIs. @@ -97,6 +98,14 @@ class ServerAPI{ @mkdir(DATA_PATH."players/", 0755); @mkdir(DATA_PATH."worlds/", 0755); @mkdir(DATA_PATH."plugins/", 0755); + + //Init all the events + foreach(get_declared_classes() as $class){ + if(is_subclass_of($class, "BaseEvent") and property_exists($class, "handlers") and property_exists($class, "handlerPriority")){ + $class::unregisterAll(); + } + } + $version = new VersionString(); console("[INFO] Starting Minecraft PE server version ".FORMAT_AQUA.CURRENT_MINECRAFT_VERSION); @@ -134,28 +143,25 @@ class ServerAPI{ )); $this->parseProperties(); + + //Load advanced properties define("DEBUG", $this->getProperty("debug", 1)); define("ADVANCED_CACHE", $this->getProperty("enable-advanced-cache", false)); - if($this->getProperty("port") !== false){ - $this->setProperty("server-port", $this->getProperty("port")); - $this->config->remove("port"); - $this->config->remove("invisible"); + define("MAX_CHUNK_RATE", 20 / $this->getProperty("max-chunks-per-second", 8)); //Default rate ~512 kB/s + if(ADVANCED_CACHE == true){ + console("[INFO] Advanced cache enabled"); } + if($this->getProperty("upnp-forwarding") == true){ + console("[INFO] [UPnP] Trying to port forward..."); + UPnP_PortForward($this->getProperty("server-port")); + } + $this->server = new PocketMinecraftServer($this->getProperty("server-name"), $this->getProperty("gamemode"), ($seed = $this->getProperty("level-seed")) != "" ? (int) $seed:false, $this->getProperty("server-port"), ($ip = $this->getProperty("server-ip")) != "" ? $ip:"0.0.0.0"); $this->server->api = $this; self::$serverRequest = $this->server; console("[INFO] This server is running PocketMine-MP version ".($version->isDev() ? FORMAT_YELLOW:"").MAJOR_VERSION.FORMAT_RESET." \"".CODENAME."\" (MCPE: ".CURRENT_MINECRAFT_VERSION.") (API ".CURRENT_API_VERSION.")", true, true, 0); console("[INFO] PocketMine-MP is distributed under the LGPL License", true, true, 0); - if(ADVANCED_CACHE == true){ - console("[INFO] Advanced cache enabled"); - } - - if($this->getProperty("upnp-forwarding") === true){ - console("[INFO] [UPnP] Trying to port forward..."); - UPnP_PortForward($this->getProperty("server-port")); - } - if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){ console("[INFO] Checking for new server version"); console("[INFO] Last check: ".FORMAT_AQUA.date("Y-m-d H:i:s", $this->getProperty("last-update"))."\x1b[0m"); @@ -257,7 +263,7 @@ class ServerAPI{ "php_version" => PHP_VERSION, "version" => MAJOR_VERSION, "mc_version" => CURRENT_MINECRAFT_VERSION, - "protocol" => CURRENT_PROTOCOL, + "protocol" => ProtocolInfo::CURRENT_PROTOCOL, "online" => count($this->server->clients), "max" => $this->server->maxClients, "plugins" => $plist, @@ -349,7 +355,7 @@ class ServerAPI{ } if($this->getProperty("enable-query") === true){ - $this->query = new Query(); + $this->query = new QueryHandler(); } CraftingRecipes::init(); $this->server->init(); diff --git a/src/BaseEvent.php b/src/BaseEvent.php new file mode 100644 index 000000000..fb65432f7 --- /dev/null +++ b/src/BaseEvent.php @@ -0,0 +1,135 @@ +eventName !== null ? get_class($this) : $this->eventName; + } + + final public function setPrioritySlot($slot){ + $this->prioritySlot = (int) $slot; + } + + final public function getPrioritySlot(){ + return (int) $this->prioritySlot; + } + + + public function isAllowed(){ + return ($this->status & 0x7FFFFFFF) === BaseEvent::ALLOW; + } + + public function setAllowed($forceAllow = false){ + $this->status = BaseEvent::ALLOW & ($forceAllow === true ? BaseEvent::FORCE : 0); + } + + public function isCancelled(){ + return ($this->status & 0x7FFFFFFF) === BaseEvent::DENY; + } + + public function setCancelled($forceCancel = false){ + if($this instanceof CancellableEvent){ + $this->status = BaseEvent::DENY & ($forceCancel === true ? BaseEvent::FORCE : 0); + } + return false; + } + + public function isNormal(){ + return $this->status === BaseEvent::NORMAL; + } + + public function setNormal(){ + $this->status = BaseEvent::NORMAL; + } + + public function isForced(){ + return ($this->status & BaseEvent::FORCE) > 0; + } + + public static function getHandlerList(){ + return static::$handlers; + } + + public static function getPriorityList(){ + return static::$handlerPriority; + } + + public static function unregisterAll(){ + static::$handlers = array(); + static::$handlerPriority = array(); + } + + public function register(callable $handler, $priority = EventPriority::NORMAL){ + if($priority < EventPriority::MONITOR or $priority > EventPriority::LOWEST){ + return false; + } + $identifier = Utils::getCallableIdentifier($handler); + if(isset(static::$handlers[$identifier])){ //Already registered + return false; + }else{ + static::$handlers[$identifier] = $handler; + if(!isset(static::$handlerPriority[(int) $priority])){ + static::$handlerPriority[(int) $priority] = array(); + } + static::$handlerPriority[(int) $priority][$identifier] = $handler; + return true; + } + } + + public function unregister(callable $handler, $priority = EventPriority::NORMAL){ + $identifier = Utils::getCallableIdentifier($handler); + if(isset(static::$handlers[$identifier])){ + if(isset(static::$handlerPriority[(int) $priority][$identifier])){ + unset(static::$handlerPriority[(int) $priority][$identifier]); + }else{ + for($priority = EventPriority::MONITOR; $priority <= EventPriority::LOWEST; ++$priority){ + unset(static::$handlerPriority[$priority][$identifier]); + if(count(static::$handlerPriority[$priority]) === 0){ + unset(static::$handlerPriority[$priority]); + } + } + } + unset(static::$handlers[$identifier]); + return true; + }else{ + return false; + } + } + +} \ No newline at end of file diff --git a/src/Player.php b/src/Player.php index 9520108d8..ae4f87d79 100644 --- a/src/Player.php +++ b/src/Player.php @@ -27,7 +27,8 @@ class Player{ private $resendQueue = array(); private $ackQueue = array(); private $receiveCount = -1; - private $buffer = ""; + private $buffer; + private $bufferLen = 0; private $nextBuffer = 0; private $evid = array(); private $lastMovement = 0; @@ -79,7 +80,7 @@ class Player{ public $lastCraft = 0; private $chunkCount = array(); private $received = array(); - public $realmsData = array(); + public $loginData = array(); /** @var \Level */ public $level; @@ -114,9 +115,11 @@ class Player{ $this->slot = 0; $this->hotbar = array(0, -1, -1, -1, -1, -1, -1, -1, -1); $this->packetStats = array(0,0); + $this->buffer = new RakNetPacket(RakNetInfo::DATA_PACKET_0); + $this->buffer->data = array(); $this->server->schedule(2, array($this, "handlePacketQueues"), array(), true); $this->server->schedule(20 * 60, array($this, "clearQueue"), array(), true); - $this->evid[] = $this->server->event("server.close", array($this, "close")); + $this->evid[] = $this->server->event("server.close", array($this, "close")); console("[DEBUG] New Session started with ".$ip.":".$port.". MTU ".$this->MTU.", Client ID ".$this->clientID, true, true, 2); } @@ -134,11 +137,11 @@ class Player{ $level = $pos->level; } $this->spawnPosition = new Position($pos->x, $pos->y, $pos->z, $level); - $this->dataPacket(MC_SET_SPAWN_POSITION, array( - "x" => (int) $this->spawnPosition->x, - "y" => (int) $this->spawnPosition->y, - "z" => (int) $this->spawnPosition->z, - )); + $pk = new SetSpawnPositionPacket; + $pk->x = (int) $this->spawnPosition->x; + $pk->y = (int) $this->spawnPosition->y; + $pk->z = (int) $this->spawnPosition->z; + $this->dataPacket($pk); } public function orderChunks(){ @@ -214,11 +217,11 @@ class Player{ $Yndex |= 1 << $iY; } } - $cnt = $this->dataPacket(MC_CHUNK_DATA, array( - "x" => $X, - "z" => $Z, - "data" => $this->level->getOrderedChunk($X, $Z, $Yndex), - )); + $pk = new ChunkDataPacket; + $pk->chunkX = $X; + $pk->chunkZ = $Z; + $pk->data = $this->level->getOrderedChunk($X, $Z, $Yndex); + $cnt = $this->dataPacket($pk); if($cnt === false){ return false; } @@ -288,7 +291,7 @@ class Player{ $reason = $reason == "" ? "server stop":$reason; $this->sendChat("You have been kicked. Reason: ".$reason."\n"); $this->sendBuffer(); - $this->directDataPacket(MC_DISCONNECT); + $this->directDataPacket(new DisconnectPacket); $this->connected = false; $this->level->freeAllChunks($this); $this->spawned = false; @@ -299,9 +302,8 @@ class Player{ $this->receiveQueue = array(); $this->resendQueue = array(); $this->ackQueue = array(); - $this->server->interface->stopChunked($this->CID); $this->server->api->player->remove($this->CID); - if($msg === true and $this->username != ""){ + if($msg === true and $this->username != "" and $this->spawned !== false){ $this->server->api->chat->broadcast($this->username." left the game"); } console("[INFO] ".FORMAT_AQUA.$this->username.FORMAT_RESET."[/".$this->ip.":".$this->port."] logged out due to ".$reason); @@ -492,23 +494,19 @@ class Player{ return; $s = (int) $s; if(!isset($this->inventory[$s])){ - $this->dataPacket(MC_CONTAINER_SET_SLOT, array( - "windowid" => 0, - "slot" => (int) $s, - "block" => AIR, - "stack" => 0, - "meta" => 0, - )); + $pk = new ContainerSetSlotPacket; + $pk->windowid = 0; + $pk->slot = (int) $s; + $pk->item = BlockAPI::getItem(AIR, 0, 0); + $this->dataPacket($pk); } $slot = $this->inventory[$s]; - $this->dataPacket(MC_CONTAINER_SET_SLOT, array( - "windowid" => 0, - "slot" => (int) $s, - "block" => $slot->getID(), - "stack" => $slot->count, - "meta" => $slot->getMetadata(), - )); + $pk = new ContainerSetSlotPacket; + $pk->windowid = 0; + $pk->slot = (int) $s; + $pk->item = $slot; + $this->dataPacket($pk); return true; } @@ -553,16 +551,17 @@ class Player{ if($data->class === TILE_FURNACE){ foreach($this->windows as $id => $w){ if($w === $data){ - $this->dataPacket(MC_CONTAINER_SET_DATA, array( - "windowid" => $id, - "property" => 0, //Smelting - "value" => floor($data->data["CookTime"]), - )); - $this->dataPacket(MC_CONTAINER_SET_DATA, array( - "windowid" => $id, - "property" => 1, //Fire icon - "value" => $data->data["BurnTicks"], - )); + $pk = new ContainerSetDataPacket; + $pk->windowid = $id; + $pk->property = 0; //Smelting + $pk->value = floor($data->data["CookTime"]); + $this->dataPacket($pk); + + $pk = new ContainerSetDataPacket; + $pk->windowid = $id; + $pk->property = 1; //Fire icon + $pk->value = $data->data["BurnTicks"]; + $this->dataPacket($pk); } } } @@ -572,13 +571,11 @@ class Player{ if($data["tile"]->level === $this->level){ foreach($this->windows as $id => $w){ if($w === $data["tile"]){ - $this->dataPacket(MC_CONTAINER_SET_SLOT, array( - "windowid" => $id, - "slot" => $data["slot"] + (isset($data["offset"]) ? $data["offset"]:0), - "block" => $data["slotdata"]->getID(), - "stack" => $data["slotdata"]->count, - "meta" => $data["slotdata"]->getMetadata(), - )); + $pk = new ContainerSetSlotPacket; + $pk->windowid = $id; + $pk->slot = $data["slot"] + (isset($data["offset"]) ? $data["offset"]:0); + $pk->item = $data["slotdata"]; + $this->dataPacket($pk); } } } @@ -589,13 +586,19 @@ class Player{ $this->sendArmor($this); break; } - $this->dataPacket(MC_PLAYER_ARMOR_EQUIPMENT, $data); + $pk = new PlayerArmorEquipmentPacket; + $pk->eid = $data["eid"]; + $pk->slots = $data["slots"]; + $this->dataPacket($pk); } break; case "player.pickup": if($data["eid"] === $this->eid){ $data["eid"] = 0; - $this->dataPacket(MC_TAKE_ITEM_ENTITY, $data); + $pk = new TakeItemEntityPacket; + $pk->eid = 0; + $pk->target = $data["entity"]->eid; + $this->dataPacket($pk); if(($this->gamemode & 0x01) === 0x00){ $this->addItem($data["entity"]->type, $data["entity"]->meta, $data["entity"]->stack, false); } @@ -608,7 +611,10 @@ class Player{ break; } }elseif($data["entity"]->level === $this->level){ - $this->dataPacket(MC_TAKE_ITEM_ENTITY, $data); + $pk = new TakeItemEntityPacket; + $pk->eid = $data["eid"]; + $pk->target = $data["entity"]->eid; + $this->dataPacket($pk); } break; case "player.equipment.change": @@ -616,28 +622,34 @@ class Player{ break; } $data["slot"] = 0; - $this->dataPacket(MC_PLAYER_EQUIPMENT, $data); + + $pk = new PlayerEquipmentPacket; + $pk->eid = $data["eid"]; + $pk->item = $data["item"]->getID(); + $pk->meta = $data["item"]->getMetadata(); + $pk->slot = $data["slot"]; + $this->dataPacket($pk); break; case "entity.motion": if($data->eid === $this->eid or $data->level !== $this->level){ break; } - $this->dataPacket(MC_SET_ENTITY_MOTION, array( - "eid" => $data->eid, - "speedX" => (int) ($data->speedX * 400), - "speedY" => (int) ($data->speedY * 400), - "speedZ" => (int) ($data->speedZ * 400), - )); + $pk = new SetEntityMotionPacket; + $pk->eid = $data->eid; + $pk->speedX = $data->speedX; + $pk->speedY = $data->speedY; + $pk->speedZ = $data->speedZ; + $this->dataPacket($pk); break; case "entity.animate": if($data["eid"] === $this->eid or $data["entity"]->level !== $this->level){ break; } - $this->dataPacket(MC_ANIMATE, array( - "eid" => $data["eid"], - "action" => $data["action"], //1 swing arm, - )); + $pk = new AnimatePacket; + $pk->eid = $data["eid"]; + $pk->action = $data["action"]; //1 swing arm, + $this->dataPacket($pk); break; case "entity.metadata": if($data->eid === $this->eid){ @@ -646,10 +658,10 @@ class Player{ $eid = $data->eid; } if($data->level === $this->level){ - $this->dataPacket(MC_SET_ENTITY_DATA, array( - "eid" => $eid, - "metadata" => $data->getMetadata(), - )); + $pk = new SetEntityDataPacket; + $pk->eid = $eid; + $pk->metadata = $data->getMetadata(); + $this->dataPacket($pk); } break; case "entity.event": @@ -659,10 +671,10 @@ class Player{ $eid = $data["entity"]->eid; } if($data["entity"]->level === $this->level){ - $this->dataPacket(MC_ENTITY_EVENT, array( - "eid" => $eid, - "event" => $data["event"], - )); + $pk = new EntityEventPacket; + $pk->eid = $eid; + $pk->event = $data["event"]; + $this->dataPacket($pk); } break; case "server.chat": @@ -706,11 +718,11 @@ class Player{ } } - if($m !== ""){ - $this->dataPacket(MC_CHAT, array( - "player" => ($author instanceof Player) ? $author->username:$author, - "message" => TextFormat::clean($m), //Colors not implemented :( - )); + if($m !== ""){ + $pk = new MessagePacket; + $pk->source = ($author instanceof Player) ? $author->username:$author; + $pk->message = TextFormat::clean($m); //Colors not implemented :( + $this->dataPacket($pk); } } } @@ -753,16 +765,16 @@ class Player{ */ $flags = 0; if(($this->gamemode & 0x02) === 0x02){ - $flags |= 0x01; //Not allow placing/breaking blocks, adventure mode + $flags |= 0x01; //Do not allow placing/breaking blocks, adventure mode } if($nametags !== false){ $flags |= 0x20; //Show Nametags } - - $this->dataPacket(MC_ADVENTURE_SETTINGS, array( - "flags" => $flags, - )); + + $pk = new AdventureSettingsPacket; + $pk->flags = $flags; + $this->dataPacket($pk); } /** @@ -902,26 +914,27 @@ class Player{ foreach($this->server->api->entity->getAll($this->level) as $e){ if($e !== $this->entity){ if($e->player instanceof Player){ - $e->player->dataPacket(MC_MOVE_ENTITY_POSROT, array( - "eid" => $this->entity->eid, - "x" => -256, - "y" => 128, - "z" => -256, - "yaw" => 0, - "pitch" => 0, - )); - $this->dataPacket(MC_MOVE_ENTITY_POSROT, array( - "eid" => $e->eid, - "x" => -256, - "y" => 128, - "z" => -256, - "yaw" => 0, - "pitch" => 0, - )); + $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{ - $this->dataPacket(MC_REMOVE_ENTITY, array( - "eid" => $e->eid, - )); + $pk = new RemoveEntityPacket; + $pk->eid = $e->eid; + $this->dataPacket($pk); } } } @@ -932,34 +945,37 @@ class Player{ $this->chunksLoaded = array(); $this->server->api->entity->spawnToAll($this->entity); $this->server->api->entity->spawnAll($this); - $this->dataPacket(MC_SET_TIME, array( - "time" => $this->level->getTime(), - )); + + $pk = new SetTimePacket; + $pk->time = $this->level->getTime(); + $this->dataPacket($pk); $terrain = true; foreach($this->server->api->player->getAll($this->level) as $player){ if($player !== $this and $player->entity instanceof Entity){ - $this->dataPacket(MC_MOVE_ENTITY_POSROT, array( - "eid" => $player->entity->eid, - "x" => $player->entity->x, - "y" => $player->entity->y, - "z" => $player->entity->z, - "yaw" => $player->entity->yaw, - "pitch" => $player->entity->pitch, - )); - $player->dataPacket(MC_PLAYER_EQUIPMENT, array( - "eid" => $this->eid, - "block" => $this->getSlot($this->slot)->getID(), - "meta" => $this->getSlot($this->slot)->getMetadata(), - "slot" => 0, - )); + $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); - $this->dataPacket(MC_PLAYER_EQUIPMENT, array( - "eid" => $player->eid, - "block" => $player->getSlot($player->slot)->getID(), - "meta" => $player->getSlot($player->slot)->getMetadata(), - "slot" => 0, - )); + + $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); } } @@ -981,15 +997,16 @@ class Player{ $this->forceMovement = $pos; } } - $this->dataPacket(MC_MOVE_PLAYER, array( - "eid" => 0, - "x" => $pos->x, - "y" => $pos->y, - "z" => $pos->z, - "bodyYaw" => $yaw, - "pitch" => $pitch, - "yaw" => $yaw, - )); + + $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(){ @@ -1106,14 +1123,15 @@ class Player{ $safeCount = (int) (($this->MTU - 1) / 4); $packetCnt = (int) ($ackCnt / $safeCount + 1); for($p = 0; $p < $packetCnt; ++$p){ - $acks = array(); + $pk = new RakNetPacket(RakNetInfo::ACK); + $pk->packets = array(); for($c = 0; $c < $safeCount; ++$c){ if(($k = array_pop($this->ackQueue)) === null){ break; } - $acks[] = $k; + $pk->packets[] = $k; } - $this->send(0xc0, array($acks)); + $this->send($pk); } $this->ackQueue = array(); } @@ -1123,38 +1141,41 @@ class Player{ foreach($this->receiveQueue as $count => $packets){ unset($this->receiveQueue[$count]); foreach($packets as $p){ - if(isset($p["counter"])){ - if($p["counter"] > $this->receiveCount){ - $this->receiveCount = $p["counter"]; - }elseif($p["counter"] !== 0){ - if(isset($this->received[$p["counter"]])){ - continue; - } - switch($p["id"]){ - case 0x01: - case MC_PONG: - case MC_PING: - case MC_MOVE_PLAYER: - case MC_REQUEST_CHUNK: - case MC_ANIMATE: - case MC_SET_HEALTH: + if($p instanceof RakNetDataPacket 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; } - $this->received[$p["counter"]] = true; + $p->decode(); + $this->handleDataPacket($p); } - $this->handleDataPacket($p["id"], $p); } } } - if($this->nextBuffer <= $time and strlen($this->buffer) > 0){ + 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){ + if($data->sendtime > $limit){ break; } unset($this->recoveryQueue[$count]); @@ -1165,8 +1186,9 @@ class Player{ foreach($this->resendQueue as $count => $data){ unset($this->resendQueue[$count]); $this->packetStats[1]++; - $this->lag[] = microtime(true) - $data["sendtime"]; - $cnt = $this->directDataPacket($data["id"], $data, $data["pid"]); + $this->lag[] = microtime(true) - $data->sendtime; + $data->sendtime = microtime(true); + $cnt = $this->send($data); if(isset($this->chunkCount[$count])){ unset($this->chunkCount[$count]); $this->chunkCount[$cnt[0]] = true; @@ -1175,25 +1197,25 @@ class Player{ } } - public function handlePacket($pid, $data){ + public function handlePacket(RakNetPacket $packet){ if($this->connected === true){ $this->timeout = microtime(true) + 20; - switch($pid){ - case 0xa0: //NACK - foreach($data[0] as $count){ + switch($packet->pid()){ + case RakNetInfo::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"]; + $this->lag[] = microtime(true) - $this->recoveryQueue[$count]->sendtime; unset($this->recoveryQueue[$count]); } ++$this->packetStats[1]; } break; - case 0xc0: //ACK - foreach($data[0] as $count){ + case RakNetInfo::ACK: + foreach($packet->packets as $count){ if(isset($this->recoveryQueue[$count])){ - $this->lag[] = microtime(true) - $this->recoveryQueue[$count]["sendtime"]; + $this->lag[] = microtime(true) - $this->recoveryQueue[$count]->sendtime; unset($this->recoveryQueue[$count]); unset($this->resendQueue[$count]); } @@ -1201,91 +1223,97 @@ class Player{ } break; - case 0x80: //Data Packet - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8a: - case 0x8b: - case 0x8c: - case 0x8d: - case 0x8e: - case 0x8f: - $this->ackQueue[] = $data[0]; - $this->receiveQueue[$data[0]] = array(); - foreach($data["packets"] as $packet){ - $this->receiveQueue[$data[0]][] = $packet[1]; + case RakNetInfo::DATA_PACKET_0: + case RakNetInfo::DATA_PACKET_1: + case RakNetInfo::DATA_PACKET_2: + case RakNetInfo::DATA_PACKET_3: + case RakNetInfo::DATA_PACKET_4: + case RakNetInfo::DATA_PACKET_5: + case RakNetInfo::DATA_PACKET_6: + case RakNetInfo::DATA_PACKET_7: + case RakNetInfo::DATA_PACKET_8: + case RakNetInfo::DATA_PACKET_9: + case RakNetInfo::DATA_PACKET_A: + case RakNetInfo::DATA_PACKET_B: + case RakNetInfo::DATA_PACKET_C: + case RakNetInfo::DATA_PACKET_D: + case RakNetInfo::DATA_PACKET_E: + case RakNetInfo::DATA_PACKET_F: + $this->ackQueue[] = $packet->seqNumber; + $this->receiveQueue[$packet->seqNumber] = array(); + foreach($packet->data as $pk){ + $this->receiveQueue[$packet->seqNumber][] = $pk; } break; } } } - public function handleDataPacket($pid, $data){ - switch($pid){ + public function handleDataPacket(RakNetDataPacket $packet){ + if($this->connected === false){ + return; + } + + if(EventHandler::callEvent(new DataPacketReceiveEvent($this, $packet)) === BaseEvent::DENY){ + return; + } + + switch($packet->pid()){ case 0x01: break; - case MC_PONG: + case ProtocolInfo::PONG_PACKET: break; - case MC_PING: - $t = abs(microtime(true) * 1000); - $this->dataPacket(MC_PONG, array( - "ptime" => $data["time"], - "time" => $t, - )); - $this->sendBuffer(); + case ProtocolInfo::PING_PACKET: + $pk = new PongPacket; + $pk->ptime = $packet->time; + $pk->time = abs(microtime(true) * 1000); + $this->directDataPacket($pk); break; - case MC_DISCONNECT: + case ProtocolInfo::DISCONNECT_PACKET: $this->close("client disconnect"); break; - case MC_CLIENT_CONNECT: + case ProtocolInfo::CLIENT_CONNECT_PACKET: if($this->loggedIn === true){ break; } - $this->dataPacket(MC_SERVER_HANDSHAKE, array( - "port" => $this->port, - "session" => $data["session"], - "session2" => Utils::readLong("\x00\x00\x00\x00\x04\x44\x0b\xa9"), - )); + $pk = new ServerHandshakePacket; + $pk->port = $this->port; + $pk->session = $packet->session; + $pk->session2 = Utils::readLong("\x00\x00\x00\x00\x04\x44\x0b\xa9"); + $this->dataPacket($pk); break; - case MC_CLIENT_HANDSHAKE: + case ProtocolInfo::CLIENT_HANDSHAKE_PACKET: if($this->loggedIn === true){ break; } break; - case MC_LOGIN: + case ProtocolInfo::LOGIN_PACKET: if($this->loggedIn === true){ break; } - $this->realmsData = array("clientId" => $data["clientId"], "realms_data" => $data["realms_data"]); + $this->loginData = array("clientId" => $packet->clientId, "loginData" => $packet->loginData); if(count($this->server->clients) > $this->server->maxClients){ $this->close("server is full!", false); return; } - if($data["protocol1"] !== CURRENT_PROTOCOL){ - if($data["protocol1"] < CURRENT_PROTOCOL){ - $this->directDataPacket(MC_LOGIN_STATUS, array( - "status" => 1, - )); + if($packet->protocol1 !== ProtocolInfo::CURRENT_PROTOCOL){ + if($packet->protocol1 < ProtocolInfo::CURRENT_PROTOCOL){ + $pk = new LoginStatusPacket; + $pk->status = 1; + $this->directDataPacket($pk); }else{ - $this->directDataPacket(MC_LOGIN_STATUS, array( - "status" => 2, - )); + $pk = new LoginStatusPacket; + $pk->status = 2; + $this->directDataPacket($pk); } - $this->close("Incorrect protocol #".$data["protocol1"], false); + $this->close("Incorrect protocol #".$packet->protocol1, false); break; } - if(preg_match('#[^a-zA-Z0-9_]#', $data["username"]) == 0 and $data["username"] != ""){ - $this->username = $data["username"]; + if(preg_match('#[^a-zA-Z0-9_]#', $packet->username) == 0 and $packet->username != ""){ + $this->username = $packet->username; $this->iusername = strtolower($this->username); }else{ - $this->username = $data["username"]; + $this->username = $packet->username; $this->iusername = strtolower($this->username); $this->close("Bad username", false); break; @@ -1360,18 +1388,21 @@ class Player{ $this->server->api->player->saveOffline($this->data); - $this->dataPacket(MC_LOGIN_STATUS, array( - "status" => 0, - )); - $this->dataPacket(MC_START_GAME, array( - "seed" => $this->level->getSeed(), - "x" => $this->data->get("position")["x"], - "y" => $this->data->get("position")["y"], - "z" => $this->data->get("position")["z"], - "generator" => 0, - "gamemode" => ($this->gamemode & 0x01), - "eid" => 0, - )); + + $pk = new LoginStatusPacket; + $pk->status = 0; + $this->dataPacket($pk); + + $pk = new StartGamePacket; + $pk->seed = $this->level->getSeed(); + $pk->x = $this->data->get("position")["x"]; + $pk->y = $this->data->get("position")["y"]; + $pk->z = $this->data->get("position")["z"]; + $pk->generator = 0; + $pk->gamemode = $this->gamemode & 0x01; + $pk->eid = 0; + $this->dataPacket($pk); + if(($this->gamemode & 0x01) === 0x01){ $this->slot = 0; $this->hotbar = array(); @@ -1390,11 +1421,12 @@ class Player{ $this->entity->z = $this->data->get("position")["z"]; 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); - $this->dataPacket(MC_SET_SPAWN_POSITION, array( - "x" => (int) $this->spawnPosition->x, - "y" => (int) $this->spawnPosition->y, - "z" => (int) $this->spawnPosition->z, - )); + + $pk = new SetSpawnPositionPacket; + $pk->x = (int) $this->spawnPosition->x; + $pk->y = (int) $this->spawnPosition->y; + $pk->z = (int) $this->spawnPosition->z; + $this->dataPacket($pk); } $this->entity->check = false; $this->entity->setName($this->username); @@ -1413,11 +1445,11 @@ class Player{ $this->server->schedule(50, array($this, "measureLag"), array(), true); console("[INFO] ".FORMAT_AQUA.$this->username.FORMAT_RESET."[/".$this->ip.":".$this->port."] logged in with entity id ".$this->eid." at (".$this->entity->level->getName().", ".round($this->entity->x, 2).", ".round($this->entity->y, 2).", ".round($this->entity->z, 2).")"); break; - case MC_READY: + case ProtocolInfo::READY_PACKET: if($this->loggedIn === false){ break; } - switch($data["status"]){ + switch($packet->status){ case 1: //Spawn!! if($this->spawned !== false){ break; @@ -1441,9 +1473,11 @@ class Player{ $this->sendSettings(); $this->server->schedule(50, array($this, "orderChunks"), array(), true); $this->blocked = false; - $this->dataPacket(MC_SET_TIME, array( - "time" => $this->level->getTime(), - )); + + $pk = new SetTimePacket; + $pk->time = $this->level->getTime(); + $this->dataPacket($pk); + $pos = new Position($this->data->get("position")["x"], $this->data->get("position")["y"], $this->data->get("position")["z"], $this->level); $pos = $this->level->getSafeSpawn($pos); $this->teleport($pos); @@ -1456,7 +1490,7 @@ class Player{ break; } break; - case MC_ROTATE_HEAD: + case ProtocolInfo::ROTATE_HEAD_PACKET: if($this->spawned === false){ break; } @@ -1466,25 +1500,26 @@ class Player{ $this->teleport($this->lastCorrect, $this->entity->yaw, $this->entity->pitch, false); } }else{ - $this->entity->setPosition($this->entity, $data["yaw"], $data["pitch"]); + $this->entity->setPosition($this->entity, $packet->yaw, $this->entity->pitch); } } break; - case MC_MOVE_PLAYER: + case ProtocolInfo::MOVE_PLAYER_PACKET: if($this->spawned === false){ break; } - if(($this->entity instanceof Entity) and $data["counter"] > $this->lastMovement){ - $this->lastMovement = $data["counter"]; + if(($this->entity instanceof Entity) and $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(new Vector3($data["x"], $data["y"], $data["z"])) <= 0.7){ + if($this->forceMovement->distance($newPos) <= 0.7){ $this->forceMovement = false; }else{ $this->teleport($this->forceMovement, $this->entity->yaw, $this->entity->pitch, false); } } $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->server->api->handle("player.move", $this->entity) === false){ + 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); } @@ -1492,18 +1527,21 @@ class Player{ console("[WARNING] ".$this->username." moved too quickly!"); } }else{ - $this->entity->setPosition(new Vector3($data["x"], $data["y"], $data["z"]), $data["yaw"], $data["pitch"]); + $this->entity->setPosition($newPos, $packet->yaw, $packet->pitch); } } break; - case MC_PLAYER_EQUIPMENT: + case ProtocolInfo::PLAYER_EQUIPMENT_PACKET: if($this->spawned === false){ break; } - $data["eid"] = $this->eid; + $packet->eid = $this->eid; + + $data = array(); + $data["eid"] = $packet->eid; $data["player"] = $this; - if($data["slot"] === 0x28 or $data["slot"] === 0){ //0 for 0.8.0 compatibility + if($packet->slot === 0x28 or $packet->slot === 0){ //0 for 0.8.0 compatibility $data["slot"] = -1; $data["item"] = BlockAPI::getItem(AIR, 0, 0); if($this->server->handle("player.equipment.change", $data) !== false){ @@ -1511,34 +1549,35 @@ class Player{ } break; }else{ - $data["slot"] -= 9; + $packet->slot -= 9; } if(($this->gamemode & 0x01) === SURVIVAL){ - $data["item"] = $this->getSlot($data["slot"]); + $data["item"] = $this->getSlot($packet->slot); if(!($data["item"] instanceof Item)){ break; } }elseif(($this->gamemode & 0x01) === CREATIVE){ - $data["slot"] = false; + $packet->slot = false; foreach(BlockAPI::$creative as $i => $d){ - if($d[0] === $data["block"] and $d[1] === $data["meta"]){ - $data["slot"] = $i; + if($d[0] === $packet->item and $d[1] === $packet->meta){ + $packet->slot = $i; } } - if($data["slot"] !== false){ - $data["item"] = $this->getSlot($data["slot"]); + if($packet->slot !== false){ + $data["item"] = $this->getSlot($packet->slot); }else{ break; } }else{ break;//????? } - $data["block"] = $data["item"]->getID(); - $data["meta"] = $data["item"]->getMetadata(); + + $data["slot"] = $packet->slot; + if($this->server->handle("player.equipment.change", $data) !== false){ - $this->slot = $data["slot"]; + $this->slot = $packet->slot; if(($this->gamemode & 0x01) === SURVIVAL){ if(!in_array($this->slot, $this->hotbar)){ array_pop($this->hotbar); @@ -1546,7 +1585,7 @@ class Player{ } } }else{ - //$this->sendInventorySlot($data["slot"]); + //$this->sendInventorySlot($packet->slot); $this->sendInventory(); } if($this->entity->inAction === true){ @@ -1554,78 +1593,103 @@ class Player{ $this->entity->updateMetadata(); } break; - case MC_REQUEST_CHUNK: + case ProtocolInfo::REQUEST_CHUNK_PACKET: break; - case MC_USE_ITEM: + case ProtocolInfo::USE_ITEM_PACKET: if(!($this->entity instanceof Entity)){ break; } - if(($this->spawned === false or $this->blocked === true) and $data["face"] >= 0 and $data["face"] <= 5){ - $target = $this->level->getBlock(new Vector3($data["x"], $data["y"], $data["z"])); - $block = $target->getSide($data["face"]); - $this->dataPacket(MC_UPDATE_BLOCK, array( - "x" => $target->x, - "y" => $target->y, - "z" => $target->z, - "block" => $target->getID(), - "meta" => $target->getMetadata() - )); - $this->dataPacket(MC_UPDATE_BLOCK, array( - "x" => $block->x, - "y" => $block->y, - "z" => $block->z, - "block" => $block->getID(), - "meta" => $block->getMetadata() - )); + + $blockVector = new Vector3($packet->x, $packet->y, $packet->z); + + if(($this->spawned === false or $this->blocked === true) and $packet->face >= 0 and $packet->face <= 5){ + $target = $this->level->getBlock($blockVector); + $block = $target->getSide($packet->face); + + $pk = new UpdateBlockPacket; + $pk->x = $target->x; + $pk->y = $target->y; + $pk->z = $target->z; + $pk->block = $target->getID(); + $pk->meta = $target->getMetadata(); + $this->dataPacket($pk); + + $pk = new UpdateBlockPacket; + $pk->x = $block->x; + $pk->y = $block->y; + $pk->z = $block->z; + $pk->block = $block->getID(); + $pk->meta = $block->getMetadata(); + $this->dataPacket($pk); break; } $this->craftingItems = array(); $this->toCraft = array(); - $data["eid"] = $this->eid; + $packet->eid = $this->eid; + $data = array(); + $data["eid"] = $packet->eid; $data["player"] = $this; - if($data["face"] >= 0 and $data["face"] <= 5){ //Use Block, place + $data["face"] = $packet->face; + $data["x"] = $packet->x; + $data["y"] = $packet->y; + $data["z"] = $packet->z; + $data["item"] = $packet->item; + $data["meta"] = $packet->meta; + $data["fx"] = $packet->fx; + $data["fy"] = $packet->fy; + $data["fz"] = $packet->fz; + $data["posX"] = $packet->posX; + $data["posY"] = $packet->posY; + $data["posZ"] = $packet->posZ; + + if($packet->face >= 0 and $packet->face <= 5){ //Use Block, place if($this->entity->inAction === true){ $this->entity->inAction = false; $this->entity->updateMetadata(); } - if($this->blocked === true or Utils::distance($this->entity->position, $data) > 10){ - }elseif($this->getSlot($this->slot)->getID() !== $data["block"] or ($this->getSlot($this->slot)->isTool() === false and $this->getSlot($this->slot)->getMetadata() !== $data["meta"])){ + + if($this->blocked === true or ($this->entity->position instanceof Vector3 and $blockVector->distance($this->entity->position) > 10)){ + + }elseif($this->getSlot($this->slot)->getID() !== $packet->item or ($this->getSlot($this->slot)->isTool() === false and $this->getSlot($this->slot)->getMetadata() !== $packet->meta)){ $this->sendInventorySlot($this->slot); }else{ - $this->server->api->block->playerBlockAction($this, new Vector3($data["x"], $data["y"], $data["z"]), $data["face"], $data["fx"], $data["fy"], $data["fz"]); + $this->server->api->block->playerBlockAction($this, $blockVector, $packet->face, $packet->fx, $packet->fy, $packet->fz); break; } - $target = $this->level->getBlock(new Vector3($data["x"], $data["y"], $data["z"])); - $block = $target->getSide($data["face"]); - $this->dataPacket(MC_UPDATE_BLOCK, array( - "x" => $target->x, - "y" => $target->y, - "z" => $target->z, - "block" => $target->getID(), - "meta" => $target->getMetadata() - )); - $this->dataPacket(MC_UPDATE_BLOCK, array( - "x" => $block->x, - "y" => $block->y, - "z" => $block->z, - "block" => $block->getID(), - "meta" => $block->getMetadata() - )); + $target = $this->level->getBlock($blockVector); + $block = $target->getSide($packet->face); + + $pk = new UpdateBlockPacket; + $pk->x = $target->x; + $pk->y = $target->y; + $pk->z = $target->z; + $pk->block = $target->getID(); + $pk->meta = $target->getMetadata(); + $this->dataPacket($pk); + + $pk = new UpdateBlockPacket; + $pk->x = $block->x; + $pk->y = $block->y; + $pk->z = $block->z; + $pk->block = $block->getID(); + $pk->meta = $block->getMetadata(); + $this->dataPacket($pk); break; - }elseif($data["face"] === 0xFF and $this->server->handle("player.action", $data) !== false){ + }elseif($packet->face === 0xff and $this->server->handle("player.action", $data) !== false){ $this->entity->inAction = true; $this->startAction = microtime(true); $this->entity->updateMetadata(); } break; - case MC_PLAYER_ACTION: + case ProtocolInfo::PLAYER_ACTION_PACKET: if($this->spawned === false or $this->blocked === true){ break; } + $packet->eid = $this->eid; $this->craftingItems = array(); $this->toCraft = array(); - switch($data["action"]){ + switch($packet->action){ case 5: //Shot arrow if($this->entity->inAction === true){ if($this->getSlot($this->slot)->getID() === BOW){ @@ -1652,18 +1716,15 @@ class Player{ $overturn = false; if(0 <= $rotation and $rotation < 90){ - } - elseif(90 <= $rotation and $rotation < 180){ + }elseif(90 <= $rotation and $rotation < 180){ $rotation -= 90; $X = (-1); $overturn = true; - } - elseif(180 <= $rotation and $rotation < 270){ + }elseif(180 <= $rotation and $rotation < 270){ $rotation -= 180; $X = (-1); $Z = (-1); - } - elseif(270 <= $rotation and $rotation < 360){ + }elseif(270 <= $rotation and $rotation < 360){ $rotation -= 270; $Z = (-1); $overturn = true; @@ -1696,33 +1757,34 @@ class Player{ $this->stopSleep(); } break; - case MC_REMOVE_BLOCK: - if($this->spawned === false or $this->blocked === true or $this->entity->distance(new Vector3($data["x"], $data["y"], $data["z"])) > 8){ - $target = $this->level->getBlock(new Vector3($data["x"], $data["y"], $data["z"])); - $this->dataPacket(MC_UPDATE_BLOCK, array( - "x" => $target->x, - "y" => $target->y, - "z" => $target->z, - "block" => $target->getID(), - "meta" => $target->getMetadata() - )); + case ProtocolInfo::REMOVE_BLOCK_PACKET: + $blockVector = new Vector3($packet->x, $packet->y, $packet->z); + if($this->spawned === false or $this->blocked === true or $this->entity->distance($blockVector) > 8){ + $target = $this->level->getBlock($blockVector); + + $pk = new UpdateBlockPacket; + $pk->x = $target->x; + $pk->y = $target->y; + $pk->z = $target->z; + $pk->block = $target->getID(); + $pk->meta = $target->getMetadata(); + $this->dataPacket($pk); break; } $this->craftingItems = array(); $this->toCraft = array(); - $this->server->api->block->playerBlockBreak($this, new Vector3($data["x"], $data["y"], $data["z"])); + $this->server->api->block->playerBlockBreak($this, $blockVector); break; - case MC_PLAYER_ARMOR_EQUIPMENT: + case ProtocolInfo::PLAYER_ARMOR_EQUIPMENT_PACKET: if($this->spawned === false or $this->blocked === true){ break; } $this->craftingItems = array(); $this->toCraft = array(); - $data["eid"] = $this->eid; - $data["player"] = $this; + $packet->eid = $this->eid; for($i = 0; $i < 4; ++$i){ - $s = $data["slot$i"]; + $s = $packet->slots[$i]; if($s === 0 or $s === 255){ $s = BlockAPI::getItem(AIR, 0, 0); }else{ @@ -1732,7 +1794,7 @@ class Player{ if($slot->getID() !== AIR and $s->getID() === AIR){ $this->addItem($slot->getID(), $slot->getMetadata(), 1, false); $this->armor[$i] = BlockAPI::getItem(AIR, 0, 0); - $data["slot$i"] = 255; + $packet->slots[$i] = 255; }elseif($s->getID() !== AIR and $slot->getID() === AIR and ($sl = $this->hasItem($s->getID())) !== false){ $this->armor[$i] = $this->getSlot($sl); $this->setSlot($sl, BlockAPI::getItem(AIR, 0, 0), false); @@ -1741,7 +1803,7 @@ class Player{ $this->armor[$i] = $this->getSlot($sl); $this->setSlot($sl, $item, false); }else{ - $data["slot$i"] = 255; + $packet->slots[$i] = 255; } } @@ -1751,13 +1813,18 @@ class Player{ $this->entity->updateMetadata(); } break; - case MC_INTERACT: + case ProtocolInfo::INTERACT_PACKET: if($this->spawned === false){ break; } + $packet->eid = $this->eid; + $data = array(); + $data["target"] = $packet->target; + $data["eid"] = $packet->eid; + $data["action"] = $packet->action; $this->craftingItems = array(); $this->toCraft = array(); - $target = $this->server->api->entity->get($data["target"]); + $target = $this->server->api->entity->get($packet->target); if($target instanceof Entity and $this->entity instanceof Entity and $this->gamemode !== VIEW and $this->blocked === false and ($target instanceof Entity) and $this->entity->distance($target) <= 8){ $data["targetentity"] = $target; $data["entity"] = $this->entity; @@ -1835,13 +1902,14 @@ class Player{ } break; - case MC_ANIMATE: + case ProtocolInfo::ANIMATE_PACKET: if($this->spawned === false){ break; } - $this->server->api->dhandle("entity.animate", array("eid" => $this->eid, "entity" => $this->entity, "action" => $data["action"])); + $packet->eid = $this->eid; + $this->server->api->dhandle("entity.animate", array("eid" => $packet->eid, "entity" => $this->entity, "action" => $packet->action)); break; - case MC_RESPAWN: + case ProtocolInfo::RESPAWN_PACKET: if($this->spawned === false){ break; } @@ -1863,20 +1931,20 @@ class Player{ $this->blocked = false; $this->server->handle("player.respawn", $this); break; - case MC_SET_HEALTH: //Not used + case ProtocolInfo::SET_HEALTH_PACKET: //Not used break; - case MC_ENTITY_EVENT: + case ProtocolInfo::ENTITY_EVENT_PACKET: if($this->spawned === false or $this->blocked === true){ break; } $this->craftingItems = array(); $this->toCraft = array(); - $data["eid"] = $this->eid; + $packet->eid = $this->eid; if($this->entity->inAction === true){ $this->entity->inAction = false; $this->entity->updateMetadata(); } - switch($data["event"]){ + switch($packet->event){ case 9: //Eating $items = array( APPLE => 4, @@ -1901,10 +1969,12 @@ class Player{ ); $slot = $this->getSlot($this->slot); if($this->entity->getHealth() < 20 and isset($items[$slot->getID()])){ - $this->dataPacket(MC_ENTITY_EVENT, array( - "eid" => 0, - "event" => 9, - )); + + $pk = new EntityEventPacket; + $pk->eid = 0; + $pk->event = 9; + $this->dataPacket($pk); + $this->entity->heal($items[$slot->getID()], "eating"); --$slot->count; if($slot->count <= 0){ @@ -1917,15 +1987,20 @@ class Player{ break; } break; - case MC_DROP_ITEM: + case ProtocolInfo::DROP_ITEM_PACKET: if($this->spawned === false or $this->blocked === true){ break; } + $packet->eid = $this->eid; + $packet->item = $this->getSlot($this->slot); $this->craftingItems = array(); $this->toCraft = array(); - $data["item"] = $this->getSlot($this->slot); + $data["eid"] = $packet->eid; + $data["unknown"] = $packet->unknown; + $data["item"] = $packet->item; + $data["player"] = $this; if($this->blocked === false and $this->server->handle("player.drop", $data) !== false){ - $this->server->api->entity->drop(new Position($this->entity->x - 0.5, $this->entity->y, $this->entity->z - 0.5, $this->level), $data["item"]); + $this->server->api->entity->drop(new Position($this->entity->x - 0.5, $this->entity->y, $this->entity->z - 0.5, $this->level), $packet->item); $this->setSlot($this->slot, BlockAPI::getItem(AIR, 0, 0), false); } if($this->entity->inAction === true){ @@ -1933,14 +2008,14 @@ class Player{ $this->entity->updateMetadata(); } break; - case MC_CHAT: + case ProtocolInfo::MESSAGE_PACKET: if($this->spawned === false){ break; } $this->craftingItems = array(); $this->toCraft = array(); - if(trim($data["message"]) != "" and strlen($data["message"]) <= 255){ - $message = $data["message"]; + if(trim($packet->message) != "" and strlen($packet->message) <= 255){ + $message = $packet->message; if($message{0} === "/"){ //Command $this->server->api->console->run(substr($message, 1), $this); }else{ @@ -1955,40 +2030,40 @@ class Player{ } } break; - case MC_CONTAINER_CLOSE: + case ProtocolInfo::CONTAINER_CLOSE_PACKET: if($this->spawned === false){ break; } $this->craftingItems = array(); $this->toCraft = array(); - if(isset($this->windows[$data["windowid"]])){ - if(is_array($this->windows[$data["windowid"]])){ - foreach($this->windows[$data["windowid"]] as $ob){ - $this->server->api->player->broadcastPacket($this->level->players, MC_TILE_EVENT, array( - "x" => $ob->x, - "y" => $ob->y, - "z" => $ob->z, - "case1" => 1, - "case2" => 0, - )); + if(isset($this->windows[$packet->windowid])){ + if(is_array($this->windows[$packet->windowid])){ + foreach($this->windows[$packet->windowid] as $ob){ + $pk = new TileEventPacket; + $pk->x = $ob->x; + $pk->y = $ob->y; + $pk->z = $ob->z; + $pk->case1 = 1; + $pk->case2 = 0; + $this->server->api->player->broadcastPacket($this->level->players, $pk); } - }elseif($this->windows[$data["windowid"]]->class === TILE_CHEST){ - $this->server->api->player->broadcastPacket($this->server->api->player->getAll($this->level), MC_TILE_EVENT, array( - "x" => $this->windows[$data["windowid"]]->x, - "y" => $this->windows[$data["windowid"]]->y, - "z" => $this->windows[$data["windowid"]]->z, - "case1" => 1, - "case2" => 0, - )); + }elseif($this->windows[$packet->windowid]->class === TILE_CHEST){ + $pk = new TileEventPacket; + $pk->x = $this->windows[$packet->windowid]->x; + $pk->y = $this->windows[$packet->windowid]->y; + $pk->z = $this->windows[$packet->windowid]->z; + $pk->case1 = 1; + $pk->case2 = 0; + $this->server->api->player->broadcastPacket($this->level->players, $pk); } } - unset($this->windows[$data["windowid"]]); + unset($this->windows[$packet->windowid]); - $this->dataPacket(MC_CONTAINER_CLOSE, array( - "windowid" => $data["windowid"], - )); + $pk = new ContainerClosePacket; + $pk->windowid = $packet->windowid; + $this->dataPacket($pk); break; - case MC_CONTAINER_SET_SLOT: + case ProtocolInfo::CONTAINER_SET_SLOT_PACKET: if($this->spawned === false or $this->blocked === true){ break; } @@ -2002,28 +2077,28 @@ class Player{ $this->craftingItems = array(); } - if($data["windowid"] === 0){ + if($packet->windowid === 0){ $craft = false; - $slot = $this->getSlot($data["slot"]); - if($slot->count >= $data["stack"] and (($slot->getID() === $data["block"] and $slot->getMetadata() === $data["meta"]) or ($data["block"] === AIR and $data["stack"] === 0)) and !isset($this->craftingItems[$data["slot"]])){ //Crafting recipe - $use = BlockAPI::getItem($slot->getID(), $slot->getMetadata(), $slot->count - $data["stack"]); - $this->craftingItems[$data["slot"]] = $use; + $slot = $this->getSlot($packet->slot); + if($slot->count >= $packet->item->count and (($slot->getID() === $packet->item->getID() and $slot->getMetadata() === $packet->item->getMetadata()) or ($packet->item->getID() === AIR and $packet->item->count === 0)) and !isset($this->craftingItems[$packet->slot])){ //Crafting recipe + $use = BlockAPI::getItem($slot->getID(), $slot->getMetadata(), $slot->count - $packet->item->count); + $this->craftingItems[$packet->slot] = $use; $craft = true; - }elseif($slot->count <= $data["stack"] and ($slot->getID() === AIR or ($slot->getID() === $data["block"] and $slot->getMetadata() === $data["meta"]))){ //Crafting final - $craftItem = BlockAPI::getItem($data["block"], $data["meta"], $data["stack"] - $slot->count); + }elseif($slot->count <= $packet->item->count and ($slot->getID() === AIR or ($slot->getID() === $packet->item->getID() and $slot->getMetadata() === $packet->item->getMetadata()))){ //Crafting final + $craftItem = BlockAPI::getItem($packet->item->getID(), $packet->item->getMetadata(), $packet->item->count - $slot->count); if(count($this->toCraft) === 0){ $this->toCraft[-1] = 0; } - $this->toCraft[$data["slot"]] = $craftItem; + $this->toCraft[$packet->slot] = $craftItem; $craft = true; - }elseif(((count($this->toCraft) === 1 and isset($this->toCraft[-1])) or count($this->toCraft) === 0) and $slot->count > 0 and $slot->getID() > AIR and ($slot->getID() !== $data["block"] or $slot->getMetadata() !== $data["meta"])){ //Crafting final - $craftItem = BlockAPI::getItem($data["block"], $data["meta"], $data["stack"]); + }elseif(((count($this->toCraft) === 1 and isset($this->toCraft[-1])) or count($this->toCraft) === 0) and $slot->count > 0 and $slot->getID() > AIR and ($slot->getID() !== $packet->item->getID() or $slot->getMetadata() !== $packet->item->getMetadata())){ //Crafting final + $craftItem = BlockAPI::getItem($packet->item->getID(), $packet->item->getMetadata(), $packet->item->count); if(count($this->toCraft) === 0){ $this->toCraft[-1] = 0; } $use = BlockAPI::getItem($slot->getID(), $slot->getMetadata(), $slot->count); - $this->craftingItems[$data["slot"]] = $use; - $this->toCraft[$data["slot"]] = $craftItem; + $this->craftingItems[$packet->slot] = $use; + $this->toCraft[$packet->slot] = $craftItem; $craft = true; } @@ -2044,42 +2119,40 @@ class Player{ $this->toCraft = array(); $this->craftingItems = array(); } - if(!isset($this->windows[$data["windowid"]])){ + if(!isset($this->windows[$packet->windowid])){ break; } - if(is_array($this->windows[$data["windowid"]])){ - $tiles = $this->windows[$data["windowid"]]; - if($data["slot"] >= 0 and $data["slot"] < CHEST_SLOTS){ + if(is_array($this->windows[$packet->windowid])){ + $tiles = $this->windows[$packet->windowid]; + if($packet->slot >= 0 and $packet->slot < CHEST_SLOTS){ $tile = $tiles[0]; - $slotn = $data["slot"]; + $slotn = $packet->slot; $offset = 0; - }elseif($data["slot"] >= CHEST_SLOTS and $data["slot"] <= (CHEST_SLOTS << 1)){ + }elseif($packet->slot >= CHEST_SLOTS and $packet->slot <= (CHEST_SLOTS << 1)){ $tile = $tiles[1]; - $slotn = $data["slot"] - CHEST_SLOTS; + $slotn = $packet->slot - CHEST_SLOTS; $offset = CHEST_SLOTS; }else{ break; } - $item = BlockAPI::getItem($data["block"], $data["meta"], $data["stack"]); + $item = BlockAPI::getItem($packet->item->getID(), $packet->item->getMetadata(), $packet->item->count); $slot = $tile->getSlot($slotn); if($this->server->api->dhandle("player.container.slot", array( "tile" => $tile, - "slot" => $data["slot"], + "slot" => $packet->slot, "offset" => $offset, "slotdata" => $slot, "itemdata" => $item, "player" => $this, )) === false){ - $this->dataPacket(MC_CONTAINER_SET_SLOT, array( - "windowid" => $data["windowid"], - "slot" => $data["slot"], - "block" => $slot->getID(), - "stack" => $slot->count, - "meta" => $slot->getMetadata(), - )); + $pk = new ContainerSetSlotPacket; + $pk->windowid = $packet->windowid; + $pk->slot = $packet->slot; + $pk->item = $slot; + $this->dataPacket($pk); break; } if($item->getID() !== AIR and $slot->getID() == $item->getID()){ @@ -2098,31 +2171,29 @@ class Player{ } $tile->setSlot($slotn, $item, true, $offset); }else{ - $tile = $this->windows[$data["windowid"]]; - if(($tile->class !== TILE_CHEST and $tile->class !== TILE_FURNACE) or $data["slot"] < 0 or ($tile->class === TILE_CHEST and $data["slot"] >= CHEST_SLOTS) or ($tile->class === TILE_FURNACE and $data["slot"] >= FURNACE_SLOTS)){ + $tile = $this->windows[$packet->windowid]; + if(($tile->class !== TILE_CHEST and $tile->class !== TILE_FURNACE) or $packet->slot < 0 or ($tile->class === TILE_CHEST and $packet->slot >= CHEST_SLOTS) or ($tile->class === TILE_FURNACE and $packet->slot >= FURNACE_SLOTS)){ break; } - $item = BlockAPI::getItem($data["block"], $data["meta"], $data["stack"]); + $item = BlockAPI::getItem($packet->item->getID(), $packet->item->getMetadata(), $packet->item->count); - $slot = $tile->getSlot($data["slot"]); + $slot = $tile->getSlot($packet->slot); if($this->server->api->dhandle("player.container.slot", array( "tile" => $tile, - "slot" => $data["slot"], + "slot" => $packet->slot, "slotdata" => $slot, "itemdata" => $item, "player" => $this, )) === false){ - $this->dataPacket(MC_CONTAINER_SET_SLOT, array( - "windowid" => $data["windowid"], - "slot" => $data["slot"], - "block" => $slot->getID(), - "stack" => $slot->count, - "meta" => $slot->getMetadata(), - )); + $pk = new ContainerSetSlotPacket; + $pk->windowid = $packet->windowid; + $pk->slot = $packet->slot; + $pk->item = $slot; + $this->dataPacket($pk); break; } - if($tile->class === TILE_FURNACE and $data["slot"] == 2){ + if($tile->class === TILE_FURNACE and $packet->slot == 2){ switch($slot->getID()){ case IRON_INGOT: AchievementAPI::grantAchievement($this, "acquireIron"); @@ -2144,27 +2215,27 @@ class Player{ } $this->addItem($slot->getID(), $slot->getMetadata(), $slot->count, false); } - $tile->setSlot($data["slot"], $item); + $tile->setSlot($packet->slot, $item); } break; - case MC_SEND_INVENTORY: //TODO, Mojang, enable this ´^_^` + case ProtocolInfo::SEND_INVENTORY_PACKET: //TODO, Mojang, enable this ´^_^` if($this->spawned === false){ break; } break; - case MC_ENTITY_DATA: + case ProtocolInfo::ENTITY_DATA_PACKET: if($this->spawned === false or $this->blocked === true){ break; } $this->craftingItems = array(); $this->toCraft = array(); - $t = $this->server->api->tile->get(new Position($data["x"], $data["y"], $data["z"], $this->level)); + $t = $this->server->api->tile->get(new Position($packet->x, $packet->y, $packet->z, $this->level)); if(($t instanceof Tile) and $t->class === TILE_SIGN){ if($t->data["creator"] !== $this->username){ $t->spawn($this); }else{ $nbt = new NBT(); - $nbt->load($data["namedtag"]); + $nbt->load($packet->namedtag); $d = array_shift($nbt->tree); if($d["id"] !== TILE_SIGN){ $t->spawn($this); @@ -2175,7 +2246,7 @@ class Player{ } break; default: - console("[DEBUG] Unhandled 0x".dechex($pid)." Data Packet for Client ID ".$this->clientID.": ".print_r($data, true), true, true, 2); + console("[DEBUG] Unhandled 0x".dechex($packet->pid())." data packet for ".$this->username." (".$this->clientID."): ".print_r($packet, true), true, true, 2); break; } } @@ -2186,27 +2257,28 @@ class Player{ public function sendArmor($player = false){ $data = array( "player" => $this, - "eid" => $this->eid + "eid" => $this->eid, + "slots" => array() ); - $armor = array(); for($i = 0; $i < 4; ++$i){ if(isset($this->armor[$i]) and ($this->armor[$i] instanceof Item) and $this->armor[$i]->getID() > AIR){ - $data["slot$i"] = $this->armor[$i]->getID() !== AIR ? $this->armor[$i]->getID() - 256:0; + $data["slots"][$i] = $this->armor[$i]->getID() !== AIR ? $this->armor[$i]->getID() - 256:0; }else{ $this->armor[$i] = BlockAPI::getItem(AIR, 0, 0); - $data["slot$i"] = 255; + $data["slots"][$i] = 255; } - $armor[] = $this->armor[$i]; } if($player instanceof Player){ if($player === $this){ - $this->dataPacket(MC_CONTAINER_SET_CONTENT, array( - "windowid" => 0x78, - "count" => 4, - "slots" => $armor, - )); + $pk = new ContainerSetContentPacket; + $pk->windowid = 0x78; //Armor window id + $pk->slots = $this->armor; + $this->dataPacket($pk); }else{ - $player->dataPacket(MC_PLAYER_ARMOR_EQUIPMENT, $data); + $pk = new PlayerArmorEquipmentPacket; + $pk->eid = $this->eid; + $pk->slots = $data["slots"]; + $player->dataPacket($pk); } }else{ $this->server->api->dhandle("player.armor", $data); @@ -2222,73 +2294,88 @@ class Player{ $hotbar[] = $slot <= -1 ? -1 : $slot + 9; } - $this->dataPacket(MC_CONTAINER_SET_CONTENT, array( - "windowid" => 0, - "count" => count($this->inventory), - "slots" => $this->inventory, - "hotbar" => $hotbar, - )); + $pk = new ContainerSetContentPacket; + $pk->windowid = 0; + $pk->slots = $this->inventory; + $pk->hotbar = $hotbar; + $this->dataPacket($pk); } - public function send($pid, $data = array(), $raw = false){ + public function send(RakNetPacket $packet){ if($this->connected === true){ - $this->bandwidthRaw += $this->server->send($pid, $data, $raw, $this->ip, $this->port); + $packet->ip = $this->ip; + $packet->port = $this->port; + $this->bandwidthRaw += $this->server->send($packet); } } public function sendBuffer(){ - if(strlen($this->buffer) > 0){ - $this->directDataPacket(false, array("raw" => $this->buffer), 0x40); + if($this->bufferLen > 0 and $this->buffer instanceof RakNetPacket){ + $this->buffer->seqNumber = $this->counter[0]++; + $this->send($this->buffer); } - $this->buffer = ""; + $this->bufferLen = 0; + $this->buffer = new RakNetPacket(RakNetInfo::DATA_PACKET_0); + $this->buffer->data = array(); $this->nextBuffer = microtime(true) + 0.1; } - public function directBigRawPacket($id, $buffer){ + private function directBigRawPacket(RakNetDataPacket $packet){ if($this->connected === false){ return false; - } - $data = array( - "id" => false, - "pid" => 0x50, - "sendtime" => microtime(true), - "raw" => "", - ); + } + + $sendtime = microtime(true); + $size = $this->MTU - 34; - $buffer = str_split(($id === false ? "":chr($id)).$buffer, $size); - $h = Utils::writeInt(count($buffer)).Utils::writeShort($this->bigCnt); + $buffer = str_split($packet->buffer, $size); + $bigCnt = $this->bigCnt; $this->bigCnt = ($this->bigCnt + 1) % 0x10000; $cnts = array(); + $bufCount = count($buffer); foreach($buffer as $i => $buf){ - $data["raw"] = Utils::writeShort(strlen($buf) << 3).strrev(Utils::writeTriad($this->counter[3]++)).$h.Utils::writeInt($i).$buf; $cnts[] = $count = $this->counter[0]++; - $this->recoveryQueue[$count] = $data; - $this->send(0x80, array( - $count, - 0x50, //0b01010000 - $data, - )); + + $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 RakNetPacket(RakNetInfo::DATA_PACKET_0); + $rk->data[] = $pk; + $rk->seqNumber = $count; + $rk->sendtime = $sendtime; + $this->recoveryQueue[$count] = $rk; + $this->send($rk); } return $cnts; } - public function directDataPacket($id, $data = array(), $pid = 0x00, $recover = true){ + public function directDataPacket(RakNetDataPacket $packet, $reliability = 0, $recover = true){ if($this->connected === false){ return false; } - $data["id"] = $id; - $data["pid"] = $pid; - $data["sendtime"] = microtime(true); - $count = $this->counter[0]++; - if($recover !== false){ - $this->recoveryQueue[$count] = $data; + + if(EventHandler::callEvent(new DataPacketSendEvent($this, $packet)) === BaseEvent::DENY){ + return array(); } - $this->send(0x80, array( - $count, - $pid, - $data, - )); - return array($count); + + $packet->encode(); + $pk = new RakNetPacket(RakNetInfo::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); } /** @@ -2297,24 +2384,30 @@ class Player{ * * @return array|bool */ - public function dataPacket($id, $data = array()){ - $data["id"] = $id; - if($id === false){ - $raw = $data["raw"]; - }else{ - $data = new CustomPacketHandler($id, "", $data, true); - $raw = chr($id).$data->raw; - } - $len = strlen($raw); - $MTU = $this->MTU - 24; - if($len > $MTU){ - return $this->directBigRawPacket(false, $raw); + public function dataPacket(RakNetDataPacket $packet){ + if($this->connected === false){ + return false; } - if((strlen($this->buffer) + $len) >= $MTU){ + if(EventHandler::callEvent(new DataPacketSendEvent($this, $packet)) === BaseEvent::DENY){ + return; + } + + $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(); } - $this->buffer .= ($this->buffer === "" ? "":"\x40").Utils::writeShort($len << 3).strrev(Utils::writeTriad($this->counter[3]++)).$raw; + + $packet->messageIndex = $this->counter[3]++; + $packet->reliability = 2; + $this->buffer->data[] = $packet; + $this->bufferLen += 6 + $len; return array(); } diff --git a/src/PocketMinecraftServer.php b/src/PocketMinecraftServer.php index 173ac144a..ac655f6cf 100644 --- a/src/PocketMinecraftServer.php +++ b/src/PocketMinecraftServer.php @@ -64,7 +64,7 @@ class PocketMinecraftServer{ $this->saveEnabled = true; $this->tickMeasure = array_fill(0, 40, 0); $this->setType("normal"); - $this->interface = new MinecraftInterface($this, "255.255.255.255", $this->port, true, false, $this->serverip); + $this->interface = new MinecraftInterface("255.255.255.255", $this->port, $this->serverip); $this->stop = false; $this->ticks = 0; if(!defined("NO_THREADS")){ @@ -421,7 +421,7 @@ class PocketMinecraftServer{ } $dump .= "\r\n\r\n"; $version = new VersionString(); - $dump .= "PocketMine-MP version: ".$version." #".$version->getNumber()." [Protocol ".CURRENT_PROTOCOL."; API ".CURRENT_API_VERSION."]\r\n"; + $dump .= "PocketMine-MP version: ".$version." #".$version->getNumber()." [Protocol ".ProtocolInfo::CURRENT_PROTOCOL."; API ".CURRENT_API_VERSION."]\r\n"; $dump .= "Git commit: ".GIT_COMMIT."\r\n"; $dump .= "Source SHA1 sum: ".SOURCE_SHA1SUM."\r\n"; $dump .= "uname -a: ".php_uname("a")."\r\n"; @@ -473,29 +473,30 @@ class PocketMinecraftServer{ } public static function clientID($ip, $port){ - //faster than string indexes in PHP return crc32($ip . $port) ^ crc32($port . $ip . BOOTUP_RANDOM); + //return $ip . ":" . $port; } - public function packetHandler($packet){ - $data =& $packet["data"]; - $CID = PocketMinecraftServer::clientID($packet["ip"], $packet["port"]); + public function packetHandler(Packet $packet){ + $data =& $packet; + $CID = PocketMinecraftServer::clientID($packet->ip, $packet->port); if(isset($this->clients[$CID])){ - $this->clients[$CID]->handlePacket($packet["pid"], $data); + $this->clients[$CID]->handlePacket($packet); }else{ - if($this->handle("server.noauthpacket", $packet) === false){ + if($this->handle("server.noauthpacket.".$packet->pid(), $packet) === false){ return; } - switch($packet["pid"]){ - case 0x01: - case 0x02: + switch($packet->pid()){ + case RakNetInfo::UNCONNECTED_PING: + case RakNetInfo::UNCONNECTED_PING_OPEN_CONNECTIONS: if($this->invisible === true){ - $this->send(0x1c, array( - $data[0], - $this->serverID, - RAKNET_MAGIC, - $this->serverType, - ), false, $packet["ip"], $packet["port"]); + $pk = new RakNetPacket(RakNetInfo::UNCONNECTED_PONG); + $pk->pingID = $packet->pingID; + $pk->serverID = $this->serverID; + $pk->serverType = $this->serverType; + $pk->ip = $packet->ip; + $pk->port = $packet->port; + $this->send($pk); break; } if(!isset($this->custom["times_".$CID])){ @@ -507,64 +508,59 @@ class PocketMinecraftServer{ } $txt = substr($this->description, $this->custom["times_".$CID], $ln); $txt .= substr($this->description, 0, $ln - strlen($txt)); - $this->send(0x1c, array( - $data[0], - $this->serverID, - RAKNET_MAGIC, - $this->serverType. $this->name . " [".count($this->clients)."/".$this->maxClients."] ".$txt, - ), false, $packet["ip"], $packet["port"]); + $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->ip = $packet->ip; + $pk->port = $packet->port; + $this->send($pk); $this->custom["times_".$CID] = ($this->custom["times_".$CID] + 1) % strlen($this->description); break; - case 0x05: - $version = $data[1]; - $size = strlen($data[2]); - if($version !== CURRENT_STRUCTURE){ - console("[DEBUG] Incorrect structure #$version from ".$packet["ip"].":".$packet["port"], true, true, 2); - $this->send(0x1a, array( - CURRENT_STRUCTURE, - RAKNET_MAGIC, - $this->serverID, - ), false, $packet["ip"], $packet["port"]); + case RakNetInfo::OPEN_CONNECTION_REQUEST_1: + if($packet->structure !== RakNetInfo::STRUCTURE){ + console("[DEBUG] Incorrect structure #".$packet->structure." from ".$packet->ip.":".$packet->port, true, true, 2); + $pk = new RakNetPacket(RakNetInfo::INCOMPATIBLE_PROTOCOL_VERSION); + $pk->serverID = $this->serverID; + $pk->ip = $packet->ip; + $pk->port = $packet->port; + $this->send($pk); }else{ - $this->send(0x06, array( - RAKNET_MAGIC, - $this->serverID, - 0, - strlen($packet["raw"]), - ), false, $packet["ip"], $packet["port"]); + $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->send($pk); } break; - case 0x07: + case RakNetInfo::OPEN_CONNECTION_REQUEST_2: if($this->invisible === true){ break; } - $port = $data[2]; - $MTU = $data[3]; - $clientID = $data[4]; - if(count($this->clients) < $this->maxClients){ - $this->clients[$CID] = new Player($clientID, $packet["ip"], $packet["port"], $MTU); //New Session! - $this->send(0x08, array( - RAKNET_MAGIC, - $this->serverID, - $this->port, - $data[3], - 0, - ), false, $packet["ip"], $packet["port"]); - } + + $this->clients[$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->port = $this->port; + $pk->mtuSize = $packet->mtuSize; + $pk->ip = $packet->ip; + $pk->port = $packet->port; + $this->send($pk); break; } } } - public function send($pid, $data = array(), $raw = false, $dest = false, $port = false){ - return $this->interface->writePacket($pid, $data, $raw, $dest, $port); + public function send(Packet $packet){ + return $this->interface->writePacket($packet); } public function process(){ $lastLoop = 0; while($this->stop === false){ $packet = $this->interface->readPacket(); - if($packet !== false){ + if($packet instanceof Packet){ $this->packetHandler($packet); $lastLoop = 0; }else{ diff --git a/src/constants/GeneralConstants.php b/src/constants/GeneralConstants.php index 9febec891..b60b45aca 100644 --- a/src/constants/GeneralConstants.php +++ b/src/constants/GeneralConstants.php @@ -31,7 +31,6 @@ define("VIEWER", 3); //Players -define("MAX_CHUNK_RATE", 20 / arg("max-chunks-per-second", 4)); //Default rate ~256 kB/s define("PLAYER_MAX_QUEUE", 1024); define("PLAYER_SURVIVAL_SLOTS", 36); diff --git a/src/event/CancellableEvent.php b/src/event/CancellableEvent.php new file mode 100644 index 000000000..11b64cb22 --- /dev/null +++ b/src/event/CancellableEvent.php @@ -0,0 +1,28 @@ + $handlerList){ + if(count($handlerList) > 0){ + $event->setPrioritySlot($priority); + foreach($handlerList as $handler){ + call_user_func($handler, $event); + } + if($event->isForced()){ + if($event instanceof CancellableEvent and $event->isCancelled()){ + return BaseEvent::DENY; + }else{ + return BaseEvent::ALLOW; + } + } + } + } + + if($event instanceof CancellableEvent and $event->isCancelled()){ + return BaseEvent::DENY; + }elseif($event->isAllowed()){ + return BaseEvent::ALLOW; + }else{ + return BaseEvent::NORMAL; + } + + } + +} \ No newline at end of file diff --git a/src/event/EventPriority.php b/src/event/EventPriority.php new file mode 100644 index 000000000..f42e8d732 --- /dev/null +++ b/src/event/EventPriority.php @@ -0,0 +1,52 @@ +packet = $packet; + } + + public function getPacket(){ + return $this->packet; + } + + public function getPlayer(){ + return $this->player; + } +} \ No newline at end of file diff --git a/src/event/server/DataPacketSendEvent.php b/src/event/server/DataPacketSendEvent.php new file mode 100644 index 000000000..a1935430d --- /dev/null +++ b/src/event/server/DataPacketSendEvent.php @@ -0,0 +1,40 @@ +packet = $packet; + } + + public function getPacket(){ + return $this->packet; + } + + public function getPlayer(){ + return $this->player; + } +} \ No newline at end of file diff --git a/src/event/server/PacketReceiveEvent.php b/src/event/server/PacketReceiveEvent.php new file mode 100644 index 000000000..cb26cbf05 --- /dev/null +++ b/src/event/server/PacketReceiveEvent.php @@ -0,0 +1,36 @@ +packet = $packet; + } + + public function getPacket(){ + return $this->packet; + } +} \ No newline at end of file diff --git a/src/event/server/PacketSendEvent.php b/src/event/server/PacketSendEvent.php new file mode 100644 index 000000000..becb15e48 --- /dev/null +++ b/src/event/server/PacketSendEvent.php @@ -0,0 +1,36 @@ +packet = $packet; + } + + public function getPacket(){ + return $this->packet; + } +} \ No newline at end of file diff --git a/src/material/block/DoorBlock.php b/src/material/block/DoorBlock.php index 06c0c4bcb..185dd4145 100644 --- a/src/material/block/DoorBlock.php +++ b/src/material/block/DoorBlock.php @@ -125,13 +125,13 @@ class DoorBlock extends TransparentBlock{ $this->level->setBlock($down, BlockAPI::get($this->id, $meta), true, false, true); $players = ServerAPI::request()->api->player->getAll($this->level); unset($players[$player->CID]); - ServerAPI::request()->api->player->broadcastPacket($players, MC_LEVEL_EVENT, array( - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "evid" => 1003, - "data" => 0 - )); + $pk = new LevelEventPacket; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->evid = 1003; + $pk->data = 0; + ServerAPI::request()->api->player->broadcastPacket($players, $pk); return true; } return false; @@ -140,13 +140,13 @@ class DoorBlock extends TransparentBlock{ $this->level->setBlock($this, $this, true, false, true); $players = ServerAPI::request()->api->player->getAll($this->level); unset($players[$player->CID]); - ServerAPI::request()->api->player->broadcastPacket($players, MC_LEVEL_EVENT, array( - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "evid" => 1003, - "data" => 0 - )); + $pk = new LevelEventPacket; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->evid = 1003; + $pk->data = 0; + ServerAPI::request()->api->player->broadcastPacket($players, $pk); } return true; } diff --git a/src/material/block/misc/Bed.php b/src/material/block/misc/Bed.php index e664cae84..1e9f46fed 100644 --- a/src/material/block/misc/Bed.php +++ b/src/material/block/misc/Bed.php @@ -29,9 +29,9 @@ class BedBlock extends TransparentBlock{ public function onActivate(Item $item, Player $player){ if(ServerAPI::request()->api->time->getPhase($player->level) !== "night"){ - $player->dataPacket(MC_CLIENT_MESSAGE, array( - "message" => "You can only sleep at night" - )); + $pk = new ChatPacket; + $pk->message = "You can only sleep at night"; + $player->dataPacket($pk); return true; } @@ -51,17 +51,17 @@ class BedBlock extends TransparentBlock{ }elseif($blockWest->getID() === $this->id and ($blockWest->meta & 0x08) === 0x08){ $b = $blockWest; }else{ - $player->dataPacket(MC_CLIENT_MESSAGE, array( - "message" => "The bed is incomplete" - )); + $pk = new ChatPacket; + $pk->message = "This bed is incomplete"; + $player->dataPacket($pk); return true; } } if($player->sleepOn($b) === false){ - $player->dataPacket(MC_CLIENT_MESSAGE, array( - "message" => "This bed is occupied" - )); + $pk = new ChatPacket; + $pk->message = "This bed is occupied"; + $player->dataPacket($pk); } return true; } diff --git a/src/network/CustomPacketHandler.php b/src/network/CustomPacketHandler.php deleted file mode 100644 index 9bd9d9678..000000000 --- a/src/network/CustomPacketHandler.php +++ /dev/null @@ -1,876 +0,0 @@ -raw, $this->offset); - if($check === true){ - $this->offset = strlen($this->raw); - } - return $data; - } - $data = substr($this->raw, $this->offset, $len); - if($check === true){ - $this->offset += $len; - } - return $data; - } - - private function feof(){ - return !isset($this->raw{$this->offset}); - } - - public function __construct($pid, $raw = "", $data = array(), $create = false){ - $this->raw = $raw; - $this->data = $data; - $this->offset = 0; - $this->c = (bool) $create; - if($pid === false){ - return; - } - switch($pid){ - case MC_PING: - if($this->c === false){ - $this->data["time"] = Utils::readLong($this->get(8)); - }else{ - $this->raw .= Utils::writeLong($this->data["time"]); - } - break; - case MC_PONG: - if($this->c === false){ - $this->data["ptime"] = Utils::readLong($this->get(8)); - $this->data["time"] = Utils::readLong($this->get(8)); - }else{ - $this->raw .= Utils::writeLong($this->data["ptime"]); - $this->raw .= Utils::writeLong($this->data["time"]); - } - break; - case MC_CLIENT_CONNECT: - if($this->c === false){ - $this->data["clientID"] = Utils::readLong($this->get(8)); - $this->data["session"] = Utils::readLong($this->get(8)); - $this->data["unknown2"] = $this->get(1); - }else{ - $this->raw .= Utils::writeLong($this->data["clientID"]); - $this->raw .= Utils::writeLong($this->data["session"]); - $this->raw .= "\x00"; - } - break; - case MC_SERVER_HANDSHAKE: - if($this->c === false){ - $this->data["cookie"] = $this->get(4); // 043f57fe - $this->data["security"] = $this->get(1); - $this->data["port"] = Utils::readShort($this->get(2), false); - $this->data["dataArray"] = Utils::readDataArray($this->get(true, false), 10, $offset); - $this->get($offset); - $this->data["timestamp"] = $this->get(2); - $this->data["session"] = Utils::readLong($this->get(8)); - $this->data["session2"] = Utils::readLong($this->get(8)); - }else{ - $this->raw .= "\x04\x3f\x57\xfe"; - $this->raw .= "\xcd"; - $this->raw .= Utils::writeShort($this->data["port"]); - $this->raw .= Utils::writeDataArray(array( - "\xf5\xff\xff\xf5", - "\xff\xff\xff\xff", - "\xff\xff\xff\xff", - "\xff\xff\xff\xff", - "\xff\xff\xff\xff", - "\xff\xff\xff\xff", - "\xff\xff\xff\xff", - "\xff\xff\xff\xff", - "\xff\xff\xff\xff", - "\xff\xff\xff\xff", - )); - $this->raw .= "\x00\x00"; - $this->raw .= Utils::writeLong($this->data["session"]); - $this->raw .= Utils::writeLong($this->data["session2"]); - } - break; - case MC_CLIENT_HANDSHAKE: - if($this->c === false){ - $this->data["cookie"] = $this->get(4); // 043f57fe - $this->data["security"] = $this->get(1); - $this->data["port"] = Utils::readShort($this->get(2), false); - $this->data["dataArray0"] = $this->get(ord($this->get(1))); - $this->data["dataArray"] = Utils::readDataArray($this->get(true, false), 9, $offset); - $this->get($offset); - $this->data["timestamp"] = $this->get(2); - $this->data["session2"] = Utils::readLong($this->get(8)); - $this->data["session"] = Utils::readLong($this->get(8)); - }else{ - $this->raw .= "\x04\x3f\x57\xfe"; - $this->raw .= "\xed"; - $this->raw .= Utils::writeShort($this->data["port"]); - $w = array_shift($this->data["dataArray"]); - $this->raw .= chr(strlen($w)).$w; - $this->raw .= Utils::writeDataArray($this->data["dataArray"]); - $this->raw .= "\x00\x00"; - $this->raw .= Utils::writeLong($this->data["session2"]); - $this->raw .= Utils::writeLong($this->data["session"]); - } - break; - case MC_SERVER_FULL: - if($this->c === false){ - }else{ - $this->raw .= RAKNET_MAGIC; - $this->raw .= Utils::writeLong($this->data["serverID"]); - } - break; - case MC_DISCONNECT: - //null - break; - case MC_BANNED: - if($this->c === false){ - }else{ - $this->raw .= RAKNET_MAGIC; - $this->raw .= Utils::writeLong($this->data["serverID"]); - } - break; - case MC_LOGIN: - if($this->c === false){ - $this->data["username"] = $this->get(Utils::readShort($this->get(2), false)); - $this->data["protocol1"] = Utils::readInt($this->get(4)); - $this->data["protocol2"] = Utils::readInt($this->get(4)); - $this->data["clientId"] = Utils::readInt($this->get(4)); - $this->data["realms_data"] = $this->get(Utils::readShort($this->get(2), false)); - }else{ - $this->raw .= Utils::writeShort(strlen($this->data["username"])).$this->data["username"]; - $this->raw .= Utils::writeInt(CURRENT_PROTOCOL). - Utils::writeInt(CURRENT_PROTOCOL). - Utils::writeInt($this->data["clientId"]); - $this->raw .= Utils::writeShort(strlen($this->data["realms_data"])).$this->data["realms_data"]; - } - break; - case MC_LOGIN_STATUS: - if($this->c === false){ - $this->data["status"] = Utils::readInt($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["status"]); - } - break; - case MC_READY: - if($this->c === false){ - $this->data["status"] = ord($this->get(1)); - }else{ - $this->raw .= chr($this->data["status"]); - } - break; - case MC_CHAT: - if($this->c === false){ - $this->data["player"] = $this->get(Utils::readShort($this->get(2), false)); - $this->data["message"] = $this->get(Utils::readShort($this->get(2), false)); - }else{ - $this->raw .= Utils::writeShort(strlen($this->data["player"])).$this->data["player"]; - $this->raw .= Utils::writeShort(strlen($this->data["message"])).$this->data["message"]; - } - break; - case MC_SET_TIME: - if($this->c === false){ - $this->data["time"] = Utils::readInt($this->get(4)); - $this->data["started"] = ord($this->get(1)) & 0x80 > 0; - }else{ - $this->raw .= Utils::writeInt($this->data["time"])."\x80"; - $this->raw .= chr((isset($this->data["started"]) and $this->data["started"] == true) ? 0x80:0x00); - } - break; - case MC_START_GAME: - if($this->c === false){ - $this->data["seed"] = Utils::readInt($this->get(4)); - $this->data["generator"] = Utils::readInt($this->get(4)); - $this->data["gamemode"] = Utils::readInt($this->get(4)); - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["x"] = Utils::readFloat($this->get(4)); - $this->data["y"] = Utils::readFloat($this->get(4)); - $this->data["z"] = Utils::readFloat($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["seed"]); - $this->raw .= Utils::writeInt($this->data["generator"]); - $this->raw .= Utils::writeInt($this->data["gamemode"]); - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeFloat($this->data["x"]); - $this->raw .= Utils::writeFloat($this->data["y"]); - $this->raw .= Utils::writeFloat($this->data["z"]); - } - break; - case MC_ADD_MOB: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["type"] = Utils::readInt($this->get(4)); - $this->data["x"] = Utils::readFloat($this->get(4)); - $this->data["y"] = Utils::readFloat($this->get(4)); - $this->data["z"] = Utils::readFloat($this->get(4)); - $this->data["pitch"] = Utils::readByte($this->get(1)); - $this->data["yaw"] = Utils::readByte($this->get(1)); - $this->data["metadata"] = Utils::readMetadata($this->get(true)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeInt($this->data["type"]); - $this->raw .= Utils::writeFloat($this->data["x"]); - $this->raw .= Utils::writeFloat($this->data["y"]); - $this->raw .= Utils::writeFloat($this->data["z"]); - $this->raw .= Utils::writeByte($this->data["pitch"]); - $this->raw .= Utils::writeByte($this->data["yaw"]); - $this->raw .= Utils::writeMetadata($this->data["metadata"]); - } - break; - case MC_ADD_PLAYER: - if($this->c === false){ - $this->data["clientID"] = Utils::readLong($this->get(8)); - $this->data["username"] = $this->get(Utils::readShort($this->get(2), false)); - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["x"] = Utils::readFloat($this->get(4)); - $this->data["y"] = Utils::readFloat($this->get(4)); - $this->data["z"] = Utils::readFloat($this->get(4)); - $this->data["pitch"] = Utils::readByte($this->get(1)); - $this->data["yaw"] = Utils::readByte($this->get(1)); - $this->data["unknown1"] = Utils::readShort($this->get(2)); - $this->data["unknown2"] = Utils::readShort($this->get(2)); - $this->data["metadata"] = Utils::readMetadata($this->get(true)); - }else{ - $this->raw .= Utils::writeLong($this->data["clientID"]); - $this->raw .= Utils::writeShort(strlen($this->data["username"])).$this->data["username"]; - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeFloat($this->data["x"]); - $this->raw .= Utils::writeFloat($this->data["y"]); - $this->raw .= Utils::writeFloat($this->data["z"]); - $this->raw .= Utils::writeByte($this->data["pitch"]); - $this->raw .= Utils::writeByte($this->data["yaw"]); - $this->raw .= Utils::writeShort($this->data["unknown1"]); - $this->raw .= Utils::writeShort($this->data["unknown2"]); - $this->raw .= Utils::writeMetadata($this->data["metadata"]); - } - break; - case MC_REMOVE_PLAYER: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["clientID"] = Utils::readLong($this->get(8)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeLong($this->data["clientID"]); - } - break; - case MC_ADD_ENTITY: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["type"] = ord($this->get(1)); - $this->data["x"] = Utils::readFloat($this->get(4)); - $this->data["y"] = Utils::readFloat($this->get(4)); - $this->data["z"] = Utils::readFloat($this->get(4)); - $this->data["did"] = Utils::readInt($this->get(4)); - if($this->data["did"] > 0){ - $this->data["speedX"] = Utils::readShort($this->get(2)); - $this->data["speedY"] = Utils::readShort($this->get(2)); - $this->data["speedZ"] = Utils::readShort($this->get(2)); - } - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= chr($this->data["type"]); - $this->raw .= Utils::writeFloat($this->data["x"]); - $this->raw .= Utils::writeFloat($this->data["y"]); - $this->raw .= Utils::writeFloat($this->data["z"]); - $this->raw .= Utils::writeInt($this->data["did"]); - if($this->data["did"] > 0){ - $this->raw .= Utils::writeShort($this->data["speedX"]); - $this->raw .= Utils::writeShort($this->data["speedY"]); - $this->raw .= Utils::writeShort($this->data["speedZ"]); - } - } - break; - case MC_REMOVE_ENTITY: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - } - break; - case MC_ADD_ITEM_ENTITY: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["block"] = Utils::readShort($this->get(2), false); - $this->data["stack"] = ord($this->get(1)); - $this->data["meta"] = Utils::readShort($this->get(2), false); - $this->data["x"] = Utils::readFloat($this->get(4)); - $this->data["y"] = Utils::readFloat($this->get(4)); - $this->data["z"] = Utils::readFloat($this->get(4)); - $this->data["yaw"] = Utils::readByte($this->get(1)); - $this->data["pitch"] = Utils::readByte($this->get(1)); - $this->data["roll"] = Utils::readByte($this->get(1)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeShort($this->data["block"]); - $this->raw .= chr($this->data["stack"]); - $this->raw .= Utils::writeShort($this->data["meta"]); - $this->raw .= Utils::writeFloat($this->data["x"]); - $this->raw .= Utils::writeFloat($this->data["y"]); - $this->raw .= Utils::writeFloat($this->data["z"]); - $this->raw .= Utils::writeByte($this->data["yaw"]); - $this->raw .= Utils::writeByte($this->data["pitch"]); - $this->raw .= Utils::writeByte($this->data["roll"]); - } - break; - case MC_TAKE_ITEM_ENTITY: - if($this->c === false){ - $this->data["target"] = Utils::readInt($this->get(4)); - $this->data["eid"] = Utils::readInt($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["target"]); - $this->raw .= Utils::writeInt($this->data["eid"]); - } - break; - case MC_MOVE_ENTITY: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["x"] = Utils::readFloat($this->get(4)); - $this->data["y"] = Utils::readFloat($this->get(4)); - $this->data["z"] = Utils::readFloat($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeFloat($this->data["x"]); - $this->raw .= Utils::writeFloat($this->data["y"]); - $this->raw .= Utils::writeFloat($this->data["z"]); - } - break; - case MC_MOVE_ENTITY_POSROT: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["x"] = Utils::readFloat($this->get(4)); - $this->data["y"] = Utils::readFloat($this->get(4)); - $this->data["z"] = Utils::readFloat($this->get(4)); - $this->data["yaw"] = Utils::readFloat($this->get(4)); - $this->data["pitch"] = Utils::readFloat($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeFloat($this->data["x"]); - $this->raw .= Utils::writeFloat($this->data["y"]); - $this->raw .= Utils::writeFloat($this->data["z"]); - $this->raw .= Utils::writeFloat($this->data["yaw"]); - $this->raw .= Utils::writeFloat($this->data["pitch"]); - } - break; - case MC_ROTATE_HEAD: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["yaw"] = Utils::readFloat($this->get(4)); - $this->data["pitch"] = Utils::readFloat($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeFloat($this->data["yaw"]); - $this->raw .= Utils::writeFloat($this->data["pitch"]); - } - break; - case MC_MOVE_PLAYER: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["x"] = Utils::readFloat($this->get(4)); - $this->data["y"] = Utils::readFloat($this->get(4)); - $this->data["z"] = Utils::readFloat($this->get(4)); - $this->data["yaw"] = Utils::readFloat($this->get(4)); - $this->data["pitch"] = Utils::readFloat($this->get(4)); - $this->data["bodyYaw"] = Utils::readFloat($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeFloat($this->data["x"]); - $this->raw .= Utils::writeFloat($this->data["y"]); - $this->raw .= Utils::writeFloat($this->data["z"]); - $this->raw .= Utils::writeFloat($this->data["yaw"]); - $this->raw .= Utils::writeFloat($this->data["pitch"]); - $this->raw .= Utils::writeFloat($this->data["bodyYaw"]); - } - break; - case MC_PLACE_BLOCK: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["x"] = Utils::readInt($this->get(4)); - $this->data["z"] = Utils::readInt($this->get(4)); - $this->data["y"] = ord($this->get(1)); - $this->data["block"] = ord($this->get(1)); - $this->data["meta"] = ord($this->get(1)); - $this->data["face"] = Utils::readByte($this->get(1)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeInt($this->data["x"]); - $this->raw .= Utils::writeInt($this->data["z"]); - $this->raw .= chr($this->data["y"]); - $this->raw .= chr($this->data["block"]); - $this->raw .= chr($this->data["meta"]); - $this->raw .= chr($this->data["face"]); - } - break; - case MC_REMOVE_BLOCK: //Sent when a player removes a block, not used - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["x"] = Utils::readInt($this->get(4)); - $this->data["z"] = Utils::readInt($this->get(4)); - $this->data["y"] = ord($this->get(1)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeInt($this->data["x"]); - $this->raw .= Utils::writeInt($this->data["z"]); - $this->raw .= chr($this->data["y"]); - } - break; - case MC_UPDATE_BLOCK: - if($this->c === false){ - $this->data["x"] = Utils::readInt($this->get(4)); - $this->data["z"] = Utils::readInt($this->get(4)); - $this->data["y"] = ord($this->get(1)); - $this->data["block"] = ord($this->get(1)); - $this->data["meta"] = ord($this->get(1)); - }else{ - $this->raw .= Utils::writeInt($this->data["x"]); - $this->raw .= Utils::writeInt($this->data["z"]); - $this->raw .= chr($this->data["y"]); - $this->raw .= chr($this->data["block"]); - $this->raw .= chr($this->data["meta"]); - } - break; - case MC_ADD_PAINTING: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["x"] = Utils::readInt($this->get(4)); - $this->data["y"] = Utils::readInt($this->get(4)); - $this->data["z"] = Utils::readInt($this->get(4)); - $this->data["direction"] = Utils::readInt($this->get(4)); - $this->data["title"] = $this->get(Utils::readShort($this->get(2), false)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeInt($this->data["x"]); - $this->raw .= Utils::writeInt($this->data["y"]); - $this->raw .= Utils::writeInt($this->data["z"]); - $this->raw .= Utils::writeInt($this->data["direction"]); - $this->raw .= Utils::writeShort(strlen($this->data["title"])).$this->data["title"]; - } - break; - case MC_EXPLOSION: - if($this->c === false){ - $this->data["x"] = Utils::readFloat($this->get(4)); - $this->data["y"] = Utils::readFloat($this->get(4)); - $this->data["z"] = Utils::readFloat($this->get(4)); - $this->data["radius"] = Utils::readFloat($this->get(4)); - $this->data["count"] = Utils::readInt($this->get(4)); - $this->data["records"] = array(); - for($r = 0; $r < $this->data["count"] and !$this->feof(); ++$r){ - $this->data["records"][] = new Vector3(Utils::readByte($this->get(1)), Utils::readByte($this->get(1)), Utils::readByte($this->get(1))); - } - }else{ - $this->raw .= Utils::writeFloat($this->data["x"]); - $this->raw .= Utils::writeFloat($this->data["y"]); - $this->raw .= Utils::writeFloat($this->data["z"]); - $this->raw .= Utils::writeFloat($this->data["radius"]); - $this->data["records"] = (array) $this->data["records"]; - $this->raw .= Utils::writeInt(count($this->data["records"])); - if(count($this->data["records"]) > 0){ - foreach($this->data["records"] as $record){ - $this->raw .= Utils::writeByte($record->x) . Utils::writeByte($record->y) . Utils::writeByte($record->z); - } - } - } - break; - case MC_LEVEL_EVENT: - if($this->c === false){ - $this->data["evid"] = Utils::readShort($this->get(2)); - $this->data["x"] = Utils::readShort($this->get(2)); - $this->data["y"] = Utils::readShort($this->get(2)); - $this->data["z"] = Utils::readShort($this->get(2)); - $this->data["data"] = Utils::readInt($this->get(4)); - }else{ - $this->raw .= Utils::writeShort($this->data["evid"]); - $this->raw .= Utils::writeShort($this->data["x"]); - $this->raw .= Utils::writeShort($this->data["y"]); - $this->raw .= Utils::writeShort($this->data["z"]); - $this->raw .= Utils::writeInt($this->data["data"]); - } - break; - case MC_TILE_EVENT: - if($this->c === false){ - $this->data["x"] = Utils::readInt($this->get(4)); - $this->data["y"] = Utils::readInt($this->get(4)); - $this->data["z"] = Utils::readInt($this->get(4)); - $this->data["case1"] = Utils::readInt($this->get(4)); - $this->data["case2"] = Utils::readInt($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["x"]); - $this->raw .= Utils::writeInt($this->data["y"]); - $this->raw .= Utils::writeInt($this->data["z"]); - $this->raw .= Utils::writeInt($this->data["case1"]); - $this->raw .= Utils::writeInt($this->data["case2"]); - } - break; - case MC_ENTITY_EVENT: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["event"] = ord($this->get(1)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= chr($this->data["event"]); - } - break; - case MC_REQUEST_CHUNK: - if($this->c === false){ - $this->data["x"] = Utils::readInt($this->get(4)); - $this->data["z"] = Utils::readInt($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["x"]); - $this->raw .= Utils::writeInt($this->data["z"]); - } - break; - case MC_CHUNK_DATA: - if($this->c === false){ - $this->data["x"] = Utils::readInt($this->get(4)); - $this->data["z"] = Utils::readInt($this->get(4)); - $this->data["data"] = $this->get(true); - }else{ - $this->raw .= Utils::writeInt($this->data["x"]); - $this->raw .= Utils::writeInt($this->data["z"]); - $this->raw .= $this->data["data"]; - } - break; - case MC_PLAYER_EQUIPMENT: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["block"] = Utils::readShort($this->get(2), false); - $this->data["meta"] = Utils::readShort($this->get(2), false); - $this->data["slot"] = ord($this->get(1)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeShort($this->data["block"]); - $this->raw .= Utils::writeShort($this->data["meta"]); - $this->raw .= chr($this->data["slot"]); - } - break; - case MC_PLAYER_ARMOR_EQUIPMENT: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["slot0"] = ord($this->get(1)); - $this->data["slot1"] = ord($this->get(1)); - $this->data["slot2"] = ord($this->get(1)); - $this->data["slot3"] = ord($this->get(1)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= chr($this->data["slot0"]); - $this->raw .= chr($this->data["slot1"]); - $this->raw .= chr($this->data["slot2"]); - $this->raw .= chr($this->data["slot3"]); - } - break; - case MC_INTERACT: - if($this->c === false){ - $this->data["action"] = Utils::readByte($this->get(1)); - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["target"] = Utils::readInt($this->get(4)); - }else{ - $this->raw .= Utils::writeByte($this->data["action"]); - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeInt($this->data["target"]); - } - break; - case MC_USE_ITEM: - if($this->c === false){ - $this->data["x"] = Utils::readInt($this->get(4)); - $this->data["y"] = Utils::readInt($this->get(4)); - $this->data["z"] = Utils::readInt($this->get(4)); - $this->data["face"] = Utils::readInt($this->get(4)); - $this->data["block"] = Utils::readShort($this->get(2)); - $this->data["meta"] = Utils::readByte($this->get(1)); - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["fx"] = Utils::readFloat($this->get(4)); - $this->data["fy"] = Utils::readFloat($this->get(4)); - $this->data["fz"] = Utils::readFloat($this->get(4)); - $this->data["posX"] = Utils::readFloat($this->get(4)); - $this->data["posY"] = Utils::readFloat($this->get(4)); - $this->data["posZ"] = Utils::readFloat($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["x"]); - $this->raw .= Utils::writeInt($this->data["y"]); - $this->raw .= Utils::writeInt($this->data["z"]); - $this->raw .= Utils::writeInt($this->data["face"]); - $this->raw .= Utils::writeShort($this->data["block"]); - $this->raw .= Utils::writeByte($this->data["meta"]); - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeFloat($this->data["fx"]); - $this->raw .= Utils::writeFloat($this->data["fy"]); - $this->raw .= Utils::writeFloat($this->data["fz"]); - $this->raw .= Utils::writeFloat($this->data["posX"]); - $this->raw .= Utils::writeFloat($this->data["posY"]); - $this->raw .= Utils::writeFloat($this->data["posZ"]); - } - break; - case MC_PLAYER_ACTION: - if($this->c === false){ - $this->data["action"] = Utils::readInt($this->get(4)); - $this->data["x"] = Utils::readInt($this->get(4)); - $this->data["y"] = Utils::readInt($this->get(4)); - $this->data["z"] = Utils::readInt($this->get(4)); - $this->data["face"] = Utils::readInt($this->get(4)); - $this->data["eid"] = Utils::readInt($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["action"]); - $this->raw .= Utils::writeInt($this->data["x"]); - $this->raw .= Utils::writeInt($this->data["y"]); - $this->raw .= Utils::writeInt($this->data["z"]); - $this->raw .= Utils::writeInt($this->data["face"]); - $this->raw .= Utils::writeInt($this->data["eid"]); - } - break; - case MC_SET_ENTITY_DATA: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["metadata"] = Utils::readMetadata($this->get(true)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeMetadata($this->data["metadata"]); - } - break; - case MC_SET_ENTITY_MOTION: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["speedX"] = Utils::readShort($this->get(2)); - $this->data["speedY"] = Utils::readShort($this->get(2)); - $this->data["speedZ"] = Utils::readShort($this->get(2)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeShort($this->data["speedX"]); - $this->raw .= Utils::writeShort($this->data["speedY"]); - $this->raw .= Utils::writeShort($this->data["speedZ"]); - } - break; - case MC_HURT_ARMOR: - if($this->c === false){ - $this->data["health"] = Utils::readByte($this->get(1)); - }else{ - $this->raw .= Utils::writeByte($this->data["health"]); - } - break; - case MC_SET_HEALTH: - if($this->c === false){ - $this->data["health"] = Utils::readByte($this->get(1)); - }else{ - $this->raw .= Utils::writeByte($this->data["health"]); - } - break; - case MC_SET_SPAWN_POSITION: - if($this->c === false){ - $this->data["x"] = Utils::readInt($this->get(4)); - $this->data["z"] = Utils::readInt($this->get(4)); - $this->data["y"] = ord($this->get(1)); - }else{ - $this->raw .= Utils::writeInt($this->data["x"]); - $this->raw .= Utils::writeInt($this->data["z"]); - $this->raw .= chr($this->data["y"]); - } - break; - case MC_ANIMATE: - if($this->c === false){ - $this->data["action"] = Utils::readByte($this->get(1)); - $this->data["eid"] = Utils::readInt($this->get(4)); - }else{ - $this->raw .= Utils::writeByte($this->data["action"]); - $this->raw .= Utils::writeInt($this->data["eid"]); - } - break; - case MC_RESPAWN: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["x"] = Utils::readFloat($this->get(4)); - $this->data["y"] = Utils::readFloat($this->get(4)); - $this->data["z"] = Utils::readFloat($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= Utils::writeFloat($this->data["x"]); - $this->raw .= Utils::writeFloat($this->data["y"]); - $this->raw .= Utils::writeFloat($this->data["z"]); - } - break; - case MC_SEND_INVENTORY: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["windowid"] = ord($this->get(1)); - $this->data["count"] = Utils::readShort($this->get(2), false); - $this->data["slots"] = array(); - for($s = 0; $s < $this->data["count"] and !$this->feof(); ++$s){ - $this->data["slots"][$s] = Utils::readSlot($this); - } - if($this->data["windowid"] === 1){ //Armor is also sent - $this->data["armor"] = array( - Utils::readSlot($this), - Utils::readSlot($this), - Utils::readSlot($this), - Utils::readSlot($this) - ); - } - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= chr($this->data["windowid"]); - $this->raw .= Utils::writeShort(count($this->data["slots"])); - foreach($this->data["slots"] as $slot){ - $this->raw .= Utils::writeSlot($slot); - } - if($this->data["windowid"] === 1 and isset($this->data["armor"])){ - $this->raw .= Utils::writeSlot($this->data["armor"][0]); - $this->raw .= Utils::writeSlot($this->data["armor"][1]); - $this->raw .= Utils::writeSlot($this->data["armor"][2]); - $this->raw .= Utils::writeSlot($this->data["armor"][3]); - } - } - break; - case MC_DROP_ITEM: - if($this->c === false){ - $this->data["eid"] = Utils::readInt($this->get(4)); - $this->data["unknown1"] = ord($this->get(1)); - $this->data["block"] = Utils::readShort($this->get(2), false); - $this->data["stack"] = ord($this->get(1)); - $this->data["meta"] = Utils::readShort($this->get(2), false); - }else{ - $this->raw .= Utils::writeInt($this->data["eid"]); - $this->raw .= chr($this->data["unknown1"]); - $this->raw .= Utils::writeShort($this->data["block"]); - $this->raw .= chr($this->data["stack"]); - $this->raw .= Utils::writeShort($this->data["meta"]); - } - break; - case MC_CONTAINER_OPEN: - if($this->c === false){ - $this->data["windowid"] = ord($this->get(1)); - $this->data["type"] = ord($this->get(1)); - $this->data["slots"] = ord($this->get(1)); - - //$this->data["title"] = $this->get(Utils::readShort($this->get(2), false)); - }else{ - $this->raw .= chr($this->data["windowid"]); - $this->raw .= chr($this->data["type"]); - $this->raw .= chr($this->data["slots"]); - $this->raw .= Utils::writeInt($this->data["x"]); - $this->raw .= Utils::writeInt($this->data["y"]); - $this->raw .= Utils::writeInt($this->data["z"]); - } - break; - case MC_CONTAINER_CLOSE: - if($this->c === false){ - $this->data["windowid"] = ord($this->get(1)); - }else{ - $this->raw .= chr($this->data["windowid"]); - } - break; - case MC_CONTAINER_SET_SLOT: - if($this->c === false){ - $this->data["windowid"] = ord($this->get(1)); - $this->data["slot"] = Utils::readShort($this->get(2), false); - $this->data["block"] = Utils::readShort($this->get(2), false); - $this->data["stack"] = ord($this->get(1)); - $this->data["meta"] = Utils::readShort($this->get(2), false); - }else{ - $this->raw .= chr($this->data["windowid"]); - $this->raw .= Utils::writeShort($this->data["slot"]); - $this->raw .= Utils::writeShort($this->data["block"]); - $this->raw .= chr($this->data["stack"]); - $this->raw .= Utils::writeShort($this->data["meta"]); - } - break; - case MC_CONTAINER_SET_CONTENT: - if($this->c === false){ - $this->data["windowid"] = ord($this->get(1)); - $this->data["count"] = Utils::readShort($this->get(2), false); - $this->data["slots"] = array(); - for($s = 0; $s < $this->data["count"] and !$this->feof(); ++$s){ - $this->data["slots"][$s] = Utils::readSlot($this); - } - if($this->data["windowid"] == 0){ - $slots = min(9, Utils::readShort($this->get(2), false)); - $this->data["hotbar"] = array(); - if($slots > 0){ - for($s = 0; $s < $slots; ++$s){ - $this->data["hotbar"][$s] = Utils::readInt($this->get(4)); - } - } - } - }else{ - $this->raw .= chr($this->data["windowid"]); - $this->raw .= Utils::writeShort(count($this->data["slots"])); - foreach($this->data["slots"] as $slot){ - $this->raw .= Utils::writeSlot($slot); - } - if($this->data["windowid"] == 0 and isset($this->data["hotbar"])){ - if(count($this->data["hotbar"]) > 0){ - $this->raw .= Utils::writeShort(count($this->data["hotbar"])); - foreach($this->data["hotbar"] as $slot){ - $this->raw .= Utils::writeInt($slot); - } - } - } - } - break; - case MC_CONTAINER_SET_DATA: - if($this->c === false){ - $this->data["windowid"] = ord($this->get(1)); - $this->data["property"] = Utils::readShort($this->get(2)); - $this->data["value"] = Utils::readShort($this->get(2)); - }else{ - $this->raw .= chr($this->data["windowid"]); - $this->raw .= Utils::writeShort($this->data["property"]); - $this->raw .= Utils::writeShort($this->data["value"]); - } - break; - case MC_CLIENT_MESSAGE: - if($this->c === false){ - $this->data["message"] = $this->get(Utils::readShort($this->get(2), false)); - }else{ - $this->raw .= Utils::writeShort(strlen($this->data["message"])).$this->data["message"]; - } - break; - case MC_ADVENTURE_SETTINGS: - if($this->c === false){ - $this->data["flags"] = Utils::readInt($this->get(4)); - }else{ - $this->raw .= Utils::writeInt($this->data["flags"]); - } - break; - case MC_ENTITY_DATA: - if($this->c === false){ - $this->data["x"] = Utils::readShort($this->get(2)); - $this->data["y"] = ord($this->get(1)); - $this->data["z"] = Utils::readShort($this->get(2)); - $this->data["namedtag"] = $this->get(true); - }else{ - $this->raw .= Utils::writeShort($this->data["x"]); - $this->raw .= chr($this->data["y"]); - $this->raw .= Utils::writeShort($this->data["z"]); - $this->raw .= $this->data["namedtag"]; - } - break; - default: - if($this->c === false){ - console("[DEBUG] Received unknown Data Packet ID 0x".dechex($pid), true, true, 2); - }else{ - console("[DEBUG] Sent unknown Data Packet ID 0x".dechex($pid), true, true, 2); - } - break; - } - } - -} \ No newline at end of file diff --git a/src/network/MinecraftInterface.php b/src/network/MinecraftInterface.php index f3288c9e4..f7e149c04 100644 --- a/src/network/MinecraftInterface.php +++ b/src/network/MinecraftInterface.php @@ -20,241 +20,80 @@ */ class MinecraftInterface{ - public $client; public $bandwidth; private $socket; - private $data; - private $chunked; - private $toChunk; - private $needCheck; - function __construct($object, $server, $port = 25565, $listen = false, $client = false, $serverip = "0.0.0.0"){ - $this->socket = new UDPSocket($server, $port, (bool) $listen, $serverip); + private $packets; + function __construct($server, $port = 25565, $serverip = "0.0.0.0"){ + $this->socket = new UDPSocket($server, $port, true, $serverip); if($this->socket->connected === false){ - console("[ERROR] Couldn't bind to $serverip:".$port, true, true, 0); + console("[SEVERE] Couldn't bind to $serverip:".$port, true, true, 0); exit(1); } $this->bandwidth = array(0, 0, microtime(true)); - $this->client = (bool) $client; $this->start = microtime(true); - $this->chunked = array(); - $this->toChunk = array(); - $this->needCheck = array(); - $object->schedule(1, array($this, "checkChunked"), array(), true); + $this->packets = array(); } public function close(){ return $this->socket->close(false); } - protected function getStruct($pid){ - if(isset(Protocol::$raknet[$pid])){ - return Protocol::$raknet[$pid]; - } - return false; - } - public function readPacket(){ - $pk = $this->popPacket(); if($this->socket->connected === false){ - return $pk; + return false; } $buf = ""; $source = false; $port = 1; $len = $this->socket->read($buf, $source, $port); if($len === false or $len === 0){ - return $pk; + return false; } $this->bandwidth[0] += $len; - $this->parsePacket($buf, $source, $port); - return ($pk !== false ? $pk : $this->popPacket()); + return $this->parsePacket($buf, $source, $port); } - private function parsePacket($buf, $source, $port){ - $pid = ord($buf{0}); - $struct = $this->getStruct($pid); - if($struct === false){ - if(ServerAPI::request()->api->dhandle("server.unknownpacket", array( - "pid" => $pid, - "data" => array(), - "raw" => $buf, - "ip" => $source, - "port" => $port - )) !== true){ - console("[ERROR] Unknown Packet ID 0x".Utils::strToHex(chr($pid)), true, true, 2); + private function parsePacket($buffer, $source, $port){ + $pid = ord($buffer{0}); + + if(RakNetInfo::isValid($pid)){ + $parser = new RakNetParser($buffer); + if($parser->packet !== false){ + $parser->packet->ip = $source; + $parser->packet->port = $port; + if(EventHandler::callEvent(new PacketReceiveEvent($parser->packet)) === BaseEvent::DENY){ + return false; + } + return $parser->packet; } return false; - } - - $packet = new Packet($pid, $struct, $buf); - @$packet->parse(); - if($pid === 0x99){ - $CID = PocketMinecraftServer::clientID($source, $port); - if(!isset($this->chunked[$CID]) and $packet->data[0] !== 0){ //Drop packet + }elseif($pid === 0xfe and $buffer{1} === "\xfd" and ServerAPI::request()->api->query instanceof QueryHandler){ + $packet = new QueryPacket; + $packet->ip = $source; + $packet->port = $port; + $packet->buffer = $buffer; + if(EventHandler::callEvent(new PacketReceiveEvent($packet)) === BaseEvent::DENY){ return false; } - switch($packet->data[0]){ - case 0: - $this->initChunked($CID, $source, $port); - return false; - case 1: - $this->stopChunked($CID); - return false; - case 3: - $this->ackChunked($CID, $data[1]["id"], $data[1]["index"]); - return false; - case 4: - $this->receiveChunked($CID, $data[1]["id"], $data[1]["index"], $data[1]["count"], $data[1]["data"]); - return true; - } - } - $this->data[] = array($pid, $packet->data, $buf, $source, $port); - return true; - } - - public function checkChunked($CID){ - $time = microtime(true); - foreach($this->needCheck as $CID => $packets){ - if($packets[-1] < $time){ - $d = $this->chunked[$CID]; - unset($packets[-1]); - foreach($packets as $packet){ - $this->writePacket(0x99, $packet, true, $d[1], $d[2], true); - } - $this->needCheck[$CID][-1] = $time + 5; - } - } - foreach($this->toChunk as $CID => $packets){ - $d = $this->chunked[$CID]; - $raw = ""; - $MTU = 512; - foreach($packets as $packet){ - $raw .= $packet; - if(($len = strlen($packet)) > $MTU){ - $MTU = $len; - } - } - if($MTU > $d[0][2]){ - $this->chunked[$CID][0][2] = $MTU; - }else{ - $MTU = $d[0][2]; - } - $raw = str_split(gzdeflate($raw, DEFLATEPACKET_LEVEL), $MTU - 9); // - 1 - 2 - 2 - 2 - 2 - $count = count($raw); - $messageID = $this->chunked[$CID][0][0]++; - $this->chunked[$CID][0][0] &= 0xFFFF; - if(!isset($this->needCheck[$CID])){ - $this->needCheck[$CID] = array(); - } - $this->needCheck[$CID][$messageID] = array(-1 => $time + 1); - foreach($raw as $index => $r){ - $p = "\x99\x02".Utils::writeShort($messageID).Utils::writeShort($index).Utils::writeShort($count).Utils::writeShort(strlen($r)).$r; - $this->needCheck[$CID][$messageID][$index] = $p; - $this->writePacket(0x99, $p, true, $d[1], $d[2], true); - } - unset($this->toChunk[$CID]); - } - } - - public function isChunked($CID){ - return isset($this->chunked[$CID]); - } - - private function initChunked($CID, $source, $port){ - console("[DEBUG] Starting DEFLATEPacket for $source:$port", true, true, 2); - $this->chunked[$CID] = array( - 0 => array(0, 0, 0), //index, sent/received; MTU - 1 => $source, - 2 => $port, - 3 => array(), //Received packets - ); - $this->writePacket(0x99, array( - 0 => 0, //start - ), false, $source, $port, true); - } - - public function stopChunked($CID){ - if(!isset($this->chunked[$CID])){ + ServerAPI::request()->api->query->handle($packet); + }else{ + $packet = new Packet(); + $packet->ip = $source; + $packet->port = $port; + $packet->buffer = $buffer; + EventHandler::callEvent(new PacketReceiveEvent($packet)); return false; } - $this->writePacket(0x99, array( - 0 => 1, //stop - ), false, $this->chunked[$CID][1], $this->chunked[$CID][2], true); - console("[DEBUG] Stopping DEFLATEPacket for ".$this->chunked[$CID][1].":".$this->chunked[$CID][2], true, true, 2); - $this->chunked[$CID][3] = null; - $this->chunked[$CID][4] = null; - unset($this->chunked[$CID]); - unset($this->toChunk[$CID]); - unset($this->needCheck[$CID]); } - private function ackChunked($CID, $ID, $index){ - unset($this->needCheck[$CID][$ID][$index]); - if(count($this->needCheck[$CID][$ID]) <= 1){ - unset($this->needCheck[$CID][$ID]); - } - } - - private function receiveChunked($CID, $ID, $index, $count, $data){ - if(!isset($this->chunked[$CID][3][$ID])){ - $this->chunked[$CID][3][$ID] = array(); - } - $this->chunked[$CID][3][$ID][$index] = $data; - - if(count($this->chunked[$CID][3][$ID]) === $count){ - ksort($this->chunked[$CID][3][$ID]); - $data = gzinflate(implode($this->chunked[$CID][3][$ID]), 524280); - unset($this->chunked[$CID][3][$ID]); - if($data === false or strlen($data) === 0){ - console("[ERROR] Invalid DEFLATEPacket for ".$this->chunked[$CID][1].":".$this->chunked[$CID][2], true, true, 2); - } - $offset = 0; - while(($plen = Utils::readShort(substr($data, $offset, 2), false)) !== 0xFFFF or $offset >= $len){ - $offset += 2; - $packet = substr($data, $offset, $plen); - $this->parsePacket($packet, $this->chunked[$CID][1], $this->chunked[$CID][2]); - } - } - } - - public function popPacket(){ - if(count($this->data) > 0){ - $p = each($this->data); - unset($this->data[$p[0]]); - $p = $p[1]; - return array("pid" => $p[0], "data" => $p[1], "raw" => $p[2], "ip" => $p[3], "port" => $p[4]); - } - return false; - } - - public function writePacket($pid, $data = array(), $raw = false, $dest = false, $port = false, $force = false){ - $CID = PocketMinecraftServer::clientID($dest, $port); - if($raw === false){ - $packet = new Packet($pid, $this->getStruct($pid)); - $packet->data = $data; - @$packet->create(); - if($force === false and $this->isChunked($CID)){ - if(!isset($this->toChunk[$CID])){ - $this->toChunk[$CID] = array(); - } - $this->toChunk[$CID][] = $packet->raw; - $write = strlen($packet->raw); - }else{ - $write = $this->socket->write($packet->raw, $dest, $port); - $this->bandwidth[1] += $write; - } - }else{ - if($force === false and $this->isChunked($CID)){ - if(!isset($this->toChunk[$CID])){ - $this->toChunk[$CID] = array(); - } - $this->toChunk[$CID][] = $data; - $write = strlen($data); - }else{ - $write = $this->socket->write($data, $dest, $port); - $this->bandwidth[1] += $write; - } + public function writePacket(Packet $packet){ + if(EventHandler::callEvent(new PacketSendEvent($packet)) === BaseEvent::DENY){ + return 0; + }elseif($packet instanceof RakNetPacket){ + $codec = new RakNetCodec($packet); } + $write = $this->socket->write($packet->buffer, $packet->ip, $packet->port); + $this->bandwidth[1] += $write; return $write; } diff --git a/src/network/Packet.php b/src/network/Packet.php index 578e94685..abfa75f9b 100644 --- a/src/network/Packet.php +++ b/src/network/Packet.php @@ -19,325 +19,9 @@ * */ - -class Packet{ - private $struct; - protected $pid, $packet; - public $data, $raw; - - function __construct($pid, $struct, $data = ""){ - $this->pid = $pid; - $this->offset = 1; - $this->raw = $data; - $this->data = array(); - if($data === ""){ - $this->addRaw(chr($pid)); - } - $this->struct = $struct; - } - - public function create($raw = false){ - foreach($this->struct as $field => $type){ - if(!isset($this->data[$field])){ - $this->data[$field] = ""; - } - if($raw === true){ - $this->addRaw($this->data[$field]); - continue; - } - switch($type){ - case "special1": - switch($this->pid){ - case 0x99: - if($this->data[0] >= 2){ - $this->addRaw(Utils::writeShort($this->data[1]["id"])); - $this->addRaw(Utils::writeShort($this->data[1]["index"])); - if($this->data[0] === 2){ - $this->addRaw(Utils::writeShort($this->data[1]["count"])); - $this->addRaw(Utils::writeShort(strlen($this->data[1]["data"])).$this->data[1]["data"]); - } - } - break; - case 0xc0: - case 0xa0: - $payload = ""; - $records = 0; - $pointer = 0; - sort($this->data[$field], SORT_NUMERIC); - $max = count($this->data[$field]); - while($pointer < $max){ - $type = true; - $curr = $start = $this->data[$field][$pointer]; - for($i = $start + 1; $i < $max; ++$i){ - $n = $this->data[$field][$i]; - if(($n - $curr) === 1){ - $curr = $end = $n; - $type = false; - $pointer = $i + 1; - }else{ - break; - } - } - ++$pointer; - if($type === false){ - $payload .= Utils::writeBool(false); - $payload .= strrev(Utils::writeTriad($start)); - $payload .= strrev(Utils::writeTriad($end)); - }else{ - $payload .= Utils::writeBool(true); - $payload .= strrev(Utils::writeTriad($start)); - } - ++$records; - } - $this->addRaw(Utils::writeShort($records) . $payload); - break; - case 0x05: - $this->addRaw($this->data[$field]); - break; - } - break; - case "customData": - $this->addRaw(chr($this->data[1])); - if($this->data[2]["id"] === false){ - $this->addRaw($this->data[2]["raw"]); - }else{ - switch($this->data[1]){ - case 0x40: - $reply = new CustomPacketHandler($this->data[2]["id"], "", $this->data[2], true); - $this->addRaw(Utils::writeShort((strlen($reply->raw) + 1) << 3)); - $this->addRaw(strrev(Utils::writeTriad($this->data[2]["count"]))); - $this->addRaw(chr($this->data[2]["id"])); - $this->addRaw($reply->raw); - break; - case 0x00: - $raw = new CustomPacketHandler($this->data[2]["id"], "", $this->data[2], true); - $raw = $raw->raw; - $this->addRaw(Utils::writeShort((strlen($raw) + 1) << 3)); - $this->addRaw(chr($this->data[2]["id"])); - $this->addRaw($raw); - break; - } - } - - break; - case "magic": - $this->addRaw(RAKNET_MAGIC); - break; - case "float": - $this->addRaw(Utils::writeFloat($this->data[$field])); - break; - case "triad": - $this->addRaw(Utils::writeTriad($this->data[$field])); - break; - case "itriad": - $this->addRaw(strrev(Utils::writeTriad($this->data[$field]))); - break; - case "int": - $this->addRaw(Utils::writeInt($this->data[$field])); - break; - case "double": - $this->addRaw(Utils::writeDouble($this->data[$field])); - break; - case "long": - $this->addRaw(Utils::writeLong($this->data[$field])); - break; - case "bool": - case "boolean": - $this->addRaw(Utils::writeBool($this->data[$field])); - break; - case "ubyte": - case "byte": - $this->addRaw(Utils::writeByte($this->data[$field])); - break; - case "short": - $this->addRaw(Utils::writeShort($this->data[$field])); - break; - case "string": - $this->addRaw(Utils::writeShort(strlen($this->data[$field]))); - $this->addRaw($this->data[$field]); - break; - default: - $this->addRaw(Utils::writeByte($this->data[$field])); - break; - } - } - } - - private function get($len = true){ - if($len === true){ - $data = substr($this->raw, $this->offset); - $this->offset = strlen($this->raw); - return $data; - } - $data = substr($this->raw, $this->offset, $len); - $this->offset += $len; - return $data; - } - - private function feof(){ - return !isset($this->raw{$this->offset}); - } - - protected function addRaw($str){ - $this->raw .= $str; - return $str; - } - - public function parse(){ - foreach($this->struct as $field => $type){ - switch($type){ - case "special1": - switch($this->pid){ - case 0x07: - $this->data[] = $this->get(5); - break; - case 0x99: - if($this->data[0] >= 2){ // - $messageID = Utils::readShort($this->get(2), false); - $messageIndex = Utils::readShort($this->get(2), false); - $this->data[1] = array("id" => $messageID, "index" => $messageIndex); - if($this->data[0] === 2){ - $this->data[1]["count"] = Utils::readShort($this->get(2), false); - $dataLength = Utils::readShort($this->get(2), false); - $this->data[1]["data"] = $this->get($dataLength); - } - } - break; - case 0xc0: - case 0xa0: - $cnt = Utils::readShort($this->get(2), false); - $this->data[$field] = array(); - for($i = 0; $i < $cnt and !$this->feof(); ++$i){ - if(Utils::readBool($this->get(1)) === false){ - $start = Utils::readTriad(strrev($this->get(3))); - $end = min(Utils::readTriad(strrev($this->get(3))), $start + 4096); - for($c = $start; $c <= $end; ++$c){ - $this->data[$field][] = $c; - } - }else{ - $this->data[$field][] = Utils::readTriad(strrev($this->get(3))); - } - } - break; - case 0x05: - $this->data[] = $this->get(true); - break; - } - break; - case "customData": - $raw = $this->get(true); - $len = strlen($raw); - $offset = 0; - $this->data["packets"] = array(); - while($len > $offset){ - $pid = ord($raw{$offset}); - ++$offset; - $reliability = ($pid & 0b11100000) >> 5; - $hasSplit = ($pid & 0b00010000) >> 4; - $length = Utils::readShort(substr($raw, $offset, 2), false); - $offset += 2; - if($reliability === 2 - or $reliability === 3 - or $reliability === 4 - or $reliability === 6 - or $reliability === 7){ - $messageIndex = Utils::readTriad(strrev(substr($raw, $offset, 3))); - $offset += 3; - }else{ - $messageIndex = 0; - } - - if($reliability === 1 - or $reliability === 3 - or $reliability === 4 - or $reliability === 7){ - $orderIndex = Utils::readTriad(strrev(substr($raw, $offset, 3))); - $offset += 3; - $orderChannel = ord($raw{$offset}); //5 bits, 32 values - ++$offset; - }else{ - $orderIndex = 0; - $orderChannel = 0; - } - - if($hasSplit === 1){ - $splitCount = Utils::readInt(substr($raw, $offset, 4)); - $offset += 4; - $splitID = Utils::readShort(substr($raw, $offset, 2)); - $offset += 2; - $splitIndex = Utils::readInt(substr($raw, $offset, 4)); - $offset += 4; - //error! no split packets allowed! - break; - }else{ - $splitCount = 0; - $splitID = 0; - $splitIndex = 0; - } - - if($length == 0 - or $orderChannel >= 32 - or ($hasSplit === 1 and $splitIndex >= $splitCount)){ - continue; - } - $ln = ceil($length / 8); - $id = ord($raw{$offset}); - ++$offset; - $pak = substr($raw, $offset, $ln - 1); - $offset += $ln - 1; - $pk = new CustomPacketHandler($id, $pak); - $pk->data["length"] = $ln; - $pk->data["id"] = $id; - $pk->data["counter"] = $messageIndex; - $pk->data["packetName"] = $pk->name; - $this->data["packets"][] = array($pid, $pk->data, $pak); - } - break; - case "magic": - $this->data[] = $this->get(16); - break; - case "triad": - $this->data[] = Utils::readTriad($this->get(3)); - break; - case "itriad": - $this->data[] = Utils::readTriad(strrev($this->get(3))); - break; - case "int": - $this->data[] = Utils::readInt($this->get(4)); - break; - case "string": - $this->data[] = $this->get(Utils::readShort($this->get(2))); - break; - case "long": - $this->data[] = Utils::readLong($this->get(8)); - break; - case "byte": - $this->data[] = Utils::readByte($this->get(1)); - break; - case "ubyte": - $this->data[] = ord($this->get(1)); - break; - case "float": - $this->data[] = Utils::readFloat($this->get(4)); - break; - case "double": - $this->data[] = Utils::readDouble($this->get(8)); - break; - case "ushort": - $this->data[] = Utils::readShort($this->get(2), false); - break; - case "short": - $this->data[] = Utils::readShort($this->get(2)); - break; - case "bool": - case "boolean": - $this->data[] = Utils::readBool($this->get(1)); - break; - } - } - } - - - +class Packet extends stdClass{ + public $ip; + public $port; + public $buffer; } \ No newline at end of file diff --git a/src/network/ProtocolInfo.php b/src/network/ProtocolInfo.php deleted file mode 100644 index b0b703b68..000000000 --- a/src/network/ProtocolInfo.php +++ /dev/null @@ -1,259 +0,0 @@ - array( - "long", //Ping ID - "magic", - ), - 0x02 => array( - "long", //Ping ID - "magic", - ), - - 0x05 => array( - "magic", - "byte", //Protocol Version - "special1", //MTU Size Null Lenght - ), - - 0x06 => array( - "magic", - "long", //Server GUID - "byte", //Server Security - "short", //MTU Size - ), - - 0x07 => array( - "magic", - "special1", //Security Cookie - "short", //Server UDP Port - "short", //MTU Size - "long", //Client GUID - ), - - 0x08 => array( - "magic", - "long", //Server GUID - "short", //Client UDP Port - "short", //MTU Size - "byte", //Security - ), - - 0x1a => array( - "byte", //Server Version - "magic", - "long", //Server GUID - ), - - 0x1c => array( - "long", //Ping ID - "long", //Server GUID - "magic", - "string", //Data - ), - - 0x1d => array( - "long", //Ping ID - "long", //Server GUID - "magic", - "string", //Data - ), - - 0x80 => array( - "itriad", - "customData", - ), - - - 0x81 => array( - "itriad", - "customData", - ), - - 0x82 => array( - "itriad", - "customData", - ), - - 0x83 => array( - "itriad", - "customData", - ), - - 0x84 => array( - "itriad", - "customData", - ), - - 0x85 => array( - "itriad", - "customData", - ), - - 0x86 => array( - "itriad", - "customData", - ), - - 0x87 => array( - "itriad", - "customData", - ), - - 0x88 => array( - "itriad", - "customData", - ), - - 0x89 => array( - "itriad", - "customData", - ), - - 0x8a => array( - "itriad", - "customData", - ), - - 0x8b => array( - "itriad", - "customData", - ), - - 0x8c => array( - "itriad", - "customData", - ), - - 0x8d => array( - "itriad", - "customData", - ), - - 0x8e => array( - "itriad", - "customData", - ), - - 0x8f => array( - "itriad", - "ubyte", - "customData", - ), - - 0x99 => array( - "byte", - "special1", - ), - - 0xa0 => array( - "special1", - ), - - 0xc0 => array( - "special1", - ), - - ); - -} \ No newline at end of file diff --git a/src/network/UDPSocket.php b/src/network/UDPSocket.php index 71b8b687b..ee9df38e0 100644 --- a/src/network/UDPSocket.php +++ b/src/network/UDPSocket.php @@ -34,8 +34,8 @@ class UDPSocket{ }else{ if(socket_bind($this->sock, $serverip, $port) === true){ socket_set_option($this->sock, SOL_SOCKET, SO_REUSEADDR, 0); - socket_set_option($this->sock, SOL_SOCKET, SO_SNDBUF, 65535); - socket_set_option($this->sock, SOL_SOCKET, SO_RCVBUF, 65535); + socket_set_option($this->sock, SOL_SOCKET, SO_SNDBUF, 1024 * 1024 * 2); //2MB + socket_set_option($this->sock, SOL_SOCKET, SO_RCVBUF, 1024 * 1024); //1MB $this->unblock(); $this->connected = true; }else{ @@ -64,11 +64,11 @@ class UDPSocket{ return @socket_recvfrom($this->sock, $buf, 65535, 0, $source, $port); } - public function write($data, $dest = false, $port = false){ + public function write($data, $dest, $port){ if($this->connected === false){ return false; } - return @socket_sendto($this->sock, $data, strlen($data), 0, ($dest === false ? $this->server:$dest), ($port === false ? $this->port:$port)); + return @socket_sendto($this->sock, $data, strlen($data), 0, $dest, $port); } } diff --git a/src/network/protocol/ProtocolInfo.php b/src/network/protocol/ProtocolInfo.php new file mode 100644 index 000000000..b321c4c2c --- /dev/null +++ b/src/network/protocol/ProtocolInfo.php @@ -0,0 +1,160 @@ + "UnknownPacket", + ProtocolInfo::PING_PACKET => "PingPacket", + ProtocolInfo::PONG_PACKET => "PongPacket", + ProtocolInfo::CLIENT_CONNECT_PACKET => "ClientConnectPacket", + ProtocolInfo::SERVER_HANDSHAKE_PACKET => "ServerHandshakePacket", + ProtocolInfo::DISCONNECT_PACKET => "DisconnectPacket", + ProtocolInfo::LOGIN_PACKET => "LoginPacket", + ProtocolInfo::LOGIN_STATUS_PACKET => "LoginStatusPacket", + ProtocolInfo::READY_PACKET => "ReadyPacket", + ProtocolInfo::MESSAGE_PACKET => "MessagePacket", + ProtocolInfo::SET_TIME_PACKET => "SetTimePacket", + ProtocolInfo::START_GAME_PACKET => "StartGamePacket", + ProtocolInfo::ADD_MOB_PACKET => "AddMobPacket", + ProtocolInfo::ADD_PLAYER_PACKET => "AddPlayerPacket", + ProtocolInfo::REMOVE_PLAYER_PACKET => "RemovePlayerPacket", + ProtocolInfo::ADD_ENTITY_PACKET => "AddEntityPacket", + ProtocolInfo::REMOVE_ENTITY_PACKET => "RemoveEntityPacket", + ProtocolInfo::ADD_ITEM_ENTITY_PACKET => "AddItemEntityPacket", + ProtocolInfo::TAKE_ITEM_ENTITY_PACKET => "TakeItemEntityPacket", + ProtocolInfo::MOVE_ENTITY_PACKET => "MoveEntityPacket", + ProtocolInfo::MOVE_ENTITY_PACKET_POSROT => "MoveEntityPacket_PosRot", + ProtocolInfo::ROTATE_HEAD_PACKET => "RotateHeadPacket", + ProtocolInfo::MOVE_PLAYER_PACKET => "MovePlayerPacket", + ProtocolInfo::REMOVE_BLOCK_PACKET => "RemoveBlockPacket", + ProtocolInfo::UPDATE_BLOCK_PACKET => "UpdateBlockPacket", + ProtocolInfo::ADD_PAINTING_PACKET => "AddPaintingPacket", + ProtocolInfo::EXPLODE_PACKET => "ExplodePacket", + ProtocolInfo::LEVEL_EVENT_PACKET => "LevelEventPacket", + ProtocolInfo::TILE_EVENT_PACKET => "TileEventPacket", + ProtocolInfo::ENTITY_EVENT_PACKET => "EntityEventPacket", + ProtocolInfo::REQUEST_CHUNK_PACKET => "RequestChunkPacket", + ProtocolInfo::CHUNK_DATA_PACKET => "ChunkDataPacket", + ProtocolInfo::PLAYER_EQUIPMENT_PACKET => "PlayerEquipmentPacket", + ProtocolInfo::PLAYER_ARMOR_EQUIPMENT_PACKET => "PlayerArmorEquipmentPacket", + ProtocolInfo::INTERACT_PACKET => "InteractPacket", + ProtocolInfo::USE_ITEM_PACKET => "UseItemPacket", + ProtocolInfo::PLAYER_ACTION_PACKET => "PlayerActionPacket", + ProtocolInfo::HURT_ARMOR_PACKET => "HurtArmorPacket", + ProtocolInfo::SET_ENTITY_DATA_PACKET => "SetEntityDataPacket", + ProtocolInfo::SET_ENTITY_MOTION_PACKET => "SetEntityMotionPacket", + ProtocolInfo::SET_HEALTH_PACKET => "SetHealthPacket", + ProtocolInfo::SET_SPAWN_POSITION_PACKET => "SetSpawnPositionPacket", + ProtocolInfo::ANIMATE_PACKET => "AnimatePacket", + ProtocolInfo::RESPAWN_PACKET => "RespawnPacket", + ProtocolInfo::SEND_INVENTORY_PACKET => "SendInventoryPacket", + ProtocolInfo::DROP_ITEM_PACKET => "DropItemPacket", + ProtocolInfo::CONTAINER_OPEN_PACKET => "ContainerOpenPacket", + ProtocolInfo::CONTAINER_CLOSE_PACKET => "ContainerClosePacket", + ProtocolInfo::CONTAINER_SET_SLOT_PACKET => "ContainerSetSlotPacket", + ProtocolInfo::CONTAINER_SET_DATA_PACKET => "ContainerSetDataPacket", + ProtocolInfo::CONTAINER_SET_CONTENT_PACKET => "ContainerSetContentPacket", + ProtocolInfo::CHAT_PACKET => "ChatPacket", + ProtocolInfo::ADVENTURE_SETTINGS_PACKET => "AdventureSettingsPacket", + ProtocolInfo::ENTITY_DATA_PACKET => "EntityDataPacket", + ); + +} + +/***REM_START***/ +require_once(FILE_PATH . "src/network/raknet/RakNetDataPacket.php"); +/***REM_END***/ \ No newline at end of file diff --git a/src/network/protocol/packet/AddEntityPacket.php b/src/network/protocol/packet/AddEntityPacket.php new file mode 100644 index 000000000..9635fb093 --- /dev/null +++ b/src/network/protocol/packet/AddEntityPacket.php @@ -0,0 +1,56 @@ +reset(); + $this->putInt($this->eid); + $this->putByte($this->type); + $this->putFloat($this->x); + $this->putFloat($this->y); + $this->putFloat($this->z); + $this->putInt($this->did); + if($this->did > 0){ + $this->putShort($this->speedX); + $this->putShort($this->speedY); + $this->putShort($this->speedZ); + } + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/AddItemEntityPacket.php b/src/network/protocol/packet/AddItemEntityPacket.php new file mode 100644 index 000000000..adc76c0a7 --- /dev/null +++ b/src/network/protocol/packet/AddItemEntityPacket.php @@ -0,0 +1,52 @@ +reset(); + $this->putInt($this->eid); + $this->putSlot($this->item); + $this->putFloat($this->x); + $this->putFloat($this->y); + $this->putFloat($this->z); + $this->putByte($this->yaw); + $this->putByte($this->pitch); + $this->putByte($this->roll); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/AddMobPacket.php b/src/network/protocol/packet/AddMobPacket.php new file mode 100644 index 000000000..3a7f41cbe --- /dev/null +++ b/src/network/protocol/packet/AddMobPacket.php @@ -0,0 +1,52 @@ +reset(); + $this->putInt($this->eid); + $this->putInt($this->type); + $this->putFloat($this->x); + $this->putFloat($this->y); + $this->putFloat($this->z); + $this->putByte($this->yaw); + $this->putByte($this->pitch); + $this->put(Utils::writeMetadata($this->metadata)); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/AddPaintingPacket.php b/src/network/protocol/packet/AddPaintingPacket.php new file mode 100644 index 000000000..6d0557ced --- /dev/null +++ b/src/network/protocol/packet/AddPaintingPacket.php @@ -0,0 +1,48 @@ +reset(); + $this->putInt($this->eid); + $this->putInt($this->x); + $this->putInt($this->y); + $this->putInt($this->z); + $this->putInt($this->direction); + $this->putString($this->title); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/AddPlayerPacket.php b/src/network/protocol/packet/AddPlayerPacket.php new file mode 100644 index 000000000..426ef480e --- /dev/null +++ b/src/network/protocol/packet/AddPlayerPacket.php @@ -0,0 +1,58 @@ +reset(); + $this->putLong($this->clientID); + $this->putString($this->username); + $this->putInt($this->eid); + $this->putFloat($this->x); + $this->putFloat($this->y); + $this->putFloat($this->z); + $this->putByte($this->yaw); + $this->putByte($this->pitch); + $this->putShort($this->unknown1); + $this->putShort($this->unknown2); + $this->put(Utils::writeMetadata($this->metadata)); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/AdventureSettingsPacket.php b/src/network/protocol/packet/AdventureSettingsPacket.php new file mode 100644 index 000000000..930941012 --- /dev/null +++ b/src/network/protocol/packet/AdventureSettingsPacket.php @@ -0,0 +1,38 @@ +reset(); + $this->putInt($this->flags); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/AnimatePacket.php b/src/network/protocol/packet/AnimatePacket.php new file mode 100644 index 000000000..d8266f6a9 --- /dev/null +++ b/src/network/protocol/packet/AnimatePacket.php @@ -0,0 +1,41 @@ +action = $this->getByte(); + $this->eid = $this->getInt(); + } + + public function encode(){ + $this->reset(); + $this->putByte($this->action); + $this->putInt($this->eid); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/ChatPacket.php b/src/network/protocol/packet/ChatPacket.php new file mode 100644 index 000000000..8c142976f --- /dev/null +++ b/src/network/protocol/packet/ChatPacket.php @@ -0,0 +1,38 @@ +reset(); + $this->putString($this->message); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/ChunkDataPacket.php b/src/network/protocol/packet/ChunkDataPacket.php new file mode 100644 index 000000000..05ccb67f1 --- /dev/null +++ b/src/network/protocol/packet/ChunkDataPacket.php @@ -0,0 +1,42 @@ +reset(); + $this->putInt($this->chunkX); + $this->putInt($this->chunkZ); + $this->put($this->data); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/ClientConnectPacket.php b/src/network/protocol/packet/ClientConnectPacket.php new file mode 100644 index 000000000..d5187caad --- /dev/null +++ b/src/network/protocol/packet/ClientConnectPacket.php @@ -0,0 +1,41 @@ +clientID = $this->getLong(); + $this->session = $this->getLong(); + $this->unknown1 = $this->get(1); + } + + public function encode(){ + + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/ClientHandshakePacket.php b/src/network/protocol/packet/ClientHandshakePacket.php new file mode 100644 index 000000000..b718ebfc8 --- /dev/null +++ b/src/network/protocol/packet/ClientHandshakePacket.php @@ -0,0 +1,51 @@ +cookie = $this->get(4); + $this->security = $this->get(1); + $this->port = $this->getShort(true); + $this->dataArray0 = $this->get($this->getByte()); + $this->dataArray = $this->getDataArray(9); + $this->timestamp = $this->get(2); + $this->session2 = $this->getLong(); + $this->session = $this->getLong(); + } + + public function encode(){ + + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/ContainerClosePacket.php b/src/network/protocol/packet/ContainerClosePacket.php new file mode 100644 index 000000000..1b962e4f9 --- /dev/null +++ b/src/network/protocol/packet/ContainerClosePacket.php @@ -0,0 +1,38 @@ +windowid = $this->getByte(); + } + + public function encode(){ + $this->reset(); + $this->putByte($this->windowid); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/ContainerOpenPacket.php b/src/network/protocol/packet/ContainerOpenPacket.php new file mode 100644 index 000000000..a1e9f55a6 --- /dev/null +++ b/src/network/protocol/packet/ContainerOpenPacket.php @@ -0,0 +1,48 @@ +reset(); + $this->putByte($this->windowid); + $this->putByte($this->type); + $this->putByte($this->slots); + $this->putInt($this->x); + $this->putInt($this->y); + $this->putInt($this->z); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/ContainerSetContentPacket.php b/src/network/protocol/packet/ContainerSetContentPacket.php new file mode 100644 index 000000000..e648c94da --- /dev/null +++ b/src/network/protocol/packet/ContainerSetContentPacket.php @@ -0,0 +1,60 @@ +windowid = $this->getByte(); + $count = $this->getShort(); + for($s = 0; $s < $count and !$this->feof(); ++$s){ + $this->slots[$s] = $this->getSlot(); + } + if($this->windowid === 0){ + $count = $this->getShort(); + for($s = 0; $s < $count and !$this->feof(); ++$s){ + $this->hotbar[$s] = $this->getInt(); + } + } + } + + public function encode(){ + $this->reset(); + $this->putByte($this->windowid); + $this->putShort(count($this->slots)); + foreach($this->slots as $slot){ + $this->putSlot($slot); + } + if($this->windowid === 0 and count($this->hotbar) > 0){ + $this->putShort(count($this->hotbar)); + foreach($this->hotbar as $slot){ + $this->putInt($slot); + } + } + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/ContainerSetDataPacket.php b/src/network/protocol/packet/ContainerSetDataPacket.php new file mode 100644 index 000000000..e18b6cb77 --- /dev/null +++ b/src/network/protocol/packet/ContainerSetDataPacket.php @@ -0,0 +1,42 @@ +reset(); + $this->putByte($this->windowid); + $this->putShort($this->property); + $this->putShort($this->value); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/ContainerSetSlotPacket.php b/src/network/protocol/packet/ContainerSetSlotPacket.php new file mode 100644 index 000000000..6f1a2079d --- /dev/null +++ b/src/network/protocol/packet/ContainerSetSlotPacket.php @@ -0,0 +1,44 @@ +windowid = $this->getByte(); + $this->slot = $this->getShort(); + $this->item = $this->getSlot(); + } + + public function encode(){ + $this->reset(); + $this->putByte($this->windowid); + $this->putShort($this->slot); + $this->putSlot($this->item); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/DisconnectPacket.php b/src/network/protocol/packet/DisconnectPacket.php new file mode 100644 index 000000000..42bfaba88 --- /dev/null +++ b/src/network/protocol/packet/DisconnectPacket.php @@ -0,0 +1,35 @@ +reset(); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/DropItemPacket.php b/src/network/protocol/packet/DropItemPacket.php new file mode 100644 index 000000000..e6851d763 --- /dev/null +++ b/src/network/protocol/packet/DropItemPacket.php @@ -0,0 +1,41 @@ +eid = $this->getInt(); + $this->unknown = $this->getByte(); + $this->item = $this->getSlot(); + } + + public function encode(){ + + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/EntityDataPacket.php b/src/network/protocol/packet/EntityDataPacket.php new file mode 100644 index 000000000..16a59db1e --- /dev/null +++ b/src/network/protocol/packet/EntityDataPacket.php @@ -0,0 +1,47 @@ +x = $this->getShort(); + $this->y = $this->getByte(); + $this->z = $this->getShort(); + $this->namedtag = $this->get(true); + } + + public function encode(){ + $this->reset(); + $this->putShort($this->x); + $this->putByte($this->y); + $this->putShort($this->z); + $this->put($this->namedtag); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/EntityEventPacket.php b/src/network/protocol/packet/EntityEventPacket.php new file mode 100644 index 000000000..8764de026 --- /dev/null +++ b/src/network/protocol/packet/EntityEventPacket.php @@ -0,0 +1,41 @@ +eid = $this->getInt(); + $this->event = $this->getByte(); + } + + public function encode(){ + $this->reset(); + $this->putInt($this->eid); + $this->putByte($this->event); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/ExplodePacket.php b/src/network/protocol/packet/ExplodePacket.php new file mode 100644 index 000000000..d3c1ef1c1 --- /dev/null +++ b/src/network/protocol/packet/ExplodePacket.php @@ -0,0 +1,53 @@ +reset(); + $this->putFloat($this->x); + $this->putFloat($this->y); + $this->putFloat($this->z); + $this->putFloat($this->radius); + $this->putInt(@count($this->records)); + if(@count($this->records) > 0){ + foreach($this->records as $record){ + $this->putByte($record->x); + $this->putByte($record->y); + $this->putByte($record->z); + } + } + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/HurtArmorPacket.php b/src/network/protocol/packet/HurtArmorPacket.php new file mode 100644 index 000000000..48a148693 --- /dev/null +++ b/src/network/protocol/packet/HurtArmorPacket.php @@ -0,0 +1,38 @@ +reset(); + $this->putByte($this->health); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/InteractPacket.php b/src/network/protocol/packet/InteractPacket.php new file mode 100644 index 000000000..f1ebd8c43 --- /dev/null +++ b/src/network/protocol/packet/InteractPacket.php @@ -0,0 +1,44 @@ +action = $this->getByte(); + $this->eid = $this->getInt(); + $this->target = $this->getInt(); + } + + public function encode(){ + $this->reset(); + $this->putByte($this->action); + $this->putInt($this->eid); + $this->putInt($this->target); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/LevelEventPacket.php b/src/network/protocol/packet/LevelEventPacket.php new file mode 100644 index 000000000..22a44ab58 --- /dev/null +++ b/src/network/protocol/packet/LevelEventPacket.php @@ -0,0 +1,46 @@ +reset(); + $this->putShort($this->evid); + $this->putShort($this->x); + $this->putShort($this->y); + $this->putShort($this->z); + $this->putInt($this->data); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/LoginPacket.php b/src/network/protocol/packet/LoginPacket.php new file mode 100644 index 000000000..a357a27e6 --- /dev/null +++ b/src/network/protocol/packet/LoginPacket.php @@ -0,0 +1,45 @@ +username = $this->getString(); + $this->protocol1 = $this->getInt(); + $this->protocol2 = $this->getInt(); + $this->clientId = $this->getInt(); + $this->loginData = $this->getString(); + } + + public function encode(){ + + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/LoginStatusPacket.php b/src/network/protocol/packet/LoginStatusPacket.php new file mode 100644 index 000000000..fce48a7ed --- /dev/null +++ b/src/network/protocol/packet/LoginStatusPacket.php @@ -0,0 +1,38 @@ +reset(); + $this->putInt($this->status); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/MessagePacket.php b/src/network/protocol/packet/MessagePacket.php new file mode 100644 index 000000000..113775104 --- /dev/null +++ b/src/network/protocol/packet/MessagePacket.php @@ -0,0 +1,41 @@ +source = $this->getString(); + $this->message = $this->getString(); + } + + public function encode(){ + $this->reset(); + $this->putString($this->source); + $this->putString($this->message); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/MoveEntityPacket.php b/src/network/protocol/packet/MoveEntityPacket.php new file mode 100644 index 000000000..ba0a672dd --- /dev/null +++ b/src/network/protocol/packet/MoveEntityPacket.php @@ -0,0 +1,36 @@ +reset(); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/MoveEntityPacket_PosRot.php b/src/network/protocol/packet/MoveEntityPacket_PosRot.php new file mode 100644 index 000000000..fbb046d1a --- /dev/null +++ b/src/network/protocol/packet/MoveEntityPacket_PosRot.php @@ -0,0 +1,48 @@ +reset(); + $this->putInt($this->eid); + $this->putFloat($this->x); + $this->putFloat($this->y); + $this->putFloat($this->z); + $this->putFloat($this->yaw); + $this->putFloat($this->pitch); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/MovePlayerPacket.php b/src/network/protocol/packet/MovePlayerPacket.php new file mode 100644 index 000000000..3730f69ee --- /dev/null +++ b/src/network/protocol/packet/MovePlayerPacket.php @@ -0,0 +1,56 @@ +eid = $this->getInt(); + $this->x = $this->getFloat(); + $this->y = $this->getFloat(); + $this->z = $this->getFloat(); + $this->yaw = $this->getFloat(); + $this->pitch = $this->getFloat(); + $this->bodyYaw = $this->getFloat(); + } + + public function encode(){ + $this->reset(); + $this->putInt($this->eid); + $this->putFloat($this->x); + $this->putFloat($this->y); + $this->putFloat($this->z); + $this->putFloat($this->yaw); + $this->putFloat($this->pitch); + $this->putFloat($this->bodyYaw); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/PingPacket.php b/src/network/protocol/packet/PingPacket.php new file mode 100644 index 000000000..85e01b663 --- /dev/null +++ b/src/network/protocol/packet/PingPacket.php @@ -0,0 +1,38 @@ +time = $this->getLong(); + } + + public function encode(){ + $this->reset(); + $this->putLong($this->time); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/PlayerActionPacket.php b/src/network/protocol/packet/PlayerActionPacket.php new file mode 100644 index 000000000..89701b085 --- /dev/null +++ b/src/network/protocol/packet/PlayerActionPacket.php @@ -0,0 +1,47 @@ +action = $this->getInt(); + $this->x = $this->getInt(); + $this->y = $this->getInt(); + $this->z = $this->getInt(); + $this->face = $this->getInt(); + $this->eid = $this->getInt(); + } + + public function encode(){ + + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/PlayerArmorEquipmentPacket.php b/src/network/protocol/packet/PlayerArmorEquipmentPacket.php new file mode 100644 index 000000000..b20345420 --- /dev/null +++ b/src/network/protocol/packet/PlayerArmorEquipmentPacket.php @@ -0,0 +1,47 @@ +eid = $this->getInt(); + $this->slots[0] = $this->getByte(); + $this->slots[1] = $this->getByte(); + $this->slots[2] = $this->getByte(); + $this->slots[3] = $this->getByte(); + } + + public function encode(){ + $this->reset(); + $this->putInt($this->eid); + $this->putByte($this->slots[0]); + $this->putByte($this->slots[1]); + $this->putByte($this->slots[2]); + $this->putByte($this->slots[3]); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/PlayerEquipmentPacket.php b/src/network/protocol/packet/PlayerEquipmentPacket.php new file mode 100644 index 000000000..f323d74dc --- /dev/null +++ b/src/network/protocol/packet/PlayerEquipmentPacket.php @@ -0,0 +1,47 @@ +eid = $this->getInt(); + $this->item = $this->getShort(); + $this->meta = $this->getShort(); + $this->slot = $this->getByte(); + } + + public function encode(){ + $this->reset(); + $this->putInt($this->eid); + $this->putShort($this->item); + $this->putShort($this->meta); + $this->putByte($this->slot); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/PongPacket.php b/src/network/protocol/packet/PongPacket.php new file mode 100644 index 000000000..453b6514d --- /dev/null +++ b/src/network/protocol/packet/PongPacket.php @@ -0,0 +1,41 @@ +ptime = $this->getLong(); + $this->time = $this->getLong(); + } + + public function encode(){ + $this->reset(); + $this->putLong($this->ptime); + $this->putLong($this->time); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/ReadyPacket.php b/src/network/protocol/packet/ReadyPacket.php new file mode 100644 index 000000000..c77fc391b --- /dev/null +++ b/src/network/protocol/packet/ReadyPacket.php @@ -0,0 +1,37 @@ +status = $this->getByte(); + } + + public function encode(){ + + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/RemoveBlockPacket.php b/src/network/protocol/packet/RemoveBlockPacket.php new file mode 100644 index 000000000..2063852d3 --- /dev/null +++ b/src/network/protocol/packet/RemoveBlockPacket.php @@ -0,0 +1,43 @@ +eid = $this->getInt(); + $this->x = $this->getInt(); + $this->z = $this->getInt(); + $this->y = $this->getByte(); + } + + public function encode(){ + + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/RemoveEntityPacket.php b/src/network/protocol/packet/RemoveEntityPacket.php new file mode 100644 index 000000000..70e7f912c --- /dev/null +++ b/src/network/protocol/packet/RemoveEntityPacket.php @@ -0,0 +1,38 @@ +reset(); + $this->putInt($this->eid); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/RemovePlayerPacket.php b/src/network/protocol/packet/RemovePlayerPacket.php new file mode 100644 index 000000000..d0727bb20 --- /dev/null +++ b/src/network/protocol/packet/RemovePlayerPacket.php @@ -0,0 +1,40 @@ +reset(); + $this->putInt($this->eid); + $this->putLong($this->clientID); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/RequestChunkPacket.php b/src/network/protocol/packet/RequestChunkPacket.php new file mode 100644 index 000000000..f3f3b604c --- /dev/null +++ b/src/network/protocol/packet/RequestChunkPacket.php @@ -0,0 +1,39 @@ +chunkX = $this->getInt(); + $this->chunkZ = $this->getInt(); + } + + public function encode(){ + + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/RespawnPacket.php b/src/network/protocol/packet/RespawnPacket.php new file mode 100644 index 000000000..f9475efb7 --- /dev/null +++ b/src/network/protocol/packet/RespawnPacket.php @@ -0,0 +1,47 @@ +eid = $this->getInt(); + $this->x = $this->getFloat(); + $this->y = $this->getFloat(); + $this->z = $this->getFloat(); + } + + public function encode(){ + $this->reset(); + $this->putInt($this->eid); + $this->putFloat($this->x); + $this->putFloat($this->y); + $this->putFloat($this->z); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/RotateHeadPacket.php b/src/network/protocol/packet/RotateHeadPacket.php new file mode 100644 index 000000000..41ba3d123 --- /dev/null +++ b/src/network/protocol/packet/RotateHeadPacket.php @@ -0,0 +1,40 @@ +reset(); + $this->putInt($this->eid); + $this->putByte($this->yaw); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/SendInventoryPacket.php b/src/network/protocol/packet/SendInventoryPacket.php new file mode 100644 index 000000000..250d3abce --- /dev/null +++ b/src/network/protocol/packet/SendInventoryPacket.php @@ -0,0 +1,61 @@ +eid = $this->getInt(); + $this->windowid = $this->getByte(); + $count = $this->getShort(); + for($s = 0; $s < $count and !$this->feof(); ++$s){ + $this->slots[$s] = $this->getSlot(); + } + if($this->windowid === 1){ //Armir is sent + for($s = 0; $s < 4; ++$s){ + $this->armor[$s] = $this->getSlot(); + } + } + } + + public function encode(){ + $this->reset(); + $this->putInt($this->eid); + $this->putByte($this->windowid); + $this->putShort(count($this->slots)); + foreach($this->slots as $slot){ + $this->putSlot($slot); + } + if($this->windowid === 1 and count($this->armor) === 4){ + for($s = 0; $s < 4; ++$s){ + $this->putSlot($this->armor[$s]); + } + } + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/ServerHandshakePacket.php b/src/network/protocol/packet/ServerHandshakePacket.php new file mode 100644 index 000000000..3077acf91 --- /dev/null +++ b/src/network/protocol/packet/ServerHandshakePacket.php @@ -0,0 +1,57 @@ +reset(); + $this->put("\x04\x3f\x57\xfe"); //cookie + $this->put("\xcd"); //Security flags + $this->putShort($this->port); + $this->putDataArray(array( + "\xf5\xff\xff\xf5", + "\xff\xff\xff\xff", + "\xff\xff\xff\xff", + "\xff\xff\xff\xff", + "\xff\xff\xff\xff", + "\xff\xff\xff\xff", + "\xff\xff\xff\xff", + "\xff\xff\xff\xff", + "\xff\xff\xff\xff", + "\xff\xff\xff\xff", + )); + $this->put("\x00\x00"); + $this->putLong($this->session); + $this->putLong($this->session2); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/SetEntityDataPacket.php b/src/network/protocol/packet/SetEntityDataPacket.php new file mode 100644 index 000000000..be9ed385e --- /dev/null +++ b/src/network/protocol/packet/SetEntityDataPacket.php @@ -0,0 +1,40 @@ +reset(); + $this->putInt($this->eid); + $this->put(Utils::writeMetadata($this->metadata)); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/SetEntityMotionPacket.php b/src/network/protocol/packet/SetEntityMotionPacket.php new file mode 100644 index 000000000..70c492322 --- /dev/null +++ b/src/network/protocol/packet/SetEntityMotionPacket.php @@ -0,0 +1,44 @@ +reset(); + $this->putInt($this->eid); + $this->putShort((int) ($this->speedX * 400)); + $this->putShort((int) ($this->speedY * 400)); + $this->putShort((int) ($this->speedZ * 400)); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/SetHealthPacket.php b/src/network/protocol/packet/SetHealthPacket.php new file mode 100644 index 000000000..66e8f7b54 --- /dev/null +++ b/src/network/protocol/packet/SetHealthPacket.php @@ -0,0 +1,38 @@ +health = $this->getByte(); + } + + public function encode(){ + $this->reset(); + $this->putByte($this->health); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/SetSpawnPositionPacket.php b/src/network/protocol/packet/SetSpawnPositionPacket.php new file mode 100644 index 000000000..baed71d8f --- /dev/null +++ b/src/network/protocol/packet/SetSpawnPositionPacket.php @@ -0,0 +1,42 @@ +reset(); + $this->putInt($this->x); + $this->putInt($this->z); + $this->putByte($this->y); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/SetTimePacket.php b/src/network/protocol/packet/SetTimePacket.php new file mode 100644 index 000000000..09df60f9d --- /dev/null +++ b/src/network/protocol/packet/SetTimePacket.php @@ -0,0 +1,40 @@ +reset(); + $this->putInt($this->time); + $this->putByte($this->started == true ? 0x80:0x00); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/StartGamePacket.php b/src/network/protocol/packet/StartGamePacket.php new file mode 100644 index 000000000..fe3ead723 --- /dev/null +++ b/src/network/protocol/packet/StartGamePacket.php @@ -0,0 +1,50 @@ +reset(); + $this->putInt($this->seed); + $this->putInt($this->generator); + $this->putInt($this->gamemode); + $this->putInt($this->eid); + $this->putFloat($this->x); + $this->putFloat($this->y); + $this->putFloat($this->z); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/TakeItemEntity.php b/src/network/protocol/packet/TakeItemEntity.php new file mode 100644 index 000000000..0d6f97cd7 --- /dev/null +++ b/src/network/protocol/packet/TakeItemEntity.php @@ -0,0 +1,40 @@ +reset(); + $this->putInt($this->target); + $this->putInt($this->eid); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/TileEventPacket.php b/src/network/protocol/packet/TileEventPacket.php new file mode 100644 index 000000000..16ef18ccf --- /dev/null +++ b/src/network/protocol/packet/TileEventPacket.php @@ -0,0 +1,46 @@ +reset(); + $this->putInt($this->x); + $this->putInt($this->y); + $this->putInt($this->z); + $this->putInt($this->case1); + $this->putInt($this->case2); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/UnknownPacket.php b/src/network/protocol/packet/UnknownPacket.php new file mode 100644 index 000000000..38cc28143 --- /dev/null +++ b/src/network/protocol/packet/UnknownPacket.php @@ -0,0 +1,37 @@ +packetID; + } + + public function decode(){ + + } + + public function encode(){ + + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/UpdateBlockPacket.php b/src/network/protocol/packet/UpdateBlockPacket.php new file mode 100644 index 000000000..9fea1461e --- /dev/null +++ b/src/network/protocol/packet/UpdateBlockPacket.php @@ -0,0 +1,46 @@ +reset(); + $this->putInt($this->x); + $this->putInt($this->z); + $this->putByte($this->y); + $this->putByte($this->block); + $this->putByte($this->meta); + } + +} \ No newline at end of file diff --git a/src/network/protocol/packet/UseItemPacket.php b/src/network/protocol/packet/UseItemPacket.php new file mode 100644 index 000000000..be2e988e9 --- /dev/null +++ b/src/network/protocol/packet/UseItemPacket.php @@ -0,0 +1,61 @@ +x = $this->getInt(); + $this->y = $this->getInt(); + $this->z = $this->getInt(); + $this->face = $this->getInt(); + $this->item = $this->getShort(); + $this->meta = $this->getByte(); //Mojang: fix this + $this->eid = $this->getInt(); + $this->fx = $this->getFloat(); + $this->fy = $this->getFloat(); + $this->fz = $this->getFloat(); + $this->posX = $this->getFloat(); + $this->posY = $this->getFloat(); + $this->posZ = $this->getFloat(); + } + + public function encode(){ + + } + +} \ No newline at end of file diff --git a/src/network/Query.php b/src/network/query/QueryHandler.php similarity index 72% rename from src/network/Query.php rename to src/network/query/QueryHandler.php index 3ec2e522c..f300695bb 100644 --- a/src/network/Query.php +++ b/src/network/query/QueryHandler.php @@ -24,7 +24,7 @@ Implementation of the UT3 Query Protocol (GameSpot) Source: http://wiki.unrealadmin.org/UT3_query_protocol */ -class Query{ +class QueryHandler{ private $socket, $server, $lastToken, $token, $longData, $timeout; public function __construct(){ @@ -41,7 +41,7 @@ class Query{ Then, the Query class handles itself sending the packets in raw form, because packets can conflict with the MCPE ones. */ - $this->server->addHandler("server.unknownpacket", array($this, "packetHandler"), 50); + $this->server->schedule(20 * 30, array($this, "regenerateToken"), array(), true); $this->regenerateToken(); $this->lastToken = $this->token; @@ -94,40 +94,41 @@ class Query{ $this->token = Utils::readInt("\x00".Utils::getRandomBytes(3, false)); } - public function packetHandler(&$packet, $event){ - if($event !== "server.unknownpacket"){ - return; - } - $magic = substr($packet["raw"], 0, 2); - $offset = 2; - if($magic !== "\xfe\xfd"){ - return; - } - $type = ord($packet["raw"]{2}); - ++$offset; - $sessionID = Utils::readInt(substr($packet["raw"], $offset, 4)); - $offset += 4; - $payload = substr($packet["raw"], $offset); - switch($type){ - case 9: //Handshake - $this->server->send(9, chr(9).Utils::writeInt($sessionID).$this->token."\x00", true, $packet["ip"], $packet["port"]); + public function handle(QueryPacket $packet){ + $packet->decode(); + switch($packet->packetType){ + case QueryPacket::HANDSHAKE: //Handshake + $pk = new QueryPacket; + $pk->ip = $packet->ip; + $pk->port = $packet->port; + $pk->packetType = QueryPacket::HANDSHAKE; + $pk->sessionID = $packet->sessionID; + $pk->payload = $this->token."\x00"; + $pk->encode(); + $this->server->send($pk); break; - case 0: //Stat - $token = Utils::readInt(substr($payload, 0, 4)); + case QueryPacket::STATISTICS: //Stat + $token = Utils::readInt(substr($packet->payload, 0, 4)); if($token !== $this->token and $token !== $this->lastToken){ break; } - if(strlen($payload) === 8){ + $pk = new QueryPacket; + $pk->ip = $packet->ip; + $pk->port = $packet->port; + $pk->packetType = QueryPacket::STATISTICS; + $pk->sessionID = $packet->sessionID; + if(strlen($packet->payload) === 8){ if($this->timeout < microtime(true)){ $this->regenerateInfo(); } - $this->server->send(0, chr(0).Utils::writeInt($sessionID).$this->longData, true, $packet["ip"], $packet["port"]); + $pk->payload = $this->longData; }else{ - $this->server->send(0, chr(0).Utils::writeInt($sessionID).$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", true, $packet["ip"], $packet["port"]); + $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->encode(); + $this->server->send($pk); break; } - return true; } -} +} \ No newline at end of file diff --git a/src/network/query/QueryPacket.php b/src/network/query/QueryPacket.php new file mode 100644 index 000000000..d0f0f148c --- /dev/null +++ b/src/network/query/QueryPacket.php @@ -0,0 +1,41 @@ +packetType = ord($this->buffer{2}); + $this->sessionID = Utils::readInt(substr($this->buffer, 3, 4)); + $this->payload = substr($this->buffer, 7); + } + + public function encode(){ + $this->buffer .= chr($this->packetType); + $this->buffer .= Utils::writeInt($this->sessionID); + $this->buffer .= $this->payload; + } +} \ No newline at end of file diff --git a/src/network/raknet/RakNetCodec.php b/src/network/raknet/RakNetCodec.php new file mode 100644 index 000000000..a009f63d2 --- /dev/null +++ b/src/network/raknet/RakNetCodec.php @@ -0,0 +1,184 @@ +packet = $packet; + $this->buffer =& $this->packet->buffer; + $this->encode(); + } + + private function encode(){ + if(strlen($this->packet->buffer) > 0){ + return; + } + $this->buffer .= chr($this->packet->pid()); + + switch($this->packet->pid()){ + case RakNetInfo::OPEN_CONNECTION_REPLY_1: + $this->buffer .= RakNetInfo::MAGIC; + $this->putLong($this->packet->serverID); + $this->putByte(0); //server security + $this->putShort($this->packet->mtuSize); + break; + case RakNetInfo::OPEN_CONNECTION_REPLY_2: + $this->buffer .= RakNetInfo::MAGIC; + $this->putLong($this->packet->serverID); + $this->putShort($this->packet->port); + $this->putShort($this->packet->mtuSize); + $this->putByte(0); //Server security + break; + case RakNetInfo::INCOMPATIBLE_PROTOCOL_VERSION: + $this->putByte(RakNetInfo::STRUCTURE); + $this->buffer .= RakNetInfo::MAGIC; + $this->putLong($this->packet->serverID); + break; + case RakNetInfo::UNCONNECTED_PONG: + case RakNetInfo::ADVERTISE_SYSTEM: + $this->putLong($this->packet->pingID); + $this->putLong($this->packet->serverID); + $this->buffer .= RakNetInfo::MAGIC; + $this->putString($this->packet->serverType); + break; + case RakNetInfo::DATA_PACKET_0: + case RakNetInfo::DATA_PACKET_1: + case RakNetInfo::DATA_PACKET_2: + case RakNetInfo::DATA_PACKET_3: + case RakNetInfo::DATA_PACKET_4: + case RakNetInfo::DATA_PACKET_5: + case RakNetInfo::DATA_PACKET_6: + case RakNetInfo::DATA_PACKET_7: + case RakNetInfo::DATA_PACKET_8: + case RakNetInfo::DATA_PACKET_9: + case RakNetInfo::DATA_PACKET_A: + case RakNetInfo::DATA_PACKET_B: + case RakNetInfo::DATA_PACKET_C: + case RakNetInfo::DATA_PACKET_D: + case RakNetInfo::DATA_PACKET_E: + case RakNetInfo::DATA_PACKET_F: + $this->putLTriad($this->packet->seqNumber); + foreach($this->packet->data as $pk){ + $this->encodeDataPacket($pk); + } + break; + case RakNetInfo::NACK: + case RakNetInfo::ACK: + $payload = b""; + $records = 0; + $pointer = 0; + sort($this->packet->packets, SORT_NUMERIC); + $max = count($this->packet->packets); + + while($pointer < $max){ + $type = true; + $curr = $start = $this->packet->packets[$pointer]; + for($i = $start + 1; $i < $max; ++$i){ + $n = $this->packet->packets[$i]; + if(($n - $curr) === 1){ + $curr = $end = $n; + $type = false; + $pointer = $i + 1; + }else{ + break; + } + } + ++$pointer; + if($type === false){ + $payload .= "\x00"; + $payload .= strrev(Utils::writeTriad($start)); + $payload .= strrev(Utils::writeTriad($end)); + }else{ + $payload .= Utils::writeBool(true); + $payload .= strrev(Utils::writeTriad($start)); + } + ++$records; + } + $this->putShort($records); + $this->buffer .= $payload; + break; + default: + + } + + } + + private function encodeDataPacket(RakNetDataPacket $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 .= Utils::writeLong($v); + } + + protected function putInt($v){ + $this->buffer .= Utils::writeInt($v); + } + + protected function putShort($v){ + $this->buffer .= Utils::writeShort($v); + } + + protected function putTriad($v){ + $this->buffer .= Utils::writeTriad($v); + } + + protected function putLTriad($v){ + $this->buffer .= strrev(Utils::writeTriad($v)); + } + + protected function putByte($v){ + $this->buffer .= chr($v); + } + + protected function putString($v){ + $this->putShort(strlen($v)); + $this->put($v); + } +} \ No newline at end of file diff --git a/src/network/raknet/RakNetDataPacket.php b/src/network/raknet/RakNetDataPacket.php new file mode 100644 index 000000000..75ebc44b7 --- /dev/null +++ b/src/network/raknet/RakNetDataPacket.php @@ -0,0 +1,171 @@ +setBuffer(chr($this->pid())); + } + + public function setBuffer($buffer = ""){ + $this->buffer = $buffer; + $this->offset = 0; + } + + public function getBuffer(){ + return $this->buffer; + } + + protected function get($len){ + if($len <= 0){ + $this->offset = strlen($this->buffer) - 1; + return ""; + } + if($len === true){ + return substr($this->buffer, $this->offset); + } + $this->offset += $len; + return substr($this->buffer, $this->offset - $len, $len); + } + + protected function put($str){ + $this->buffer .= $str; + } + + protected function getLong($unsigned = false){ + return Utils::readLong($this->get(8), $unsigned); + } + + protected function putLong($v){ + $this->buffer .= Utils::writeLong($v); + } + + protected function getInt($unsigned = false){ + return Utils::readInt($this->get(4), $unsigned); + } + + protected function putInt($v){ + $this->buffer .= Utils::writeInt($v); + } + + protected function getShort($unsigned = false){ + return Utils::readShort($this->get(2), $unsigned); + } + + protected function putShort($v){ + $this->buffer .= Utils::writeShort($v); + } + + protected function getFloat(){ + return Utils::readFloat($this->get(4)); + } + + protected function putFloat($v){ + $this->buffer .= Utils::writeFloat($v); + } + + protected function getTriad(){ + return Utils::readTriad($this->get(3)); + } + + protected function putTriad($v){ + $this->buffer .= Utils::writeTriad($v); + } + + + protected function getLTriad(){ + return Utils::readTriad(strrev($this->get(3))); + } + + protected function putLTriad($v){ + $this->buffer .= strrev(Utils::writeTriad($v)); + } + + protected function getByte(){ + return ord($this->get(1)); + } + + protected function putByte($v){ + $this->buffer .= chr($v); + } + + protected function getDataArray($len = 10){ + $data = array(); + for($i = 1; $i <= $len and !$this->feof(); ++$i){ + $data[] = $this->get($this->getTriad()); + } + return $data; + } + + protected function putDataArray(array $data = array()){ + foreach($data as $v){ + $this->putTriad(strlen($v)); + $this->put($v); + } + } + + protected function getSlot(){ + $id = $this->getShort(); + $cnt = $this->getByte(); + return BlockAPI::getItem( + $id, + $this->getShort(), + $cnt + ); + } + + protected function putSlot(Item $item){ + $this->putShort($item->getID()); + $this->putByte($item->count); + $this->putShort($item->getMetadata()); + } + + protected function getString(){ + return $this->get($this->getShort(true)); + } + + protected function putString($v){ + $this->putShort(strlen($v)); + $this->put($v); + } + + protected function feof(){ + return !isset($this->buffer{$this->offset}); + } +} \ No newline at end of file diff --git a/src/network/raknet/RakNetInfo.php b/src/network/raknet/RakNetInfo.php new file mode 100644 index 000000000..485f53973 --- /dev/null +++ b/src/network/raknet/RakNetInfo.php @@ -0,0 +1,94 @@ +packetID = (int) $packetID; + } + + public function pid(){ + return $this->packetID; + } + + public function __destruct(){} +} \ No newline at end of file diff --git a/src/network/raknet/RakNetParser.php b/src/network/raknet/RakNetParser.php new file mode 100644 index 000000000..fa2f6dca2 --- /dev/null +++ b/src/network/raknet/RakNetParser.php @@ -0,0 +1,208 @@ +buffer =& $buffer; + $this->offset = 0; + if(strlen($this->buffer) > 0){ + $this->parse(); + }else{ + $this->packet = false; + } + } + + private function get($len){ + if($len <= 0){ + $this->offset = strlen($this->buffer) - 1; + return ""; + } + if($len === true){ + return substr($this->buffer, $this->offset); + } + $this->offset += $len; + return substr($this->buffer, $this->offset - $len, $len); + } + + private function getLong($unsigned = false){ + return Utils::readLong($this->get(8), $unsigned); + } + + private function getInt($unsigned = false){ + return Utils::readInt($this->get(4), $unsigned); + } + + private function getShort($unsigned = false){ + return Utils::readShort($this->get(2), $unsigned); + } + + private function getLTriad(){ + return Utils::readTriad(strrev($this->get(3))); + } + + private function getByte(){ + return ord($this->get(1)); + } + + + private function feof(){ + return !isset($this->buffer{$this->offset}); + } + + private function parse(){ + $this->packet = new RakNetPacket(ord($this->get(1))); + $this->packet->buffer =& $this->buffer; + $this->packet->length = strlen($this->buffer); + switch($this->packet->pid()){ + case RakNetInfo::UNCONNECTED_PING: + case RakNetInfo::UNCONNECTED_PING_OPEN_CONNECTIONS: + $this->packet->pingID = $this->getLong(); + $this->offset += 16; //Magic + break; + case RakNetInfo::OPEN_CONNECTION_REQUEST_1: + $this->offset += 16; //Magic + $this->packet->structure = $this->getByte(); + $this->packet->mtuSize = strlen($this->get(true)); + break; + case RakNetInfo::OPEN_CONNECTION_REQUEST_2: + $this->offset += 16; //Magic + $this->packet->security = $this->get(5); + $this->packet->port = $this->getShort(false); + $this->packet->mtuSize = $this->getShort(false); + $this->packet->clientID = $this->getLong(); + break; + case RakNetInfo::DATA_PACKET_0: + case RakNetInfo::DATA_PACKET_1: + case RakNetInfo::DATA_PACKET_2: + case RakNetInfo::DATA_PACKET_3: + case RakNetInfo::DATA_PACKET_4: + case RakNetInfo::DATA_PACKET_5: + case RakNetInfo::DATA_PACKET_6: + case RakNetInfo::DATA_PACKET_7: + case RakNetInfo::DATA_PACKET_8: + case RakNetInfo::DATA_PACKET_9: + case RakNetInfo::DATA_PACKET_A: + case RakNetInfo::DATA_PACKET_B: + case RakNetInfo::DATA_PACKET_C: + case RakNetInfo::DATA_PACKET_D: + case RakNetInfo::DATA_PACKET_E: + case RakNetInfo::DATA_PACKET_F: + $this->packet->seqNumber = $this->getLTriad(); + $this->packet->data = array(); + while(!$this->feof() and ($pk = $this->parseDataPacket()) instanceof RakNetDataPacket){ + $this->packet->data[] = $pk; + } + break; + case RakNetInfo::NACK: + case RakNetInfo::ACK: + $count = $this->getShort(); + $this->packet->packets = array(); + 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->packet->packets[] = $c; + } + }else{ + $this->packet->packets[] = $this->getLTriad(); + } + } + break; + default: + $this->packet = false; + 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; + } + if(isset(ProtocolInfo::$packets[$pid])){ + $data = new ProtocolInfo::$packets[$pid]; + }else{ + $data = new UnknownPacket(); + $data->packetID = $pid; + } + $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); + } + return $data; + } + +} \ No newline at end of file diff --git a/src/utils/Cache.php b/src/utils/Cache.php index f9dc362c5..3d05eee60 100644 --- a/src/utils/Cache.php +++ b/src/utils/Cache.php @@ -28,7 +28,7 @@ class Cache{ public static function get($identifier){ if(isset(self::$cached[$identifier])){ - self::$cached[$identifier][1] += $minTTL; + self::$cached[$identifier][1] = microtime(true) + self::$cached[$identifier][2]; return self::$cached[$identifier][0]; } return false; diff --git a/src/utils/Utils.php b/src/utils/Utils.php index 9d77a8a63..a27a62ca7 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -31,6 +31,14 @@ class Utils{ return ((@fsockopen("8.8.8.8", 80, $e = null, $n = null, 2) !== false or @fsockopen("www.linux.org", 80, $e = null, $n = null, 2) !== false or @fsockopen("www.php.net", 80, $e = null, $n = null, 2) !== false) ? true:false); } + public static function getCallableIdentifier(callable $variable){ + if(is_array($variable)){ + return sha1(strtolower(get_class($variable))."::".strtolower($variable[1])); + }else{ + return sha1(strtolower($variable)); + } + } + public static function getUniqueID($raw = false, $extra = ""){ $machine = php_uname("a"); $machine .= file_exists("/proc/cpuinfo") ? file_get_contents("/proc/cpuinfo") : ""; diff --git a/src/world/Entity.php b/src/world/Entity.php index 4eb2772a7..e96703152 100644 --- a/src/world/Entity.php +++ b/src/world/Entity.php @@ -572,24 +572,24 @@ class Entity extends Position{ $players = $this->server->api->player->getAll($this->level); if($this->player instanceof Player){ unset($players[$this->player->CID]); - $this->server->api->player->broadcastPacket($players, MC_MOVE_PLAYER, array( - "eid" => $this->eid, - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "yaw" => $this->yaw, - "pitch" => $this->pitch, - "bodyYaw" => $this->yaw, - )); + $pk = new MovePlayerPacket; + $pk->eid = $this->eid; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->bodyYaw = $this->yaw; + $this->server->api->player->broadcastPacket($players, $pk); }else{ - $this->server->api->player->broadcastPacket($players, MC_MOVE_ENTITY_POSROT, array( - "eid" => $this->eid, - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "yaw" => $this->yaw, - "pitch" => $this->pitch, - )); + $pk = new MoveEntityPacket_PosRot; + $pk->eid = $this->eid; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $this->server->api->player->broadcastPacket($players, $pk); } } }else{ @@ -661,116 +661,135 @@ class Entity extends Position{ if($this->player->connected !== true or $this->player->spawned === false){ return false; } - $player->dataPacket(MC_ADD_PLAYER, array( - "clientID" => 0,/*$this->player->clientID,*/ - "username" => $this->player->username, - "eid" => $this->eid, - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "yaw" => 0, - "pitch" => 0, - "unknown1" => 0, - "unknown2" => 0, - "metadata" => $this->getMetadata(), - )); - $player->dataPacket(MC_PLAYER_EQUIPMENT, array( - "eid" => $this->eid, - "block" => $this->player->getSlot($this->player->slot)->getID(), - "meta" => $this->player->getSlot($this->player->slot)->getMetadata(), - "slot" => 0, - )); + + $pk = new AddPlayerPacket; + $pk->clientID = 0; //$this->player->clientID; + $pk->username = $this->player->username; + $pk->eid = $this->eid; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->yaw = 0; + $pk->pitch = 0; + $pk->unknown1 = 0; + $pk->unknown2 = 0; + $pk->metadata = $this->getMetadata(); + $player->dataPacket($pk); + + $pk = new SetEntityMotionPacket; + $pk->eid = $this->eid; + $pk->speedX = $this->speedX; + $pk->speedY = $this->speedY; + $pk->speedZ = $this->speedZ; + $player->dataPacket($pk); + + $pk = new PlayerEquipmentPacket; + $pk->eid = $this->eid; + $pk->item = $this->player->getSlot($this->player->slot)->getID(); + $pk->meta = $this->player->getSlot($this->player->slot)->getMetadata(); + $pk->slot = 0; + $player->dataPacket($pk); $this->player->sendArmor($player); break; case ENTITY_ITEM: - $player->dataPacket(MC_ADD_ITEM_ENTITY, array( - "eid" => $this->eid, - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "yaw" => $this->yaw, - "pitch" => $this->pitch, - "roll" => 0, - "block" => $this->type, - "meta" => $this->meta, - "stack" => $this->stack, - )); - $player->dataPacket(MC_SET_ENTITY_MOTION, array( - "eid" => $this->eid, - "speedX" => (int) ($this->speedX * 400), - "speedY" => (int) ($this->speedY * 400), - "speedZ" => (int) ($this->speedZ * 400), - )); + $pk = new AddItemEntityPacket; + $pk->eid = $this->eid; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->roll = 0; + $pk->item = BlockAPI::getItem($this->type, $this->meta, $this->stack); + $pk->metadata = $this->getMetadata(); + $player->dataPacket($pk); + + $pk = new SetEntityMotionPacket; + $pk->eid = $this->eid; + $pk->speedX = $this->speedX; + $pk->speedY = $this->speedY; + $pk->speedZ = $this->speedZ; + $player->dataPacket($pk); break; case ENTITY_MOB: - $player->dataPacket(MC_ADD_MOB, array( - "type" => $this->type, - "eid" => $this->eid, - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "yaw" => 0, - "pitch" => 0, - "metadata" => $this->getMetadata(), - )); - $player->dataPacket(MC_SET_ENTITY_MOTION, array( - "eid" => $this->eid, - "speedX" => (int) ($this->speedX * 400), - "speedY" => (int) ($this->speedY * 400), - "speedZ" => (int) ($this->speedZ * 400), - )); + $pk = new AddMobPacket; + $pk->eid = $this->eid; + $pk->type = $this->type; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->metadata = $this->getMetadata(); + $player->dataPacket($pk); + + $pk = new SetEntityMotionPacket; + $pk->eid = $this->eid; + $pk->speedX = $this->speedX; + $pk->speedY = $this->speedY; + $pk->speedZ = $this->speedZ; + $player->dataPacket($pk); break; case ENTITY_OBJECT: if($this->type === OBJECT_PAINTING){ - $player->dataPacket(MC_ADD_PAINTING, array( - "eid" => $this->eid, - "x" => (int) $this->x, - "y" => (int) $this->y, - "z" => (int) $this->z, - "direction" => $this->getDirection(), - "title" => $this->data["Motive"], - )); + $pk = new AddPaintingPacket; + $pk->eid = $this->eid; + $pk->x = (int) $this->x; + $pk->y = (int) $this->y; + $pk->z = (int) $this->z; + $pk->direction = $this->getDirection(); + $pk->title = $this->data["Motive"]; + $player->dataPacket($pk); }elseif($this->type === OBJECT_PRIMEDTNT){ - $player->dataPacket(MC_ADD_ENTITY, array( - "eid" => $this->eid, - "type" => $this->type, - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "did" => 0, - )); + $pk = new AddEntityPacket; + $pk->eid = $this->eid; + $pk->type = $this->type; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->did = 0; + $player->dataPacket($pk); + + $pk = new SetEntityMotionPacket; + $pk->eid = $this->eid; + $pk->speedX = $this->speedX; + $pk->speedY = $this->speedY; + $pk->speedZ = $this->speedZ; + $player->dataPacket($pk); }elseif($this->type === OBJECT_ARROW){ - $player->dataPacket(MC_ADD_ENTITY, array( - "eid" => $this->eid, - "type" => $this->type, - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "did" => 0, - )); - $player->dataPacket(MC_SET_ENTITY_MOTION, array( - "eid" => $this->eid, - "speedX" => (int) ($this->speedX * 400), - "speedY" => (int) ($this->speedY * 400), - "speedZ" => (int) ($this->speedZ * 400), - )); + $pk = new AddEntityPacket; + $pk->eid = $this->eid; + $pk->type = $this->type; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->did = 0; + $player->dataPacket($pk); + + $pk = new SetEntityMotionPacket; + $pk->eid = $this->eid; + $pk->speedX = $this->speedX; + $pk->speedY = $this->speedY; + $pk->speedZ = $this->speedZ; + $player->dataPacket($pk); } break; case ENTITY_FALLING: - $player->dataPacket(MC_ADD_ENTITY, array( - "eid" => $this->eid, - "type" => $this->type, - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "did" => -$this->data["Tile"], - )); - $player->dataPacket(MC_SET_ENTITY_MOTION, array( - "eid" => $this->eid, - "speedX" => (int) ($this->speedX * 400), - "speedY" => (int) ($this->speedY * 400), - "speedZ" => (int) ($this->speedZ * 400), - )); + $pk = new AddEntityPacket; + $pk->eid = $this->eid; + $pk->type = $this->type; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->did = -$this->data["Tile"]; + $player->dataPacket($pk); + + $pk = new SetEntityMotionPacket; + $pk->eid = $this->eid; + $pk->speedX = $this->speedX; + $pk->speedY = $this->speedY; + $pk->speedZ = $this->speedZ; + $player->dataPacket($pk); break; } } @@ -828,7 +847,7 @@ class Entity extends Position{ $this->server->preparedSQL->entity->setLevel->reset(); $this->server->preparedSQL->entity->setLevel->clear(); $this->server->preparedSQL->entity->setLevel->bindValue(":level", $this->level->getName(), SQLITE3_TEXT); - $this->server->preparedSQL->entity->setLevel->bindValue(":eid", $this->eid, SQLITE3_TEXT); + $this->server->preparedSQL->entity->setLevel->bindValue(":eid", $this->eid, SQLITE3_INTEGER); $this->server->preparedSQL->entity->setLevel->execute(); } $this->x = $pos->x; @@ -847,7 +866,7 @@ class Entity extends Position{ $this->server->preparedSQL->entity->setPosition->bindValue(":z", $this->z, SQLITE3_TEXT); $this->server->preparedSQL->entity->setPosition->bindValue(":pitch", $this->pitch, SQLITE3_TEXT); $this->server->preparedSQL->entity->setPosition->bindValue(":yaw", $this->yaw, SQLITE3_TEXT); - $this->server->preparedSQL->entity->setPosition->bindValue(":eid", $this->eid, SQLITE3_TEXT); + $this->server->preparedSQL->entity->setPosition->bindValue(":eid", $this->eid, SQLITE3_INTEGER); $this->server->preparedSQL->entity->setPosition->execute(); } @@ -981,9 +1000,9 @@ class Entity extends Position{ $this->server->api->dhandle("entity.event", array("entity" => $this, "event" => 2)); //Ouch! sound } if($this->player instanceof Player){ - $this->player->dataPacket(MC_SET_HEALTH, array( - "health" => $this->health, - )); + $pk = new SetHealthPacket; + $pk->health = $this->health; + $this->player->dataPacket($pk); } if($this->health <= 0 and $this->dead === false){ $this->spawnDrops(); @@ -995,14 +1014,14 @@ class Entity extends Position{ $this->updateMetadata(); $this->dead = true; if($this->player instanceof Player){ - $this->server->api->player->broadcastPacket($this->server->api->player->getAll($this->level), MC_MOVE_ENTITY_POSROT, array( - "eid" => $this->eid, - "x" => -256, - "y" => 128, - "z" => -256, - "yaw" => 0, - "pitch" => 0, - )); + $pk = new MoveEntityPacket_PosRot; + $pk->eid = $this->eid; + $pk->x = -256; + $pk->y = 128; + $pk->z = -256; + $pk->yaw = 0; + $pk->pitch = 0; + $this->server->api->player->broadcastPacket($this->level->players, $pk); }else{ $this->server->api->dhandle("entity.event", array("entity" => $this, "event" => 3)); //Entity dead } diff --git a/src/world/Explosion.php b/src/world/Explosion.php index d94361d0b..751b3a735 100644 --- a/src/world/Explosion.php +++ b/src/world/Explosion.php @@ -114,13 +114,13 @@ class Explosion{ $this->level->level->setBlockID($block->x, $block->y, $block->z, 0); $send[] = new Vector3($block->x - $source->x, $block->y - $source->y, $block->z - $source->z); } - $server->api->player->broadcastPacket($server->api->player->getAll($this->level), MC_EXPLOSION, array( - "x" => $this->source->x, - "y" => $this->source->y, - "z" => $this->source->z, - "radius" => $this->size, - "records" => $send, - )); + $pk = new ExplodePacket; + $pk->x = $this->source->x; + $pk->y = $this->source->y; + $pk->z = $this->source->z; + $pk->radius = $this->size; + $pk->records = $send; + $server->api->player->broadcastPacket($this->level->players, $pk); } } diff --git a/src/world/Level.php b/src/world/Level.php index 02099398f..84ff983be 100644 --- a/src/world/Level.php +++ b/src/world/Level.php @@ -78,10 +78,11 @@ class Level{ } if($this->server->api->dhandle("time.change", array("level" => $this, "time" => $time)) !== false){ $this->time = $time; - $this->server->api->player->broadcastPacket($this->players, MC_SET_TIME, array( - "time" => (int) $this->time, - "started" => $this->stopTime == false, - )); + + $pk = new SetTimePacket; + $pk->time = (int) $this->time; + $pk->started = $this->stopTime == false; + $this->server->api->player->broadcastPacket($this->players, $pk); } } @@ -109,13 +110,13 @@ class Level{ if(count($this->changedBlocks) > 0){ foreach($this->changedBlocks as $blocks){ foreach($blocks as $b){ - $this->server->api->player->broadcastPacket($this->players, MC_UPDATE_BLOCK, array( - "x" => $b->x, - "y" => $b->y, - "z" => $b->z, - "block" => $b->getID(), - "meta" => $b->getMetadata(), - )); + $pk = new UpdateBlockPacket; + $pk->x = $b->x; + $pk->y = $b->y; + $pk->z = $b->z; + $pk->block = $b->getID(); + $pk->meta = $b->getMetadata(); + $this->server->api->player->broadcastPacket($this->players, $pk); } } $this->changedBlocks = array(); @@ -286,13 +287,13 @@ class Level{ public function setBlockRaw(Vector3 $pos, Block $block, $direct = true, $send = true){ if(($ret = $this->level->setBlock($pos->x, $pos->y, $pos->z, $block->getID(), $block->getMetadata())) === true and $send !== false){ if($direct === true){ - $this->server->api->player->broadcastPacket($this->players, MC_UPDATE_BLOCK, array( - "x" => $pos->x, - "y" => $pos->y, - "z" => $pos->z, - "block" => $block->getID(), - "meta" => $block->getMetadata(), - )); + $pk = new UpdateBlockPacket; + $pk->x = $pos->x; + $pk->y = $pos->y; + $pk->z = $pos->z; + $pk->block = $block->getID(); + $pk->meta = $block->getMetadata(); + $this->server->api->player->broadcastPacket($this->players, $pk); }elseif($direct === false){ if(!($pos instanceof Position)){ $pos = new Position($pos->x, $pos->y, $pos->z, $this); @@ -326,13 +327,13 @@ class Level{ $block->position($pos); if($direct === true){ - $this->server->api->player->broadcastPacket($this->players, MC_UPDATE_BLOCK, array( - "x" => $pos->x, - "y" => $pos->y, - "z" => $pos->z, - "block" => $block->getID(), - "meta" => $block->getMetadata(), - )); + $pk = new UpdateBlockPacket; + $pk->x = $pos->x; + $pk->y = $pos->y; + $pk->z = $pos->z; + $pk->block = $block->getID(); + $pk->meta = $block->getMetadata(); + $this->server->api->player->broadcastPacket($this->players, $pk); }else{ $i = ($pos->x >> 4).":".($pos->y >> 4).":".($pos->z >> 4); if(!isset($this->changedBlocks[$i])){ diff --git a/src/world/Tile.php b/src/world/Tile.php index d095850b1..b7ccd4283 100644 --- a/src/world/Tile.php +++ b/src/world/Tile.php @@ -142,26 +142,27 @@ class Tile extends Position{ }else{ $player->windows[$id] = $this; } - $player->dataPacket(MC_CONTAINER_OPEN, array( - "windowid" => $id, - "type" => WINDOW_CHEST, - "slots" => is_array($player->windows[$id]) ? CHEST_SLOTS << 1:CHEST_SLOTS, - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - )); + + $pk = new ContainerOpenPacket; + $pk->windowid = $id; + $pk->type = WINDOW_CHEST; + $pk->slots = is_array($player->windows[$id]) ? CHEST_SLOTS << 1:CHEST_SLOTS; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $player->dataPacket($pk); $slots = array(); if(is_array($player->windows[$id])){ $all = $this->server->api->player->getAll($this->level); - foreach($player->windows[$id] as $ob){ - $this->server->api->player->broadcastPacket($all, MC_TILE_EVENT, array( - "x" => $ob->x, - "y" => $ob->y, - "z" => $ob->z, - "case1" => 1, - "case2" => 2, - )); + foreach($player->windows[$id] as $ob){ + $pk = new TileEventPacket; + $pk->x = $ob->x; + $pk->y = $ob->y; + $pk->z = $ob->z; + $pk->case1 = 1; + $pk->case2 = 2; + $this->server->api->player->broadcastPacket($all, $pk); for($s = 0; $s < CHEST_SLOTS; ++$s){ $slot = $ob->getSlot($s); if($slot->getID() > AIR and $slot->count > 0){ @@ -172,13 +173,13 @@ class Tile extends Position{ } } }else{ - $this->server->api->player->broadcastPacket($this->server->api->player->getAll($this->level), MC_TILE_EVENT, array( - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "case1" => 1, - "case2" => 2, - )); + $pk = new TileEventPacket; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->case1 = 1; + $pk->case2 = 2; + $this->server->api->player->broadcastPacket($this->server->api->player->getAll($this->level), $pk); for($s = 0; $s < CHEST_SLOTS; ++$s){ $slot = $this->getSlot($s); if($slot->getID() > AIR and $slot->count > 0){ @@ -188,24 +189,26 @@ class Tile extends Position{ } } } - $player->dataPacket(MC_CONTAINER_SET_CONTENT, array( - "windowid" => $id, - "count" => count($slots), - "slots" => $slots, - )); + + $pk = new ContainerSetContentPacket; + $pk->windowid = $id; + $pk->slots = $slots; + $player->dataPacket($pk); return true; }elseif($this->class === TILE_FURNACE){ $player->windowCnt++; $player->windowCnt = $id = max(2, $player->windowCnt % 99); $player->windows[$id] = $this; - $player->dataPacket(MC_CONTAINER_OPEN, array( - "windowid" => $id, - "type" => WINDOW_FURNACE, - "slots" => FURNACE_SLOTS, - "x" => $this->x, - "y" => $this->y, - "z" => $this->z - )); + + $pk = new ContainerOpenPacket; + $pk->windowid = $id; + $pk->type = WINDOW_FURNACE; + $pk->slots = FURNACE_SLOTS; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $player->dataPacket($pk); + $slots = array(); for($s = 0; $s < FURNACE_SLOTS; ++$s){ $slot = $this->getSlot($s); @@ -215,11 +218,10 @@ class Tile extends Position{ $slots[] = BlockAPI::getItem(AIR, 0, 0); } } - $player->dataPacket(MC_CONTAINER_SET_CONTENT, array( - "windowid" => $id, - "count" => count($slots), - "slots" => $slots - )); + $pk = new ContainerSetContentPacket; + $pk->windowid = $id; + $pk->slots = $slots; + $player->dataPacket($pk); return true; } } @@ -383,12 +385,12 @@ class Tile extends Position{ $nbt->write(chr(NBT::TAG_END)); - $player->dataPacket(MC_ENTITY_DATA, array( - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "namedtag" => $nbt->binary, - )); + $pk = new EntityDataPacket; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->namedtag = $nbt->binary; + $player->dataPacket($pk); break; case TILE_SIGN: $nbt = new NBT(); @@ -428,12 +430,12 @@ class Tile extends Position{ $nbt->write(chr(NBT::TAG_END)); - $player->dataPacket(MC_ENTITY_DATA, array( - "x" => $this->x, - "y" => $this->y, - "z" => $this->z, - "namedtag" => $nbt->binary, - )); + $pk = new EntityDataPacket; + $pk->x = $this->x; + $pk->y = $this->y; + $pk->z = $this->z; + $pk->namedtag = $nbt->binary; + $player->dataPacket($pk); break; } }