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; break;
case 0x09: case 0x09:
if($this->c === false){ 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["session"] = Utils::readLong($this->get(8));
$this->data["unknown2"] = $this->get(1); $this->data["unknown2"] = $this->get(1);
}else{ }else{
$this->raw .= $this->data["clientID"]; $this->raw .= Utils::writeLong($this->data["clientID"]);
$this->raw .= Utils::writeLong($this->data["session"]); $this->raw .= Utils::writeLong($this->data["session"]);
$this->raw .= "\x00"; $this->raw .= "\x00";
} }
@ -124,6 +124,9 @@ class CustomPacketHandler{
case 0x15: case 0x15:
//null //null
break; break;
case 0x18:
//null
break;
case 0x82: case 0x82:
if($this->c === false){ if($this->c === false){
$this->data["username"] = $this->get(Utils::readShort($this->get(2), false)); $this->data["username"] = $this->get(Utils::readShort($this->get(2), false));
@ -141,6 +144,13 @@ class CustomPacketHandler{
$this->raw .= Utils::writeInt($this->data["status"]); $this->raw .= Utils::writeInt($this->data["status"]);
} }
break; break;
case 0x84:
if($this->c === false){
$this->data["status"] = ord($this->get(1));
}else{
$this->raw .= chr($this->data["status"]);
}
break;
case 0x85: case 0x85:
if($this->c === false){ if($this->c === false){
$this->data["message"] = $this->get(Utils::readShort($this->get(2), false)); $this->data["message"] = $this->get(Utils::readShort($this->get(2), false));
@ -157,23 +167,60 @@ class CustomPacketHandler{
break; break;
case 0x87: case 0x87:
if($this->c === false){ if($this->c === false){
$this->data["seed"] = $this->get(4); $this->data["seed"] = Utils::readInt($this->get(4));
$this->data["spawnX"] = Utils::readInt($this->get(4)); $this->data["unknown1"] = Utils::readInt($this->get(4));
$this->data["spawnY"] = Utils::readInt($this->get(4)); $this->data["gamemode"] = Utils::readInt($this->get(4));
$this->data["spawnZ"] = Utils::readInt($this->get(4)); $this->data["unknown2"] = Utils::readInt($this->get(4));
$this->data["x"] = Utils::readFloat($this->get(4)); $this->data["x"] = Utils::readFloat($this->get(4));
$this->data["y"] = Utils::readFloat($this->get(4)); $this->data["y"] = Utils::readFloat($this->get(4));
$this->data["z"] = Utils::readFloat($this->get(4)); $this->data["z"] = Utils::readFloat($this->get(4));
}else{ }else{
$this->raw .= $this->data["seed"]; $this->raw .= Utils::writeInt($this->data["seed"]);
$this->raw .= Utils::writeInt($this->data["spawnX"]); $this->raw .= Utils::writeInt($this->data["unknown1"]);
$this->raw .= Utils::writeInt($this->data["spawnY"]); $this->raw .= Utils::writeInt($this->data["gamemode"]);
$this->raw .= Utils::writeInt($this->data["spawnZ"]); $this->raw .= Utils::writeInt($this->data["unknown2"]);
$this->raw .= Utils::writeFloat($this->data["x"]); $this->raw .= Utils::writeFloat($this->data["x"]);
$this->raw .= Utils::writeFloat($this->data["y"]); $this->raw .= Utils::writeFloat($this->data["y"]);
$this->raw .= Utils::writeFloat($this->data["z"]); $this->raw .= Utils::writeFloat($this->data["z"]);
} }
break; 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: case 0xb1:
if($this->c === false){ if($this->c === false){
$this->data["message"] = $this->get(Utils::readShort($this->get(2), false)); $this->data["message"] = $this->get(Utils::readShort($this->get(2), false));

View File

@ -28,20 +28,20 @@ the Free Software Foundation, either version 3 of the License, or
class PocketMinecraftClient{ class PocketMinecraftClient{
protected $interface, $protocol, $entities, $player, $cnt, $events, $username, $version, $clientID, $connected, $serverID, $start; protected $interface, $protocol, $entities, $player, $cnt, $events, $username, $version, $clientID, $connected, $serverID, $start;
var $serverList = array(), $counter; 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->player = new Player($username);
$this->start = microtime(true); $this->start = microtime(true);
$this->version = (int) $version; $this->version = (int) $version;
$this->username = $username; $this->username = $username;
$this->connected = false; $this->connected = false;
$this->cnt = 1; $this->cnt = 1;
$this->clientID = Utils::getRandomBytes(8); $this->clientID = $clientID === false ? Utils::readLong(Utils::getRandomBytes(8)):$clientID;
$this->events = array("disabled" => array()); $this->events = array("disabled" => array());
$this->actions = array(); $this->actions = array();
$this->interface = new MinecraftInterface("255.255.255.255", $protocol, 19132); $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] Username: ".$this->username);
console("[INFO] Version: ".$this->version); console("[INFO] Client GUID: ".$this->clientID);
$this->event("onReceivedPacket", "packetHandler", true); $this->event("onReceivedPacket", "packetHandler", true);
$this->stop = false; $this->stop = false;
$this->counter = array(0,0); $this->counter = array(0,0);
@ -118,7 +118,7 @@ class PocketMinecraftClient{
array( array(
"id" => 0x09, "id" => 0x09,
"clientID" => $this->clientID, "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]; ++$this->counter[0];
@ -138,6 +138,7 @@ class PocketMinecraftClient{
"port" => 19132, "port" => 19132,
"dataArray" => $data["dataArray"], "dataArray" => $data["dataArray"],
"session" => $data["session"], "session" => $data["session"],
"session2" => $data["session2"],
), ),
)); ));
++$this->counter[0]; ++$this->counter[0];
@ -146,7 +147,7 @@ class PocketMinecraftClient{
0x00, 0x00,
array( array(
"id" => 0x00, "id" => 0x00,
"payload" => "\x00\x00\x00\x00\x00".$data["session"]."\x5e", "payload" => $data["session"],
), ),
)); ));
++$this->counter[0]; ++$this->counter[0];
@ -159,7 +160,7 @@ class PocketMinecraftClient{
), ),
)); ));
++$this->counter[0]; ++$this->counter[0];
$this->send(0x84, array( /*$this->send(0x84, array(
$this->counter[0], $this->counter[0],
0x00, 0x00,
array( array(
@ -167,7 +168,7 @@ class PocketMinecraftClient{
"message" => $this->username, "message" => $this->username,
), ),
)); ));
++$this->counter[0]; ++$this->counter[0];*/
break; break;
case 0x86: case 0x86:
console("[DEBUG] Time: ".$data["time"], true, true, 2); 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"); require_once("classes/Session.class.php");
class PocketMinecraftServer{ class PocketMinecraftServer{
var $seed, $protocol; var $seed, $protocol, $gamemode, $name, $maxClients, $clients;
protected $interface, $entities, $player, $cnt, $events, $username, $version, $clients, $serverType; protected $interface, $entities, $player, $cnt, $events, $version, $serverType;
function __construct($username, $protocol = CURRENT_PROTOCOL, $version = CURRENT_VERSION){ function __construct($name, $gamemode = 1, $seed = false, $port = 19132, $protocol = CURRENT_PROTOCOL, $serverID = false, $version = CURRENT_VERSION){
//$this->player = new Player($username); $this->gamemode = (int) $gamemode;
$this->port = (int) $port;
$this->version = (int) $version; $this->version = (int) $version;
$this->username = $username; $this->name = $name;
$this->cnt = 1; $this->cnt = 1;
$this->serverID = Utils::getRandomBytes(8); $this->maxClients = 20;
$this->seed = Utils::getRandomBytes(4);//"\x4f\xf0\x2d\x84"; $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->events = array("disabled" => array());
$this->actions = array(); $this->actions = array();
$this->clients = array(); $this->clients = array();
$this->protocol = (int) $protocol; $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->setType("normal");
$this->interface = new MinecraftInterface("255.255.255.255", $this->protocol, 19132, true, false); $this->interface = new MinecraftInterface("255.255.255.255", $this->protocol, $this->port, true, false);
console("[INFO] Creating Minecraft Server"); console("[INFO] Starting Minecraft PE Server at *:".$this->port);
console("[INFO] Username: ".$this->username); $this->action(1000000 * 5 * 60, '$this->chat(false, "This server uses Pocket-Minecraft-PHP");');
console("[INFO] Seed: ".Utils::readInt($this->seed)); sleep(2);
//console("[INFO] Protocol: ".$this->protocol); $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; $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"){ public function setType($type = "demo"){
switch($type){ switch($type){
case "normal": 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){ public function action($microseconds, $code){
$this->actions[] = array($microseconds / 1000000, microtime(true), $code); $this->actions[] = array($microseconds / 1000000, microtime(true), $code);
console("[INTERNAL] Attached to action ".$microseconds, true, true, 3); console("[INTERNAL] Attached to action ".$microseconds, true, true, 3);
@ -72,6 +106,7 @@ class PocketMinecraftServer{
register_tick_function(array($this, "tickerFunction")); register_tick_function(array($this, "tickerFunction"));
$this->action(50000, '$this->trigger("onTick", $time);'); $this->action(50000, '$this->trigger("onTick", $time);');
$this->event("onReceivedPacket", "packetHandler", true); $this->event("onReceivedPacket", "packetHandler", true);
register_shutdown_function(array($this, "close"));
$this->process(); $this->process();
} }
@ -102,7 +137,7 @@ class PocketMinecraftServer{
$data[0], $data[0],
$this->serverID, $this->serverID,
MAGIC, MAGIC,
$this->serverType. $this->username, $this->serverType. $this->name . " [".count($this->clients)."/".$this->maxClients."]",
), false, $packet["ip"], $packet["port"]); ), false, $packet["ip"], $packet["port"]);
break; break;
case 0x05: case 0x05:

View File

@ -60,7 +60,7 @@ class SerializedPacketHandler{
$pid = ord($this->get(1)); $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){ if($pid !== 0x00){
$c = Utils::readTriad($this->get(3)); $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{ class Session{
protected $server, $serverID, $timeout, $eventID, $connected; protected $server, $serverID, $timeout, $connected, $evid;
var $clientID, $ip, $port, $counter, $username; var $clientID, $ip, $port, $counter, $username;
function __construct($server, $clientID, $ip, $port){ function __construct($server, $clientID, $ip, $port){
$this->server = $server; $this->server = $server;
$this->clientID = $clientID; $this->clientID = $clientID;
$this->CID = $this->server->clientID($ip, $port);
$this->ip = $ip; $this->ip = $ip;
$this->port = $port; $this->port = $port;
$this->serverID =& $this->server->serverID; $this->serverID =& $this->server->serverID;
$this->eventID = $this->server->event("onTick", array($this, "checkTimeout")); $this->timeout = microtime(true) + 25;
console("[DEBUG] New Session started with ".$ip.":".$port, true, true, 2); $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->connected = true;
$this->counter = array(0, 0); $this->counter = array(0, 0);
} }
public function checkTimeout($time){ public function checkTimeout($time){
if($time > $this->timeout){ if($time > $this->timeout){
$this->close(); $this->close("timeout");
} }
} }
public function close($reason = "timeout"){ public function close($reason = "server stop"){
$this->server->deleteEvent("onTick", $this->eventID); 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->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); 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){ public function handle($pid, &$data){
@ -72,16 +117,6 @@ class Session{
$this->send(0xc0, array(1, true, $data[0])); $this->send(0xc0, array(1, true, $data[0]));
} }
switch($data["id"]){ switch($data["id"]){
/*case 0x00:
$this->send(0x84, array(
$this->counter[0],
0x40,
array(
"payload" => $data["payload"],
),
));
++$this->counter[0];
break;*/
case 0x15: case 0x15:
$this->close("client disconnect"); $this->close("client disconnect");
break; break;
@ -102,6 +137,8 @@ class Session{
case 0x82: case 0x82:
$this->username = $data["username"]; $this->username = $data["username"];
console("[INFO] ".$this->username." connected from ".$this->ip.":".$this->port); 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->send(0x84, array(
$this->counter[0], $this->counter[0],
0x00, 0x00,
@ -120,15 +157,17 @@ class Session{
"x" => 128, "x" => 128,
"y" => 100, "y" => 100,
"z" => 128, "z" => 128,
"spawnX" => 0, "unknown1" => 0,
"spawnY" => 0, "gamemode" => $this->server->gamemode,
"spawnZ" => 0, "unknwon2" => 0,
), ),
)); ));
++$this->counter[0]; ++$this->counter[0];
break; break;
case 0x84: 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; break;
} }
@ -141,7 +180,9 @@ class Session{
} }
public function send($pid, $data = array(), $raw = false){ public function send($pid, $data = array(), $raw = false){
if($this->connected === true){
$this->server->send($pid, $data, $raw, $this->ip, $this->port); $this->server->send($pid, $data, $raw, $this->ip, $this->port);
} }
}
} }

View File

@ -44,17 +44,22 @@ if(version_compare("5.4.0", PHP_VERSION) > 0){
} }
if(php_sapi_name() !== "cli"){ if(php_sapi_name() !== "cli"){
console("[ERROR] Use PHP-CLI to execute the client or create your own", true, true, 0); console("[ERROR] Use PHP-CLI to execute the library or create your own", true, true, 0);
++$errors; ++$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); console("[ERROR] Unable to find Zlib extension", true, true, 0);
++$errors; ++$errors;
} }*/
if(!function_exists("socket_create")){ if(!extension_loaded("sqlite3")){
console("[ERROR] Unable to find Socket functions", true, true, 0); console("[ERROR] Unable to find SQLite3 extension", true, true, 0);
++$errors; ++$errors;
} }

View File

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

View File

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

View File

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