More packets, new structure

This commit is contained in:
Shoghi Cervantes Pueyo 2012-12-06 16:10:26 +01:00
parent 2fd71922ca
commit 8b1c010b4d
9 changed files with 213 additions and 69 deletions

View File

@ -58,11 +58,11 @@ class CustomPacketHandler{
break;
case 0x09:
if($this->c === false){
$this->data["clientID"] = $this->get(8);
$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 .= $this->data["clientID"];
$this->raw .= Utils::writeLong($this->data["clientID"]);
$this->raw .= Utils::writeLong($this->data["session"]);
$this->raw .= "\x00";
}
@ -124,6 +124,9 @@ class CustomPacketHandler{
case 0x15:
//null
break;
case 0x18:
//null
break;
case 0x82:
if($this->c === false){
$this->data["username"] = $this->get(Utils::readShort($this->get(2), false));
@ -139,6 +142,13 @@ class CustomPacketHandler{
$this->data["status"] = Utils::readInt($this->get(4));
}else{
$this->raw .= Utils::writeInt($this->data["status"]);
}
break;
case 0x84:
if($this->c === false){
$this->data["status"] = ord($this->get(1));
}else{
$this->raw .= chr($this->data["status"]);
}
break;
case 0x85:
@ -157,22 +167,59 @@ class CustomPacketHandler{
break;
case 0x87:
if($this->c === false){
$this->data["seed"] = $this->get(4);
$this->data["spawnX"] = Utils::readInt($this->get(4));
$this->data["spawnY"] = Utils::readInt($this->get(4));
$this->data["spawnZ"] = Utils::readInt($this->get(4));
$this->data["seed"] = Utils::readInt($this->get(4));
$this->data["unknown1"] = Utils::readInt($this->get(4));
$this->data["gamemode"] = Utils::readInt($this->get(4));
$this->data["unknown2"] = 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 .= $this->data["seed"];
$this->raw .= Utils::writeInt($this->data["spawnX"]);
$this->raw .= Utils::writeInt($this->data["spawnY"]);
$this->raw .= Utils::writeInt($this->data["spawnZ"]);
$this->raw .= Utils::writeInt($this->data["seed"]);
$this->raw .= Utils::writeInt($this->data["unknown1"]);
$this->raw .= Utils::writeInt($this->data["gamemode"]);
$this->raw .= Utils::writeInt($this->data["unknown2"]);
$this->raw .= Utils::writeFloat($this->data["x"]);
$this->raw .= Utils::writeFloat($this->data["y"]);
$this->raw .= Utils::writeFloat($this->data["z"]);
}
break;
case 0x94: //MovePlayer
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 0x96: //RemoveBlock
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"] = ord($this->get(1));
}else{
$this->raw .= Utils::writeInt($this->data["x"]);
$this->raw .= Utils::writeInt($this->data["y"]);
$this->raw .= Utils::writeInt($this->data["z"]);
$this->raw .= chr($this->data["face"]);
}
break;
case 0xa5: //SetHealth
if($this->c === false){
$this->data["health"] = ord($this->get(1));
}else{
$this->raw .= chr($this->data["health"]);
}
break;
case 0xb1:
if($this->c === false){

View File

@ -28,20 +28,20 @@ the Free Software Foundation, either version 3 of the License, or
class PocketMinecraftClient{
protected $interface, $protocol, $entities, $player, $cnt, $events, $username, $version, $clientID, $connected, $serverID, $start;
var $serverList = array(), $counter;
function __construct($username, $protocol = CURRENT_PROTOCOL, $version = CURRENT_VERSION){
function __construct($username, $protocol = CURRENT_PROTOCOL, $clientID = false, $version = CURRENT_VERSION){
//$this->player = new Player($username);
$this->start = microtime(true);
$this->version = (int) $version;
$this->username = $username;
$this->connected = false;
$this->cnt = 1;
$this->clientID = Utils::getRandomBytes(8);
$this->clientID = $clientID === false ? Utils::readLong(Utils::getRandomBytes(8)):$clientID;
$this->events = array("disabled" => array());
$this->actions = array();
$this->interface = new MinecraftInterface("255.255.255.255", $protocol, 19132);
console("[INFO] Creating Minecraft Client");
console("[INFO] Starting Minecraft Client");
console("[INFO] Username: ".$this->username);
console("[INFO] Version: ".$this->version);
console("[INFO] Client GUID: ".$this->clientID);
$this->event("onReceivedPacket", "packetHandler", true);
$this->stop = false;
$this->counter = array(0,0);
@ -118,7 +118,7 @@ class PocketMinecraftClient{
array(
"id" => 0x09,
"clientID" => $this->clientID,
"session" => "\x00\x00\x00\x00\x03\x1c\xaf\x05",
"session" => Utils::readLong("\x00\x00\x00\x00\x03\x1c\xaf\x05"),
),
));
++$this->counter[0];
@ -138,6 +138,7 @@ class PocketMinecraftClient{
"port" => 19132,
"dataArray" => $data["dataArray"],
"session" => $data["session"],
"session2" => $data["session2"],
),
));
++$this->counter[0];
@ -146,7 +147,7 @@ class PocketMinecraftClient{
0x00,
array(
"id" => 0x00,
"payload" => "\x00\x00\x00\x00\x00".$data["session"]."\x5e",
"payload" => $data["session"],
),
));
++$this->counter[0];
@ -159,7 +160,7 @@ class PocketMinecraftClient{
),
));
++$this->counter[0];
$this->send(0x84, array(
/*$this->send(0x84, array(
$this->counter[0],
0x00,
array(
@ -167,7 +168,7 @@ class PocketMinecraftClient{
"message" => $this->username,
),
));
++$this->counter[0];
++$this->counter[0];*/
break;
case 0x86:
console("[DEBUG] Time: ".$data["time"], true, true, 2);

View File

@ -28,28 +28,54 @@ the Free Software Foundation, either version 3 of the License, or
require_once("classes/Session.class.php");
class PocketMinecraftServer{
var $seed, $protocol;
protected $interface, $entities, $player, $cnt, $events, $username, $version, $clients, $serverType;
function __construct($username, $protocol = CURRENT_PROTOCOL, $version = CURRENT_VERSION){
//$this->player = new Player($username);
var $seed, $protocol, $gamemode, $name, $maxClients, $clients;
protected $interface, $entities, $player, $cnt, $events, $version, $serverType;
function __construct($name, $gamemode = 1, $seed = false, $port = 19132, $protocol = CURRENT_PROTOCOL, $serverID = false, $version = CURRENT_VERSION){
$this->gamemode = (int) $gamemode;
$this->port = (int) $port;
$this->version = (int) $version;
$this->username = $username;
$this->name = $name;
$this->cnt = 1;
$this->serverID = Utils::getRandomBytes(8);
$this->seed = Utils::getRandomBytes(4);//"\x4f\xf0\x2d\x84";
$this->maxClients = 20;
$this->serverID = $serverID === false ? Utils::readLong(Utils::getRandomBytes(8)):$serverID;
$this->seed = $seed === false ? Utils::readInt(Utils::getRandomBytes(4)):((int) $seed);
$this->events = array("disabled" => array());
$this->actions = array();
$this->clients = array();
$this->protocol = (int) $protocol;
$this->time = 0;
//$this->event("onTick", "onTick", true);
$this->event("onChat", "eventHandler", true);
//$this->action(1000000, '$this->time += 10000;$this->trigger("onTimeChange", $this->time);');
$this->setType("normal");
$this->interface = new MinecraftInterface("255.255.255.255", $this->protocol, 19132, true, false);
console("[INFO] Creating Minecraft Server");
console("[INFO] Username: ".$this->username);
console("[INFO] Seed: ".Utils::readInt($this->seed));
//console("[INFO] Protocol: ".$this->protocol);
$this->interface = new MinecraftInterface("255.255.255.255", $this->protocol, $this->port, true, false);
console("[INFO] Starting Minecraft PE Server at *:".$this->port);
$this->action(1000000 * 5 * 60, '$this->chat(false, "This server uses Pocket-Minecraft-PHP");');
sleep(2);
$this->action(1000000 * 5 * 60, '$this->chat(false, "Check it at http://bit.ly/RE7uaW");');
console("[INFO] Server Name: ".$this->name);
console("[INFO] Server GUID: ".$this->serverID);
console("[INFO] Seed: ".$this->seed);
console("[INFO] Gamemode: ".($this->gamemode === 0 ? "survival":"creative"));
console("[INFO] Max Clients: ".$this->maxClients);
$this->stop = false;
}
public function close($reason = "stop"){
$this->chat(false, "Stopping server...");
$this->stop = true;
$this->trigger("onClose");
}
public function chat($owner, $text, $target = true){
$message = "";
if($owner !== false){
$message = "<".$owner."> ";
}
$message .= $text;
$this->trigger("onChat", $text);
}
public function setType($type = "demo"){
switch($type){
case "normal":
@ -62,6 +88,14 @@ class PocketMinecraftServer{
}
public function eventHandler($data, $event){
switch($event){
case "onChat":
console("[CHAT] $data");
break;
}
}
public function action($microseconds, $code){
$this->actions[] = array($microseconds / 1000000, microtime(true), $code);
console("[INTERNAL] Attached to action ".$microseconds, true, true, 3);
@ -72,6 +106,7 @@ class PocketMinecraftServer{
register_tick_function(array($this, "tickerFunction"));
$this->action(50000, '$this->trigger("onTick", $time);');
$this->event("onReceivedPacket", "packetHandler", true);
register_shutdown_function(array($this, "close"));
$this->process();
}
@ -102,7 +137,7 @@ class PocketMinecraftServer{
$data[0],
$this->serverID,
MAGIC,
$this->serverType. $this->username,
$this->serverType. $this->name . " [".count($this->clients)."/".$this->maxClients."]",
), false, $packet["ip"], $packet["port"]);
break;
case 0x05:

View File

@ -60,7 +60,7 @@ class SerializedPacketHandler{
$pid = ord($this->get(1));
}
$len = Utils::readShort($this->get(2), false) >> 3;
$len = ceil(Utils::readShort($this->get(2), false) / 8); //Utils::readShort($this->get(2), false) >> 3;
if($pid !== 0x00){
$c = Utils::readTriad($this->get(3));
}

View File

@ -27,30 +27,75 @@ the Free Software Foundation, either version 3 of the License, or
class Session{
protected $server, $serverID, $timeout, $eventID, $connected;
protected $server, $serverID, $timeout, $connected, $evid;
var $clientID, $ip, $port, $counter, $username;
function __construct($server, $clientID, $ip, $port){
$this->server = $server;
$this->clientID = $clientID;
$this->CID = $this->server->clientID($ip, $port);
$this->ip = $ip;
$this->port = $port;
$this->serverID =& $this->server->serverID;
$this->eventID = $this->server->event("onTick", array($this, "checkTimeout"));
console("[DEBUG] New Session started with ".$ip.":".$port, true, true, 2);
$this->timeout = microtime(true) + 25;
$this->evid = array();
$this->evid[] = array("onTick", $this->server->event("onTick", array($this, "checkTimeout")));
$this->evid[] = array("onClose", $this->server->event("onClose", array($this, "close")));
console("[DEBUG] New Session started with ".$ip.":".$port.". Client GUID ".$this->clientID, true, true, 2);
$this->connected = true;
$this->counter = array(0, 0);
}
public function checkTimeout($time){
if($time > $this->timeout){
$this->close();
$this->close("timeout");
}
}
public function close($reason = "timeout"){
$this->server->deleteEvent("onTick", $this->eventID);
public function close($reason = "server stop"){
foreach($this->evid as $ev){
$this->server->deleteEvent($ev[0], $ev[1]);
}
if($this->reason === "server stop"){
$this->send(0x84, array(
$this->counter[0],
0x00,
array(
"id" => 0x15,
),
));
++$this->counter[0];
}
$this->connected = false;
$this->server->trigger("onChat", $this->username." left the game");
console("[DEBUG] Session with ".$this->ip.":".$this->port." closed due to ".$reason, true, true, 2);
unset($this->server->clients[$this->CID]);
}
public function eventHandler($data, $event){
switch($event){
case "onTimeChange":
$this->send(0x84, array(
$this->counter[0],
0x00,
array(
"id" => 0x86,
"time" => $data,
),
));
++$this->counter[0];
break;
case "onChat":
$this->send(0x84, array(
$this->counter[0],
0x00,
array(
"id" => 0x85,
"message" => $data,
),
));
++$this->counter[0];
break;
}
}
public function handle($pid, &$data){
@ -72,16 +117,6 @@ class Session{
$this->send(0xc0, array(1, true, $data[0]));
}
switch($data["id"]){
/*case 0x00:
$this->send(0x84, array(
$this->counter[0],
0x40,
array(
"payload" => $data["payload"],
),
));
++$this->counter[0];
break;*/
case 0x15:
$this->close("client disconnect");
break;
@ -102,6 +137,8 @@ class Session{
case 0x82:
$this->username = $data["username"];
console("[INFO] ".$this->username." connected from ".$this->ip.":".$this->port);
$this->evid[] = array("onTimeChange", $this->server->event("onTimeChange", array($this, "eventHandler")));
$this->evid[] = array("onChat", $this->server->event("onChat", array($this, "eventHandler")));
$this->send(0x84, array(
$this->counter[0],
0x00,
@ -120,15 +157,17 @@ class Session{
"x" => 128,
"y" => 100,
"z" => 128,
"spawnX" => 0,
"spawnY" => 0,
"spawnZ" => 0,
"unknown1" => 0,
"gamemode" => $this->server->gamemode,
"unknwon2" => 0,
),
));
++$this->counter[0];
break;
case 0x84:
console("[INFO] ".$this->username." spawned!");
console("[DEBUG] ".$this->username." spawned!", true, true, 2);
$this->server->trigger("onChat", $this->username." joined the game");
$this->eventHandler("Welcome to ".$this->server->name, "onChat");
break;
}
@ -141,7 +180,9 @@ class Session{
}
public function send($pid, $data = array(), $raw = false){
$this->server->send($pid, $data, $raw, $this->ip, $this->port);
if($this->connected === true){
$this->server->send($pid, $data, $raw, $this->ip, $this->port);
}
}
}

View File

@ -43,18 +43,23 @@ if(version_compare("5.4.0", PHP_VERSION) > 0){
define("HEX2BIN", true);
}
if(php_sapi_name()!=="cli"){
console("[ERROR] Use PHP-CLI to execute the client or create your own", true, true, 0);
if(php_sapi_name() !== "cli"){
console("[ERROR] Use PHP-CLI to execute the library or create your own", true, true, 0);
++$errors;
}
if(!function_exists("gzinflate")){
if(!extension_loaded("sockets")){
console("[ERROR] Unable to find Socket extension", true, true, 0);
++$errors;
}
/*if(!extension_loaded("zlib")){
console("[ERROR] Unable to find Zlib extension", true, true, 0);
++$errors;
}
}*/
if(!function_exists("socket_create")){
console("[ERROR] Unable to find Socket functions", true, true, 0);
if(!extension_loaded("sqlite3")){
console("[ERROR] Unable to find SQLite3 extension", true, true, 0);
++$errors;
}

View File

@ -27,7 +27,7 @@ the Free Software Foundation, either version 3 of the License, or
$pstruct = array(
0x02 => array(
"double", //Ping ID
"long", //Ping ID
"magic",
),
@ -39,7 +39,7 @@ $pstruct = array(
0x06 => array(
"magic",
8, //Server GUID
"long", //Server GUID
"byte", //Server Security
"short", //MTU Size
),
@ -49,12 +49,12 @@ $pstruct = array(
5, //Security Cookie (idk why it's sent here)
"short", //Server UDP Port
"short", //MTU Size
8, //Client GUID
"long", //Client GUID
),
0x08 => array(
"magic",
8, //Server GUID
"long", //Server GUID
"short", //Client UDP Port
"short", //MTU Size
"byte", //Security
@ -63,19 +63,19 @@ $pstruct = array(
0x1a => array(
"byte", //Server Version
"magic",
8, //Server GUID
"long", //Server GUID
),
0x1c => array(
"double", //Ping ID
8, //Server ID
"long", //Ping ID
"long", //Server GUID
"magic",
"string", //Data
),
0x1d => array(
"double", //Ping ID
8, //Server ID
"long", //Ping ID
"long", //Server GUID
"magic",
"string", //Data
),

View File

@ -27,11 +27,16 @@ the Free Software Foundation, either version 3 of the License, or
$dataName = array(
0x00 => "KeepAlive",
0x09 => "ClientHandshake",
0x10 => "ServerHandshake",
0x13 => "ClientConnect",
0x15 => "ClientDisconnect",
0x18 => "ServerDisconnect",
0x82 => "Login",
0x83 => "LoginStatus",
0x84 => "Ready",
@ -41,7 +46,17 @@ $dataName = array(
0x93 => "MoveEntity_PosRot",
0x94 => "MovePlayer",
0x96 => "RemoveBlock",
0x9d => "RequestChunk",
0x9f => "PlayerEquipment",
0xa1 => "UseItem",
0xa4 => "SetEntityMotion",
0xa5 => "SetHealth",
0xa7 => "Animate",
);

View File

@ -29,6 +29,6 @@ require_once("common/dependencies.php");
require_once("classes/PocketMinecraftServer.class.php");
file_put_contents("packets.log", "");
$server = new PocketMinecraftServer("TEST");
$server = new PocketMinecraftServer("PHP Server");
$server->setType("minecon");
$server->start();