Compare commits

..

43 Commits

Author SHA1 Message Date
db4bdcd2bd PocketMine-MP Alpha_1.2.1 2013-03-16 13:12:08 +01:00
ce8724c5ed PMF Plugin Loading 2013-03-16 12:52:14 +01:00
d46a61d0c4 Removed Server getting via Plugin Loading 2013-03-16 12:29:29 +01:00
1bfef261ab PMF Plugin Reading 2013-03-16 12:27:23 +01:00
6dfe348767 Added Command Permissions Whitelist 2013-03-16 09:54:42 +01:00
3f10e11ddf Array format fixes 2013-03-16 00:21:50 +01:00
5b79722fa9 Better NACK handling (#133, #16, fixes #75) 2013-03-16 00:16:47 +01:00
fc06e1bcaf Packet Sending Buffering 2013-03-16 00:09:00 +01:00
ffaaca6f2d PMF class 2013-03-15 21:54:19 +01:00
0660409987 Updated Spyc 2013-03-14 21:55:50 +01:00
bbc925b188 Updated Message level of World generation 2013-03-14 21:55:31 +01:00
6f7268902d Added the libtool dependency to the compile script 2013-03-14 19:42:23 +01:00
6851f9c7b1 Added a dynamic title function 2013-03-14 16:36:34 +01:00
9ec9d22bbc BlockAPI::setBlock now uses a Vector3 2013-03-10 13:34:11 +01:00
40842ec794 Fixed Vector3::add() 2013-03-10 13:33:52 +01:00
ab1c28fc57 Changed the api.op.check event check 2013-03-09 22:38:53 +01:00
a9f7d47c25 Added all the future tags 2013-03-09 13:58:22 +01:00
5241f0527b Fix typo for De-Op (I know a very little change) 2013-03-09 22:52:56 +10:30
5c7f397bde Changed default debug level 2013-03-09 12:52:57 +01:00
84ac13d591 Added checks 2013-03-09 12:40:53 +01:00
8bf4b5cafa Added callable type hinting 2013-03-09 10:08:42 +01:00
7acbf13a8a Updated README.md image 2013-03-09 09:33:39 +01:00
fa4813d335 Raised save interval to 25 minutes 2013-03-09 09:31:41 +01:00
3432a69a41 Cancel correctly Handling Events using return true 2013-03-09 09:27:29 +01:00
bc5516867c Fixed Quartz Blocks not getting placed correctly 2013-03-08 23:05:57 +01:00
5c17f77bcc Name update 2013-03-07 19:56:07 +01:00
5fab555c48 Real Minecraft username check 2013-03-07 18:46:04 +01:00
ba3dfd91db Removed unnecesary replace 2013-03-07 18:11:35 +01:00
8f21eb41ee Added message separation 2013-03-07 18:06:51 +01:00
d90e41c0d5 Fixed Server description not being displayed 2013-03-07 18:05:33 +01:00
aecfbbbdc1 Removed flying damage 2013-03-07 17:56:33 +01:00
1c63448c6c Drop in the correct position 2013-03-07 17:44:28 +01:00
8253d63d9b Case-insensitive playernames, removed Client ID kick 2013-03-07 17:43:44 +01:00
a7d8e22e7e Player inventory is changed using chests (Fixes #127) 2013-03-07 17:36:19 +01:00
ad11851c61 Remove items from Player inventory on drop 2013-03-07 17:15:12 +01:00
b259ed2532 Fixed #124 2013-03-06 20:29:49 +01:00
9510cbd716 New block touch event 2013-03-06 20:17:38 +01:00
8a345e6582 Target player gets notified of op 2013-03-06 19:28:24 +01:00
66fe5d2a3e Added Kicking on Ban 2013-03-06 19:21:50 +01:00
7f88ab95e2 Added the /sudo command 2013-03-06 19:19:12 +01:00
3355f71ab3 Added a tile.update event to the container slot change 2013-03-06 19:00:48 +01:00
e8c2662258 Get Item Lists from BlockAPI::fromString() method 2013-03-06 16:43:25 +01:00
6c4900cd32 Dev version 2013-03-06 14:40:58 +01:00
26 changed files with 547 additions and 252 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@ worlds/*
plugins/*
logs/*
*.log
*.pmf
server.properties
white-list.txt
banned-ips.txt

View File

@ -35,4 +35,5 @@ require_once(FILE_PATH."/src/dependencies.php");
$server = new ServerAPI();
$server->run();
kill(getmypid()); //Fix for segfault

View File

@ -1,4 +1,4 @@
![](http://www.pocketmine.org/favicon.png)
![](http://shoghicp.github.com/PocketMine-MP/favicon.png)
# PocketMine-MP [![Build Status](https://travis-ci.org/shoghicp/PocketMine-MP.png?branch=master)](https://travis-ci.org/shoghicp/PocketMine-MP)

View File

@ -18,6 +18,7 @@ echo "[INFO] Checking dependecies"
type make >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"make\""; exit 1; }
type autoconf >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"autoconf\""; exit 1; }
type automake >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"automake\""; exit 1; }
type libtool >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"libtool\""; exit 1; }
type gcc >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"gcc\""; exit 1; }
type m4 >> "$DIR/install.log" 2>&1 || { echo >&2 "[ERROR] Please install \"m4\""; exit 1; }

View File

@ -31,6 +31,7 @@ class BanAPI{
private $banned;
private $ops;
private $bannedIPs;
private $cmdWL = array();
function __construct(PocketMinecraftServer $server){
$this->server = $server;
}
@ -46,16 +47,22 @@ class BanAPI{
$this->server->api->console->register("kick", "Kicks a player", array($this, "commandHandler"));
$this->server->api->console->register("whitelist", "Manages White-listing", array($this, "commandHandler"));
$this->server->api->console->register("op", "Ops a player", array($this, "commandHandler"));
$this->server->api->console->register("deop", "Deops a player", array($this, "commandHandler"));
$this->server->api->console->register("deop", "De-ops a player", array($this, "commandHandler"));
$this->server->api->console->register("sudo", "Run a command as a player", array($this, "commandHandler"));
$this->server->api->console->alias("ban-ip", "banip add");
$this->server->api->console->alias("banlist", "ban list");
$this->server->api->console->alias("pardon", "ban remove");
$this->server->api->console->alias("pardon-ip", "banip remove");
$this->server->addHandler("console.command", array($this, "opCheck"), 1);
$this->server->addHandler("console.command", array($this, "permissionsCheck"), 1);
$this->cmdWhitelist("help");
}
public function cmdWhitelist($cmd){
$this->cmdWhitelist[strtolower(trim($cmd))] = true;
}
public function isOp($username){
if($this->server->api->dhandle("api.op.check", $username) === false){
if($this->server->api->dhandle("op.check", $username) === true){
return true;
}elseif($this->ops->exists($username)){
return true;
@ -63,16 +70,14 @@ class BanAPI{
return false;
}
public function opCheck($data, $event){
$whitelist = array(
"help",
);
if(in_array($data["cmd"], $whitelist, true)){
public function permissionsCheck($data, $event){
if(isset($this->cmdWhitelist[$data["cmd"]])){
return true;
}
if($data["issuer"] instanceof Player){
if($this->isOp($data["issuer"]->username)){
if($this->server->api->handle("console.check", $data) === true or $this->isOp($data["issuer"]->username)){
return true;
}
}elseif($data["issuer"] === "console"){
@ -84,23 +89,35 @@ class BanAPI{
public function commandHandler($cmd, $params, $issuer, $alias){
$output = "";
switch($cmd){
case "sudo":
$target = array_shift($params);
$player = $this->server->api->player->get($target);
if(!($player instanceof Player)){
$output .= "Player not connected.\n";
break;
}
$this->server->api->console->run(implode(" ", $params), $player);
$output .= "Command ran.\n";
break;
case "op":
$user = trim(implode(" ", $params));
$user = array_shift($params);
if($user == ""){
break;
}
$this->ops->set($user);
$this->ops->save();
$output .= $user." is now op\n";
$this->server->api->chat->sendTo(false, "You are now op.", $user);
break;
case "deop":
$user = trim(implode(" ", $params));
$user = array_shift($params);
if($user == ""){
break;
}
$this->ops->remove($user);
$this->ops->save();
$output .= $user." is not longer op\n";
$this->server->api->chat->sendTo(false, "You are not longer op.", $user);
break;
case "kick":
if(!isset($params[0])){
@ -200,7 +217,7 @@ class BanAPI{
break;
case "add":
case "ban":
$user = trim(implode($params));
$user = array_shift($params);
$this->banned->set($user);
$this->banned->save();
$player = $this->server->api->player->get($user);
@ -213,6 +230,7 @@ class BanAPI{
}else{
$this->server->api->chat->broadcast($user." has been banned\n");
}
$this->kick($user, "Banned");
$output .= "Player \"$user\" added to ban list\n";
break;
case "reload":
@ -246,7 +264,7 @@ class BanAPI{
$this->commandHandler("banip", array("pardon", $ip));
}
public function kick($username, $reason){
public function kick($username, $reason = "No Reason"){
$this->commandHandler("kick", array($username, $reason));
}

View File

@ -38,7 +38,14 @@ define("BLOCK_UPDATE_WEAK", 3);
class BlockAPI{
private $server;
public static function fromString($str){
public static function fromString($str, $multiple = false){
if($multiple === true){
$blocks = array();
foreach(explode(",",$str) as $b){
$blocks[] = BlockAPI::fromString($b, false);
}
return $blocks;
}else{
$b = explode(":", str_replace(" ", "_", trim($str)));
if(!isset($b[1])){
$meta = 0;
@ -56,6 +63,7 @@ class BlockAPI{
}
return $item;
}
}
public static function get($id, $meta = 0, $v = false){
$id = (int) $id;
@ -82,7 +90,7 @@ class BlockAPI{
return $i;
}
public function setBlock($block, $id, $meta, $update = true, $tiles = false){
public function setBlock(Vector3 $block, $id, $meta, $update = true, $tiles = false){
if(($block instanceof Vector3) or (($block instanceof Block) and $block->inWorld === true)){
$this->server->api->level->setBlock($block->x, $block->y, $block->z, (int) $id, (int) $meta, $update, $tiles);
return true;
@ -157,6 +165,11 @@ class BlockAPI{
$target = $this->getBlock($vector);
$item = $player->equipment;
if($this->server->api->dhandle("player.block.touch", array("type" => "break", "player" => $player, "target" => $target, "item" => $item)) === false){
return $this->cancelAction($target, $player);
}
if(!$target->isBreakable($item, $player) or $player->gamemode === ADVENTURE or ($player->lastBreak + $target->getBreakTime($item, $player)) >= microtime(true)){
return $this->cancelAction($target, $player);
}
@ -189,7 +202,7 @@ class BlockAPI{
"z" => $pos->z + mt_rand(2, 8) / 10,
"item" => $item,
);
if($this->server->api->handle("block.drop", $data) !== false){
if($this->server->api->handle("item.drop", $data) !== false){
for($count = $item->count; $count > 0; ){
$item->count = min($item->getMaxStackSize(), $count);
$count -= $item->count;
@ -217,11 +230,16 @@ class BlockAPI{
return $this->cancelAction($block, $player);
}
if($this->server->api->dhandle("player.block.touch", array("type" => "place", "player" => $player, "block" => $block, "target" => $target, "item" => $item)) === false){
return $this->cancelAction($block, $player);
}
if($target->isActivable === true){
if($this->server->api->dhandle("player.block.activate", array("player" => $player, "block" => $block, "target" => $target, "item" => $item)) !== false and $target->onActivate($this, $item, $player) === true){
return false;
}
}
if($player->gamemode === ADVENTURE){ //Adventure mode!!
return $this->cancelAction($block, $player);
}
@ -307,6 +325,7 @@ class BlockAPI{
return;
}
$this->updateBlock($data["x"], $data["y"], $data["z"], isset($data["type"]) ? $data["type"]:BLOCK_UPDATE_RANDOM);
return true;
}
public function flowLavaOn($source, $face){

View File

@ -34,27 +34,11 @@ class LevelAPI{
}
public function init(){
/*$this->server->event("player.block.break", array($this, "handle"));
$this->server->event("player.block.place", array($this, "handle"));
$this->server->event("player.block.update", array($this, "handle"));*/
}
public function handle($data, $event){
switch($event){
case "player.block.place":
case "player.block.update":
$b = BlockAPI::get($data["block"], $data["meta"]);
console("[DEBUG] Player ".$data["entity"]->player->username." placed ".$b->getName()." (".$data["block"].":".$data["meta"].") at (".$data["x"].", ".$data["y"].", ".$data["z"].")", true, true, 2);
$this->setBlock($data["x"], $data["y"], $data["z"], $data["block"], $data["meta"]);
break;
case "player.block.break":
if($data["block"]->getID() === 0){
break;
}
$b = BlockAPI::get($block[0], $block[1]);
console("[DEBUG] Player ".$data["player"]->username." broke ".$data["block"]->getName()." (".$data["block"]->getID().":".$data["block"]->getMetadata().") at (".$data["block"]->x.", ".$data["block"]->y.", ".$data["block"]->z.")", true, true, 2);
$this->setBlock($data["block"]->x, $data["block"]->y, $data["block"]->z, 0, 0, true, true);
break;
}
}

View File

@ -54,6 +54,7 @@ class PlayerAPI{
$player->setHealth(min(20, $player->getHealth() + $data), "regeneration");
}
}
return true;
}
break;
case "player.death":
@ -103,6 +104,7 @@ class PlayerAPI{
}
}
$this->server->chat(false, $message);
return true;
break;
}
}
@ -195,7 +197,7 @@ class PlayerAPI{
}
public function get($name){
$CID = $this->server->query("SELECT ip,port FROM players WHERE name = '".str_replace("'", "", $name)."';", true);
$CID = $this->server->query("SELECT ip,port FROM players WHERE name = '".$name."';", true);
$CID = $this->server->clientID($CID["ip"], $CID["port"]);
if(isset($this->server->clients[$CID])){
return $this->server->clients[$CID];

View File

@ -41,6 +41,7 @@ class PluginAPI extends stdClass{
}
public function getInfo($className){
$className = strtolower($className);
if(!isset($this->plugins[$className])){
return false;
}
@ -49,6 +50,10 @@ class PluginAPI extends stdClass{
}
public function load($file){
if(strtolower(substr($file, -3)) === "pmf"){
$pmf = new PMFPlugin($file);
$info = $pmf->getPluginInfo();
}else{
$content = file_get_contents($file);
$info = strstr($content, "*/", true);
$content = substr(strstr($content, "*/"),2);
@ -73,24 +78,30 @@ class PluginAPI extends stdClass{
}
$info[$i] = $v;
}
$info["code"] = $content;
$info["class"] = trim(strtolower($info["class"]));
}
if(!isset($info["name"]) or !isset($info["version"]) or !isset($info["class"]) or !isset($info["author"])){
console("[ERROR] [PluginAPI] Failed parsing of ".basename($file));
return false;
}
console("[INFO] [PluginAPI] Loading plugin \"\x1b[32m".$info["name"]."\x1b[0m\" \x1b[35m".$info["version"]."\x1b[0m by \x1b[36m".$info["author"]."\x1b[0m");
console("[INFO] [PluginAPI] Loading plugin \"\x1b[32m".$info["name"]."\x1b[0m\" \x1b[35m".$info["version"]." #".intval($info["apiversion"])."\x1b[0m by \x1b[36m".$info["author"]."\x1b[0m");
if(class_exists($info["class"])){
console("[ERROR] [PluginAPI] Failed loading plugin: class exists");
return false;
}
if(eval($content) === false or !class_exists($info["class"])){
if(eval($info["code"]) === false or !class_exists($info["class"])){
console("[ERROR] [PluginAPI] Failed loading plugin: evaluation error");
return false;
}
$className = trim($info["class"]);
if(!isset($info["apiversion"]) or intval($info["apiversion"]) < CURRENT_API_VERSION){
console("[ERROR] [PluginAPI] Plugin \"".$info["name"]."\" uses an outdated API! It can crash or corrupt the server!");
$className = $info["class"];
if(isset($info["apiversion"]) and intval($info["apiversion"]) > CURRENT_API_VERSION){
console("[ERROR] [PluginAPI] Plugin \"".$info["name"]."\" uses a newer API! It can crash or corrupt the server!");
}elseif(!isset($info["apiversion"]) or intval($info["apiversion"]) < CURRENT_API_VERSION){
console("[NOTICE] [PluginAPI] Plugin \"".$info["name"]."\" uses an old API");
}
if(isset($info["api"]) and $info["api"] !== true){
console("[INFO] [PluginAPI] Plugin \"\x1b[36m".$info["name"]."\x1b[0m\" got raw access to Server methods");
}
$object = new $className($this->server->api, ((isset($info["api"]) and $info["api"] !== true) ? $this->server:false));
$object = new $className($this->server->api, false);
if(!($object instanceof Plugin)){
console("[ERROR] [PluginAPI] Plugin \"\x1b[36m".$info["name"]."\x1b[0m\" doesn't use the Plugin Interface");
if(method_exists($object, "__destruct")){
@ -166,7 +177,8 @@ class PluginAPI extends stdClass{
$dir = dir(DATA_PATH."plugins/");
while(false !== ($file = $dir->read())){
if($file{0} !== "."){
if(strtolower(substr($file, -3)) === "php"){
$ext = strtolower(substr($file, -3));
if($ext === "php" or $ext === "pmf"){
$this->load(DATA_PATH."plugins/" . $file);
}
}

View File

@ -94,7 +94,7 @@ class ServerAPI{
"memory-limit" => "256M",
"last-update" => false,
"white-list" => false,
"debug" => 2,
"debug" => 1,
"max-players" => 20,
"server-type" => "normal",
"time-per-second" => 20,

View File

@ -29,6 +29,8 @@ the Free Software Foundation, either version 3 of the License, or
class Deprecation{
public static $events = array(
"world.block.change" => "block.change",
"block.drop" => "item.drop",
"api.op.check" => "op.check",
);

View File

@ -29,26 +29,29 @@ the Free Software Foundation, either version 3 of the License, or
class Player{
private $server;
private $queue = array();
private $buffer = array();
private $buffer = "";
private $lastBuffer = 0;
private $recovery = array();
private $evid = array();
var $timeout;
var $connected = true;
var $clientID;
var $ip;
var $port;
var $counter = array(0, 0, 0);
var $username;
var $eid = false;
var $data = array();
var $entity = false;
var $auth = false;
var $CID;
var $MTU;
var $spawned = false;
var $inventory;
public $timeout;
public $connected = true;
public $clientID;
public $ip;
public $port;
public $counter = array(0, 0, 0);
public $username;
public $iusername;
public $eid = false;
public $data = array();
public $entity = false;
public $auth = false;
public $CID;
public $MTU;
public $spawned = false;
public $inventory;
public $equipment;
public $armor;
var $loggedIn = false;
public $loggedIn = false;
public $gamemode;
public $lastBreak;
public $windowCnt = 0;
@ -151,6 +154,10 @@ class Player{
if($time > $this->timeout){
$this->close("timeout");
}else{
if($this->lastBuffer <= $time and strlen($this->buffer) > 0){
$this->sendBuffer();
}
if(!empty($this->queue)){
$cnt = 0;
while($cnt < 4){
@ -160,7 +167,7 @@ class Player{
}
switch($p[0]){
case 0:
$this->dataPacket($p[1], $p[2], false, $p[3]);
$this->dataPacket($p[1]["id"], $p[1], false);
break;
case 1:
eval($p[1]);
@ -187,7 +194,7 @@ class Player{
foreach($this->evid as $ev){
$this->server->deleteEvent($ev);
}
$this->server->api->dhandle("player.quit", $this);
$this->server->api->handle("player.quit", $this);
$reason = $reason == "" ? "server stop":$reason;
$this->save();
$this->eventHandler(new Container("You have been kicked. Reason: ".$reason), "server.chat");
@ -421,32 +428,32 @@ class Player{
$this->timeout = microtime(true) + 20;
switch($pid){
case 0xa0: //NACK
if(isset($this->buffer[$data[2]])){
array_unshift($this->queue, array(0, $this->buffer[$data[2]][0], $this->buffer[$data[2]][1], $data[2]));
if(isset($this->recovery[$data[2]])){
$this->directDataPacket($this->recovery[$data[2]]["id"], $this->recovery[$data[2]]);
}
if(isset($data[3])){
if(isset($this->buffer[$data[3]])){
array_unshift($this->queue, array(0, $this->buffer[$data[3]][0], $this->buffer[$data[3]][1], $data[3]));
if(isset($this->recovery[$data[3]])){
$this->directDataPacket($this->recovery[$data[3]]["id"], $this->recovery[$data[3]]);
}
}
break;
case 0xc0: //ACK
$diff = $data[2] - $this->counter[2];
if($diff > 8){ //Packet recovery
array_unshift($this->queue, array(0, $this->buffer[$data[2]][0], $this->buffer[$data[2]][1], $data[2]));
$this->directDataPacket($this->recovery[$data[2]]["id"], $this->recovery[$data[2]]);
}
$this->counter[2] = $data[2];
$this->buffer[$data[2]] = null;
unset($this->buffer[$data[2]]);
$this->recovery[$data[2]] = null;
unset($this->recovery[$data[2]]);
if(isset($data[3])){
$diff = $data[3] - $this->counter[2];
if($diff > 8){ //Packet recovery
array_unshift($this->queue, array(0, $this->buffer[$data[3]][0], $this->buffer[$data[3]][1], $data[3]));
$this->directDataPacket($this->recovery[$data[3]]["id"], $this->recovery[$data[3]]);
}
$this->counter[2] = $data[3];
$this->buffer[$data[3]] = null;
unset($this->buffer[$data[3]]);
$this->recovery[$data[3]] = null;
unset($this->recovery[$data[3]]);
}
break;
case 0x07:
@ -528,30 +535,30 @@ class Player{
break;
}
$this->loggedIn = true;
$this->username = str_replace(array("\x00", "/", " ", "\r", "\n", '"', "'"), array("", "-", "_", "", "", "", ""), $data["username"]);
if($this->username == ""){
if(preg_match('#^[a-zA-Z0-9_]{2,16}$#', $data["username"])){
$this->username = $data["username"];
$this->iusername = strtolower($this->username);
}else{
$this->close("bad username", false);
break;
}
$o = $this->server->api->player->getOffline($this->username);
if($this->server->whitelist === true and !$this->server->api->ban->inWhitelist($this->username)){
if($this->server->whitelist === true and !$this->server->api->ban->inWhitelist($this->iusername)){
$this->close("\"\x1b[33m".$this->username."\x1b[0m\" not being on white-list", false);
break;
}elseif($this->server->api->ban->isBanned($this->username) or $this->server->api->ban->isIPBanned($this->ip)){
}elseif($this->server->api->ban->isBanned($this->iusername) or $this->server->api->ban->isIPBanned($this->ip)){
$this->close("\"\x1b[33m".$this->username."\x1b[0m\" is banned!", false);
}
$u = $this->server->api->player->get($this->username);
$c = $this->server->api->player->getByClientID($this->clientID);
$u = $this->server->api->player->get($this->iusername);
if($u !== false){
$u->close("logged in from another location");
}
if($c !== false){
$c->close("logged in from another location");
}
if($this->server->api->dhandle("player.join", $this) === false){
if($this->server->api->handle("player.join", $this) === false){
$this->close();
return;
}
$this->server->api->player->add($this->CID);
$this->auth = true;
if(!isset($this->data["inventory"]) or $this->gamemode === CREATIVE){
@ -616,17 +623,45 @@ class Player{
if($this->MTU <= 548){
$this->eventHandler("Your connection is bad, you may experience lag and slow map loading.", "server.chat");
}
if($this->iusername === "steve" or $this->iusername === "stevie"){
$this->eventHandler("You're using the default username. Please change it on the Minecraft PE settings.", "server.chat");
}
$this->sendInventory();
$this->entity->setPosition($this->entity->x, $this->entity->y, $this->entity->z, 0, 0);
/*
0x01 world_inmutable
0x02 ?
0x04 ?
0x08 ?
0x10 ?
0x20 nametags_visible
0x40 ?
0x80 ?
0x00000001 world_inmutable
0x00000002 ?
0x00000004 ?
0x00000008 ?
0x00000010 ?
0x00000020 nametags_visible
0x00000040 ?
0x00000080 ?
0x00000100 ?
0x00000200 ?
0x00000400 ?
0x00000800 ?
0x00001000 ?
0x00002000 ?
0x00004000 ?
0x00008000 ?
0x00010000 ?
0x00020000 ?
0x00040000 ?
0x00080000 ?
0x00100000 ?
0x00200000 ?
0x00400000 ?
0x00800000 ?
0x01000000 ?
0x02000000 ?
0x04000000 ?
0x08000000 ?
0x10000000 ?
0x20000000 ?
0x40000000 ?
0x80000000 ?
*/
$flags = 0;
if($this->gamemode === ADVENTURE){
@ -656,8 +691,10 @@ class Player{
break;
}
$data["eid"] = $this->eid;
$data["player"] = $this;
$data["item"] = BlockAPI::getItem($data["block"], $data["meta"]);
if($this->server->handle("player.equipment.change", $data) !== false){
$this->equipment = BlockAPI::getItem($data["block"], $data["meta"]);
$this->equipment = $data["item"];
console("[DEBUG] Player ".$this->username." has now ".$this->equipment->getName()." (".$this->equipment->getID().":".$this->equipment->getMetadata().") in their hands!", true, true, 2);
}
break;
@ -769,8 +806,11 @@ class Player{
if($this->loggedIn === false){
break;
}
$item = BlockAPI::getItem($data["block"], $data["meta"], $data["stack"]);
$data["item"] = $item;
if($this->server->handle("player.drop", $data) !== false){
$this->server->api->block->drop(new Vector3($this->entity->x, $this->entity->y, $this->entity->z), BlockAPI::getItem($data["block"], $data["meta"], $data["stack"]));
$this->removeItem($item->getID(), $item->getMetadata(), $item->count);
$this->server->api->block->drop(new Vector3($this->entity->x - 0.5, $this->entity->y, $this->entity->z - 0.5), $item);
}
break;
case MC_SIGN_UPDATE:
@ -817,32 +857,50 @@ class Player{
}
$tile = $this->windows[$data["windowid"]];
$done = false;
$item = BlockAPI::getItem($data["block"], $data["meta"], $data["stack"]);
$s = array(
"Count" => $item->count,
"Slot" => $data["slot"],
"id" => $item->getID(),
"Damage" => $item->getMetadata(),
);
foreach($tile->data["Items"] as $i => $slot){
if($slot["Slot"] === $data["slot"]){
$done = true;
$s = $tile->data["Items"][$i] = array(
"Count" => $data["stack"] & 0xFFFF,
"Slot" => $data["slot"],
"id" => $data["block"] & 0xFFFF,
"Damage" => $data["meta"] & 0xFFFF
);
if($item->getID() !== AIR and $slot["id"] == $item->getID()){
if($slot["Count"] < $item->count){
$this->removeItem($item->getID(), $item->getMetadata(), $item->count - $slot["Count"]);
}elseif($slot["Count"] > $item->count){
$this->addItem($item->getID(), $item->getMetadata(), $slot["Count"] - $item->count);
}
$tile->data["Items"][$i] = $s;
}else{
$this->removeItem($item->getID(), $item->getMetadata(), $item->count);
$this->addItem($slot["id"], $slot["Damage"], $slot["Count"]);
if($item->getID() === AIR or $item->count <= 0){
unset($tile->data["Items"][$i]);
}
}
break;
}
}
if($done === false){
$tile->data["Items"][] = $s = array(
"Count" => $data["stack"] & 0xFFFF,
"Slot" => $data["slot"],
"id" => $data["block"] & 0xFFFF,
"Damage" => $data["meta"] & 0xFFFF
);
if($item->getID() !== AIR and $item->count > 0){
$this->removeItem($item->getID(), $item->getMetadata(), $item->count);
$tile->data["Items"][] = $s;
}
}
$this->server->api->dhandle("tile.container.slot", array(
"tile" => $tile,
"slot" => $data["slot"],
"slotdata" => $s,
"player" => $this,
));
$this->server->handle("tile.update", $tile);
break;
case MC_SEND_INVENTORY: //TODO, Mojang, enable this <20>^_^`
break;
@ -904,25 +962,52 @@ class Player{
$this->queue[] = array(1, $code);
}
public function dataPacket($id, $data = array(), $queue = false, $count = false){
if($queue === true){
$this->queue[] = array(0, $id, $data, $count);
}else{
if($count === false){
public function sendBuffer(){
if(strlen($this->buffer) > 0){
$count = $this->counter[0];
++$this->counter[0];
if(count($this->buffer) >= 512){
array_shift($this->buffer);
if(count($this->recovery) >= 512){
array_shift($this->recovery);
}
$this->buffer[$count] = array($id, $data);
$this->recovery[$count] = array("id" => false, "raw" => $this->buffer);
$this->send(0x80, array(
$count,
0x00,
$this->recovery[$count],
));
}
$this->buffer = "";
$this->lastBuffer = microtime(true) + 0.05;
}
public function directDataPacket($id, $data){
$data["id"] = $id;
$count = $this->counter[0];
++$this->counter[0];
$this->send(0x80, array(
$count,
0x00,
$data,
));
}
public function dataPacket($id, $data = array(), $queue = false){
$data["id"] = $id;
if($queue === true){
$this->queue[] = array(0, $data);
}else{
$data = new CustomPacketHandler($id, "", $data, true);
$len = strlen($data->raw) + 1;
$MTU = $this->MTU - 7;
if((strlen($this->buffer) + $len) >= $MTU){
$this->sendBuffer();
}
$this->buffer .= ($this->buffer === "" ? "":"\x00").Utils::writeShort($len << 3) . chr($id) . $data->raw;
}
}
function __toString(){

View File

@ -98,7 +98,16 @@ class PocketMinecraftServer{
return round($tps, 4);
}
public function titleTick(){
if(ENABLE_ANSI === true){
echo "\x1b]0;PocketMine-MP ".MAJOR_VERSION." | Online ". count($this->clients)." | RAM ".round((memory_get_usage(true) / 1024) / 1024, 2)."MB | TPS ".$this->getTPS()."\x07";
}
}
public function loadEvents(){
if(ENABLE_ANSI === true){
$this->action(1500000, '$this->titleTick();');
}
$this->action(500000, '$this->time += (int) ($this->timePerSecond / 2);$this->api->dhandle("server.time", $this->time);');
$this->action(5000000, 'if($this->difficulty < 2){$this->api->dhandle("server.regeneration", 1);}');
$this->action(1000000 * 60, '$this->reloadConfig();');
@ -106,7 +115,6 @@ class PocketMinecraftServer{
if($this->api instanceof ServerAPI){
$this->action(1000000 * 80, '$cnt = count($this->clients); if($cnt > 1){$this->api->chat->broadcast("Online (".$cnt."): ".implode(", ",$this->api->player->online()));}');
}
$this->action(1000000 * 120, '$this->debugInfo(true);');
}
public function startDatabase(){
@ -115,7 +123,7 @@ class PocketMinecraftServer{
//$this->query("PRAGMA journal_mode = OFF;");
//$this->query("PRAGMA encoding = \"UTF-8\";");
//$this->query("PRAGMA secure_delete = OFF;");
$this->query("CREATE TABLE players (clientID INTEGER PRIMARY KEY, EID NUMERIC, ip TEXT, port NUMERIC, name TEXT UNIQUE);");
$this->query("CREATE TABLE players (clientID INTEGER PRIMARY KEY, EID NUMERIC, ip TEXT, port NUMERIC, name TEXT UNIQUE COLLATE NOCASE);");
$this->query("CREATE TABLE entities (EID INTEGER PRIMARY KEY, type NUMERIC, class NUMERIC, name TEXT, x NUMERIC, y NUMERIC, z NUMERIC, yaw NUMERIC, pitch NUMERIC, health NUMERIC);");
$this->query("CREATE TABLE tileentities (ID INTEGER PRIMARY KEY, class TEXT, x NUMERIC, y NUMERIC, z NUMERIC, spawnable NUMERIC);");
$this->query("CREATE TABLE actions (ID INTEGER PRIMARY KEY, interval NUMERIC, last NUMERIC, code TEXT, repeat NUMERIC);");
@ -193,7 +201,7 @@ class PocketMinecraftServer{
}
public function addHandler($event, $callable, $priority = 5){
public function addHandler($event,callable $callable, $priority = 5){
if(!is_callable($callable)){
return false;
}elseif(isset(Deprecation::$events[$event])){
@ -216,7 +224,7 @@ class PocketMinecraftServer{
$this->preparedSQL->selectHandlers->clear();
$this->preparedSQL->selectHandlers->bindValue(":name", $event, SQLITE3_TEXT);
$handlers = $this->preparedSQL->selectHandlers->execute();
$result = true;
$result = null;
if($handlers !== false and $handlers !== true){
console("[INTERNAL] Handling ".$event, true, true, 3);
$call = array();
@ -225,7 +233,7 @@ class PocketMinecraftServer{
}
$handlers->finalize();
foreach($call as $hnid => $boolean){
if($result !== false){
if($result !== false and $result !== true){
$called[$hnid] = true;
$handler = $this->handlers[$hnid];
if(is_array($handler)){
@ -349,7 +357,7 @@ class PocketMinecraftServer{
}
$t = $this->api->tileentity->add($tile["id"], $tile["x"], $tile["y"], $tile["z"], $tile);
}
$this->action(1000000 * 60 * 15, '$this->api->chat->broadcast("Forcing save...");$this->save();');
$this->action(1000000 * 60 * 25, '$this->api->chat->broadcast("Forcing save...");$this->save();');
}
}
@ -539,7 +547,9 @@ class PocketMinecraftServer{
$this->custom["times_".$CID] = 0;
}
$ln = 15;
if($this->description == "" or substr($this->description, -1) != " "){
$this->description .= " ";
}
$txt = substr($this->description, $this->custom["times_".$CID], $ln);
$txt .= substr($this->description, 0, $ln - strlen($txt));
$this->send(0x1c, array(
@ -654,7 +664,7 @@ class PocketMinecraftServer{
}
}
public function schedule($ticks, $callback, $data = array(), $repeat = false, $eventName = "server.schedule"){
public function schedule($ticks,callable $callback, $data = array(), $repeat = false, $eventName = "server.schedule"){
if(!is_callable($callback)){
return false;
}
@ -696,7 +706,7 @@ class PocketMinecraftServer{
$this->preparedSQL->updateActions->execute();
}
public function event($event, $func){
public function event($event,callable $func){
if(!is_callable($func)){
return false;
}elseif(isset(Deprecation::$events[$event])){

View File

@ -43,9 +43,9 @@ ini_set("memory_limit", "256M"); //Default
define("LOG", true);
define("MAGIC", "\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78");
define("TEST_MD5", "ffe889db5932db1e3371d48773590e59");
define("MAJOR_VERSION", "Alpha_1.2");
define("MAJOR_VERSION", "Alpha_1.2.1");
define("CURRENT_STRUCTURE", 5);
define("CURRENT_PROTOCOL", 9);
define("CURRENT_MINECRAFT_VERSION", "v0.6.1 alpha");
define("CURRENT_API_VERSION", 3);
define("CURRENT_API_VERSION", 4);
define("CURRENT_PHP_VERSION", "5.4.12");

View File

@ -25,6 +25,11 @@ the Free Software Foundation, either version 3 of the License, or
*/
/***REM_START***/
require_once("BurningFurnace.php");
/***REM_END***/
class FurnaceBlock extends BurningFurnaceBlock{
public function __construct($meta = 0){
parent::__construct($meta);

View File

@ -27,7 +27,7 @@ the Free Software Foundation, either version 3 of the License, or
class QuartzBlock extends SolidBlock{
public function __construct($meta = 0){
parent::__construct(QUARTZ, $meta, "Quartz Block");
parent::__construct(QUARTZ_BLOCK, $meta, "Quartz Block");
$names = array(
0 => "Quartz Block",
1 => "Chiseled Quartz Block",

View File

@ -86,9 +86,6 @@ class Vector3{
if(($x instanceof Vector3) === true){
return $this->add($x->x, $x->y, $x->z);
}else{
$this->x += $x;
$this->y += $y;
$this->z += $z;
return new Vector3($this->x + $x, $this->y + $y, $this->z + $z);
}
}

View File

@ -26,7 +26,11 @@ the Free Software Foundation, either version 3 of the License, or
*/
class CustomPacketHandler{
var $offset, $raw, $c, $data, $name = "";
public $offset;
public $raw;
public $c;
public $data;
public $name = "";
private function get($len = true, $check = true){
if($len === true){

View File

@ -69,24 +69,27 @@ class MinecraftInterface{
if($this->socket->connected === false){
return false;
}
$data = $this->socket->read();
if($data[3] === false){
$buf = "";
$source = false;
$port = 1;
$len = $this->socket->read($buf, $source, $port);
if($len === false){
return false;
}
$pid = ord($data[0]);
$pid = ord($buf{0});
$struct = $this->getStruct($pid);
if($struct === false){
console("[ERROR] Unknown Packet ID 0x".Utils::strToHex(chr($pid)), true, true, 0);
$p = "[".(microtime(true) - $this->start)."] [".((($origin === "client" and $this->client === true) or ($origin === "server" and $this->client === false)) ? "CLIENT->SERVER":"SERVER->CLIENT")." ".$ip.":".$port."]: Error, bad packet id 0x".Utils::strTohex(chr($pid))." [length ".strlen($raw)."]".PHP_EOL;
$p .= Utils::hexdump($data[0]);
$p = "[".(microtime(true) - $this->start)."] [".((($origin === "client" and $this->client === true) or ($origin === "server" and $this->client === false)) ? "CLIENT->SERVER":"SERVER->CLIENT")." ".$ip.":".$port."]: Error, bad packet id 0x".Utils::strToHex(chr($pid))." [length ".strlen($buf)."]".PHP_EOL;
$p .= Utils::hexdump($buf);
$p .= PHP_EOL;
logg($p, "packets", true, 2);
return false;
}
$packet = new Packet($pid, $struct, $data[0]);
$packet = new Packet($pid, $struct, $buf);
@$packet->parse();
$this->data[] = array($pid, $packet->data, $data[0], $data[1], $data[2]);
$this->data[] = array($pid, $packet->data, $buf, $source, $port);
return $this->popPacket();
}

View File

@ -80,10 +80,15 @@ class Packet{
$this->addRaw($reply->raw);
break;
case 0x00:
$reply = new CustomPacketHandler($this->data[$field]["id"], "", $this->data[$field], true);
$this->addRaw(Utils::writeShort((strlen($reply->raw) + 1) << 3));
if($this->data[$field]["id"] !== false){
$raw = new CustomPacketHandler($this->data[$field]["id"], "", $this->data[$field], true);
$raw = $raw->raw;
$this->addRaw(Utils::writeShort((strlen($raw) + 1) << 3));
$this->addRaw(chr($this->data[$field]["id"]));
$this->addRaw($reply->raw);
$this->addRaw($raw);
}else{
$this->addRaw($this->data[$field]["raw"]);
}
break;
}
break;

View File

@ -76,14 +76,18 @@ class UDPSocket{
socket_set_nonblock($this->sock);
}
public function read(){
$source = false;
$port = 1;
$len = @socket_recvfrom($this->sock, $buf, 65536, 0, $source, $port);
return array($buf, $source, $port, $len);
public function read(&$buf, &$source, &$port){
if($this->connected === false){
return false;
}
$len = @socket_recvfrom($this->sock, $buf, 65535, 0, $source, $port);
return $len;
}
public function write($data, $dest = false, $port = false){
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));
}

130
src/pmf/PMF.php Normal file
View File

@ -0,0 +1,130 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
define("PMF_CURRENT_VERSION", 0x01);
class PMF{
protected $fp;
private $file;
private $version;
private $type;
public function __construct($file, $new = false, $type = 0, $version = PMF_CURRENT_VERSION){
if($new === true){
$this->create($file, $type, $version);
}else{
if($this->load($file) !== true){
$this->parseInfo();
}
}
}
public function getVersion(){
return $this->version;
}
public function getType(){
return $this->type;
}
public function load($file){
$this->close();
$this->file = realpath($file);
if(($this->fp = @fopen($file, "c+b")) !== false){
$stat = fstat($this->fp);
if($stat["size"] >= 5){ //Header + 2 Bytes
return true;
}
$this->close();
}
return false;
}
public function parseInfo(){
$this->seek(0);
if(fread($this->fp, 3) !== "PMF"){
return false;
}
$this->version = ord($this->read(1));
switch($this->version){
case 0x01:
$this->type = ord($this->read(1));
break;
default:
console("[ERROR] Tried loading non-supported PMF version ".$this->version." on file ".$this->file);
return false;
}
return true;
}
public function getFile(){
return $this->file;
}
public function close(){
unset($this->version, $this->type, $this->file);
if(is_object($this->fp)){
fclose($this->fp);
}
}
public function create($file, $type, $version = PMF_CURRENT_VERSION){
$this->file = realpath($file);
if(!is_resource($this->fp)){
if(($this->fp = @fopen($file, "c+b")) === false){
return false;
}
}
$this->seek(0);
$this->write("PMF" . chr((int) $version) . chr((int) $type));
}
public function read($length){
if($length <= 0){
return "";
}
if(is_resource($this->fp)){
return fread($this->fp, (int) $length);
}
return false;
}
public function write($string, $length = false){
if(is_resource($this->fp)){
return ($length === false ? fwrite($this->fp, $string) : fwrite($this->fp, $string, $length));
}
return false;
}
public function seek($offset, $whence = SEEK_SET){
if(is_resource($this->fp)){
return fseek($this->fp, (int) $offset, (int) $whence);
}
return false;
}
}

66
src/pmf/Plugin.php Normal file
View File

@ -0,0 +1,66 @@
<?php
/*
-
/ \
/ \
/ PocketMine \
/ MP \
|\ @shoghicp /|
|. \ / .|
| .. \ / .. |
| .. | .. |
| .. | .. |
\ | /
\ | /
\ | /
\ | /
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
/***REM_START***/
require_once(FILE_PATH."/src/pmf/PMF.php");
/***REM_END***/
define("PMF_CURRENT_PLUGIN_VERSION", 0x00);
class PMFPlugin extends PMF{
private $pluginData = array();
public function __construct($file){
$this->load($file);
$this->parseInfo();
$this->parsePlugin();
}
public function getPluginInfo(){
return $this->pluginData;
}
protected function parsePlugin(){
if($this->getType() !== 0x01){
return false;
}
$this->pluginData["fversion"] = ord($this->read(1));
$this->pluginData["name"] = $this->read(Utils::readShort($this->read(2), false));
$this->pluginData["version"] = $this->read(Utils::readShort($this->read(2), false));
$this->pluginData["author"] = $this->read(Utils::readShort($this->read(2), false));
$this->pluginData["apiversion"] = Utils::readShort($this->read(2), false);
$this->pluginData["class"] = $this->read(Utils::readShort($this->read(2), false));
$this->pluginData["identifier"] = $this->read(Utils::readShort($this->read(2), false)); //Will be used to check for updates
$this->pluginData["extra"] = gzinflate($this->read(Utils::readShort($this->read(2), false))); //Additional custom plugin data
$this->pluginData["code"] = "";
while(!feof($this->fp)){
$this->pluginData["code"] .= $this->read(4096);
}
$this->pluginData["code"] = gzinflate($this->pluginData["code"]);
}
}

View File

@ -1,32 +1,7 @@
<?php
/**
The MIT License
Copyright (c) 2011 Vladimir Andersen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
* Spyc -- A Simple PHP YAML Class
* @version 0.5
* @version 0.5.1
* @author Vlad Andersen <vlad.andersen@gmail.com>
* @author Chris Wanstrath <chris@ozmm.org>
* @link http://code.google.com/p/spyc/
@ -35,28 +10,6 @@ THE SOFTWARE.
* @package Spyc
*/
if (!function_exists('spyc_load')) {
/**
* Parses YAML to array.
* @param string $string YAML string.
* @return array
*/
function spyc_load ($string) {
return Spyc::YAMLLoadString($string);
}
}
if (!function_exists('spyc_load_file')) {
/**
* Parses YAML to array.
* @param string $file Path to YAML file.
* @return array
*/
function spyc_load_file ($file) {
return Spyc::YAMLLoad($file);
}
}
/**
* The Simple PHP YAML Class.
*
@ -458,18 +411,16 @@ class Spyc {
$i--;
}
// Strip out comments
if (strpos ($line, '#')) {
$line = preg_replace('/\s*#([^"\']+)$/','',$line);
}
while (++$i < $cnt && self::greedilyNeedNextLine($line)) {
$line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t");
}
$i--;
if (strpos ($line, '#')) {
if (strpos ($line, '"') === false && strpos ($line, "'") === false)
$line = preg_replace('/\s+#(.+)$/','',$line);
}
$lineArray = $this->_parseLine($line);
if ($literalBlockStyle)
@ -679,6 +630,7 @@ class Spyc {
} while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false);
$explode = explode(',',$inline);
$explode = array_map('trim', $explode);
$stringi = 0; $i = 0;
while (1) {

View File

@ -326,12 +326,6 @@ class Entity extends stdClass{
}elseif($y > $this->fallY){
$this->fallY = $y;
}
if($this->fallY !== false and ($this->fallStart + 8) < microtime(true)){ //Flying
$this->harm(1, "flying");
if($y > $this->fallY){
$this->fallY = $y;
}
}
}elseif($this->fallY !== false){ //Fall damage!
if($y < $this->fallY){
$d = $this->server->api->block->getBlock(new Vector3($x, $y + 1, $z));

View File

@ -308,7 +308,7 @@ class WorldGenerator{
$chunk = str_pad($this->getChunk($X, $Z), 86012, "\x00", STR_PAD_RIGHT);
$this->raw .= Utils::writeLInt(strlen($chunk)) . $chunk;
}
console("[DEBUG] Generating level ".ceil(($Z + 1)/0.16)."%", true, true, 2);
console("[NOTICE] Generating level ".ceil(($Z + 1)/0.16)."%");
}
return true;
}