Added Logger interface, threaded MainLogger and updated PluginLogger

This commit is contained in:
Shoghi Cervantes 2014-05-28 23:46:56 +02:00
parent 9df56295f6
commit 7bd6f2ed91
22 changed files with 624 additions and 178 deletions

View File

@ -82,6 +82,7 @@ use pocketmine\tile\Sign;
use pocketmine\tile\Spawnable; use pocketmine\tile\Spawnable;
use pocketmine\tile\Tile; use pocketmine\tile\Tile;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\MainLogger;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
/** /**
@ -392,7 +393,8 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$this->buffer->data = []; $this->buffer->data = [];
$this->tasks[] = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "handlePacketQueues")), 1); $this->tasks[] = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "handlePacketQueues")), 1);
$this->tasks[] = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "clearQueue")), 20 * 60); $this->tasks[] = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "clearQueue")), 20 * 60);
console("[DEBUG] New Session started with " . $ip . ":" . $port . ". MTU " . $this->MTU . ", Client ID " . $this->clientID, true, true, 2);
$this->server->getLogger()->debug("New Session started with " . $ip . ":" . $port . ". MTU " . $this->MTU . ", Client ID " . $this->clientID);
} }
/** /**
@ -1448,7 +1450,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$this->lastMeasure = microtime(true); $this->lastMeasure = microtime(true);
$this->tasks[] = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "measureLag")), 50); $this->tasks[] = $this->server->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "measureLag")), 50);
console("[INFO] " . TextFormat::AQUA . $this->username . TextFormat::RESET . "[/" . $this->ip . ":" . $this->port . "] logged in with entity id " . $this->id . " at (" . $this->getLevel()->getName() . ", " . round($this->x, 4) . ", " . round($this->y, 4) . ", " . round($this->z, 4) . ")"); $this->server->getLogger()->info(TextFormat::AQUA . $this->username . TextFormat::WHITE . "[/" . $this->ip . ":" . $this->port . "] logged in with entity id " . $this->id . " at (" . $this->getLevel()->getName() . ", " . round($this->x, 4) . ", " . round($this->y, 4) . ", " . round($this->z, 4) . ")");
$this->server->getPluginManager()->callEvent(new PlayerJoinEvent($this, $this->username . " joined the game")); $this->server->getPluginManager()->callEvent(new PlayerJoinEvent($this, $this->username . " joined the game"));
@ -1517,7 +1519,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
$this->teleport($this->lastCorrect, $this->entity->yaw, $this->entity->pitch, false); $this->teleport($this->lastCorrect, $this->entity->yaw, $this->entity->pitch, false);
} }
if($this->blocked !== true){ if($this->blocked !== true){
console("[WARNING] ".$this->username." moved too quickly!"); $this->server->getLogger()->warning($this->username." moved too quickly!");
} }
}else{*/ }else{*/
$this->setPositionAndRotation($newPos, $packet->yaw, $packet->pitch); $this->setPositionAndRotation($newPos, $packet->yaw, $packet->pitch);
@ -2163,7 +2165,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
} }
break; break;
default: default:
console("[DEBUG] Unhandled " . $packet->pid() . " data packet for " . $this->username . " (" . $this->clientID . "): " . print_r($packet, true), true, true, 2); $this->server->getLogger()->debug("Unhandled " . $packet->pid() . " data packet for " . $this->username . " (" . $this->clientID . "): " . print_r($packet, true));
break; break;
} }
} }
@ -2257,7 +2259,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
} }
$this->server->getPluginManager()->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_USERS, $this); $this->server->getPluginManager()->unsubscribeFromPermission(Server::BROADCAST_CHANNEL_USERS, $this);
$this->spawned = false; $this->spawned = false;
console("[INFO] " . TextFormat::AQUA . $this->username . TextFormat::RESET . "[/" . $this->ip . ":" . $this->port . "] logged out due to " . $reason); $this->server->getLogger()->info(TextFormat::AQUA . $this->username . TextFormat::WHITE . "[/" . $this->ip . ":" . $this->port . "] logged out due to " . $reason);
$this->windows = new \SplObjectStorage(); $this->windows = new \SplObjectStorage();
$this->windowIndex = []; $this->windowIndex = [];
$this->chunksLoaded = []; $this->chunksLoaded = [];

View File

@ -20,18 +20,6 @@
*/ */
namespace { namespace {
/**
* Output text to the console, can contain Minecraft-formatted text.
*
* @param string $message
* @param bool $EOL
* @param bool $log
* @param int $level
*/
function console($message, $EOL = true, $log = true, $level = 1){
pocketmine\console($message, $EOL, $log, $level);
}
function safe_var_dump(){ function safe_var_dump(){
static $cnt = 0; static $cnt = 0;
foreach(func_get_args() as $var){ foreach(func_get_args() as $var){
@ -78,6 +66,8 @@ namespace {
namespace pocketmine { namespace pocketmine {
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\LogLevel;
use pocketmine\utils\MainLogger;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
use pocketmine\wizard\Installer; use pocketmine\wizard\Installer;
@ -154,11 +144,9 @@ namespace pocketmine {
define("pocketmine\\DATA", isset($opts["data"]) ? realpath($opts["data"]) . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR); define("pocketmine\\DATA", isset($opts["data"]) ? realpath($opts["data"]) . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR);
define("pocketmine\\PLUGIN_PATH", isset($opts["plugins"]) ? realpath($opts["plugins"]) . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR); define("pocketmine\\PLUGIN_PATH", isset($opts["plugins"]) ? realpath($opts["plugins"]) . DIRECTORY_SEPARATOR : \getcwd() . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR);
if((strpos(strtoupper(php_uname("s")), "WIN") === false or isset($opts["enable-ansi"])) and !isset($opts["disable-ansi"])){ define("pocketmine\\ANSI", ((strpos(strtoupper(php_uname("s")), "WIN") === false or isset($opts["enable-ansi"])) and !isset($opts["disable-ansi"])));
define("pocketmine\\ANSI", true);
}else{ $logger = new MainLogger(\pocketmine\PATH . "server.log", \pocketmine\ANSI);
define("pocketmine\\ANSI", false);
}
function kill($pid){ function kill($pid){
switch(Utils::getOS()){ switch(Utils::getOS()){
@ -172,57 +160,6 @@ namespace pocketmine {
} }
} }
/**
* Output text to the console, can contain Minecraft-formatted text.
*
* @param $message
* @param bool $EOL
* @param bool $log
* @param int $level
*/
function console($message, $EOL = true, $log = true, $level = 1){
if(!defined("pocketmine\\DEBUG") or \pocketmine\DEBUG >= $level){
$message .= $EOL === true ? PHP_EOL : "";
if($message{0} !== "["){
$message = "[INFO] $message";
}
$time = (\pocketmine\ANSI === true ? TextFormat::AQUA . date("H:i:s") . TextFormat::RESET : date("H:i:s")) . " ";
$replaced = TextFormat::clean(preg_replace('/\x1b\[[0-9;]*m/', "", $time . $message));
if($log === true and (!defined("LOG") or LOG === true)){
log(date("Y-m-d") . " " . $replaced, "server", false, $level);
}
if(\pocketmine\ANSI === true){
$add = "";
if(preg_match("/^\\[([a-zA-Z0-9]*)\\]/", $message, $matches) > 0){
switch($matches[1]){
case "ERROR":
case "SEVERE":
$add .= TextFormat::RED;
break;
case "TRACE":
case "INTERNAL":
case "DEBUG":
$add .= TextFormat::GRAY;
break;
case "WARNING":
$add .= TextFormat::YELLOW;
break;
case "NOTICE":
$add .= TextFormat::AQUA;
break;
default:
$add = "";
break;
}
}
$message = TextFormat::toANSI($time . $add . $message . TextFormat::RESET);
}else{
$message = $replaced;
}
echo $message;
}
}
function getTrace($start = 1){ function getTrace($start = 1){
$e = new \Exception(); $e = new \Exception();
$trace = $e->getTrace(); $trace = $e->getTrace();
@ -262,11 +199,12 @@ namespace pocketmine {
E_DEPRECATED => "E_DEPRECATED", E_DEPRECATED => "E_DEPRECATED",
E_USER_DEPRECATED => "E_USER_DEPRECATED", E_USER_DEPRECATED => "E_USER_DEPRECATED",
); );
$type = ($errno === E_ERROR or $errno === E_WARNING or $errno === E_USER_ERROR or $errno === E_USER_WARNING) ? "ERROR" : "NOTICE"; $type = ($errno === E_ERROR or $errno === E_WARNING or $errno === E_USER_ERROR or $errno === E_USER_WARNING) ? LogLevel::ERROR : LogLevel::NOTICE;
$errno = isset($errorConversion[$errno]) ? $errorConversion[$errno] : $errno; $errno = isset($errorConversion[$errno]) ? $errorConversion[$errno] : $errno;
console("[$type] A $errno error happened: \"$errstr\" in \"$errfile\" at line $errline", true, true, 0); $logger = MainLogger::getLogger();
$logger->log($type, "A $errno error happened: \"$errstr\" in \"$errfile\" at line $errline");
foreach(getTrace() as $i => $line){ foreach(getTrace() as $i => $line){
console("[TRACE] $line"); $logger->debug($line);
} }
return true; return true;
@ -296,22 +234,22 @@ namespace pocketmine {
$errors = 0; $errors = 0;
if(version_compare("5.4.0", PHP_VERSION) > 0){ if(version_compare("5.4.0", PHP_VERSION) > 0){
console("[ERROR] Use PHP >= 5.4.0", true, true, 0); $logger->critical("Use PHP >= 5.4.0");
++$errors; ++$errors;
} }
if(php_sapi_name() !== "cli"){ if(php_sapi_name() !== "cli"){
console("[ERROR] You must run PocketMine-MP using the CLI.", true, true, 0); $logger->critical("You must run PocketMine-MP using the CLI.");
++$errors; ++$errors;
} }
if(!extension_loaded("sockets")){ if(!extension_loaded("sockets")){
console("[ERROR] Unable to find the Socket extension.", true, true, 0); $logger->critical("Unable to find the Socket extension.");
++$errors; ++$errors;
} }
if(!extension_loaded("pthreads")){ if(!extension_loaded("pthreads")){
console("[ERROR] Unable to find the pthreads extension.", true, true, 0); $logger->critical("Unable to find the pthreads extension.");
++$errors; ++$errors;
}else{ }else{
$pthreads_version = phpversion("pthreads"); $pthreads_version = phpversion("pthreads");
@ -319,52 +257,54 @@ namespace pocketmine {
$pthreads_version = "0.$pthreads_version"; $pthreads_version = "0.$pthreads_version";
} }
if(version_compare($pthreads_version, "2.0.4") < 0){ if(version_compare($pthreads_version, "2.0.4") < 0){
console("[ERROR] pthreads >= 2.0.4 is required, while you have $pthreads_version.", true, true, 0); $logger->critical("pthreads >= 2.0.4 is required, while you have $pthreads_version.");
++$errors; ++$errors;
} }
} }
if(!extension_loaded("uopz")){ if(!extension_loaded("uopz")){
//console("[NOTICE] Couldn't find the uopz extension. Some functions may be limited", true, true, 0); //$logger->notice("Couldn't find the uopz extension. Some functions may be limited");
} }
if(extension_loaded("pocketmine")){ if(extension_loaded("pocketmine")){
if(version_compare(phpversion("pocketmine"), "0.0.1") < 0){ if(version_compare(phpversion("pocketmine"), "0.0.1") < 0){
console("[ERROR] You have the native PocketMine extension, but your version is lower than 0.0.1.", true, true, 0); $logger->critical("You have the native PocketMine extension, but your version is lower than 0.0.1.");
++$errors; ++$errors;
}elseif(version_compare(phpversion("pocketmine"), "0.0.4") > 0){ }elseif(version_compare(phpversion("pocketmine"), "0.0.4") > 0){
console("[ERROR] You have the native PocketMine extension, but your version is higher than 0.0.4.", true, true, 0); $logger->critical("You have the native PocketMine extension, but your version is higher than 0.0.4.");
++$errors; ++$errors;
} }
} }
if(!extension_loaded("Weakref") and !extension_loaded("weakref")){ if(!extension_loaded("Weakref") and !extension_loaded("weakref")){
console("[ERROR] Unable to find the Weakref extension.", true, true, 0); $logger->critical("Unable to find the Weakref extension.");
++$errors; ++$errors;
} }
if(!extension_loaded("curl")){ if(!extension_loaded("curl")){
console("[ERROR] Unable to find the cURL extension.", true, true, 0); $logger->critical("Unable to find the cURL extension.");
++$errors; ++$errors;
} }
if(!extension_loaded("sqlite3")){ if(!extension_loaded("sqlite3")){
console("[ERROR] Unable to find the SQLite3 extension.", true, true, 0); $logger->critical("Unable to find the SQLite3 extension.");
++$errors; ++$errors;
} }
if(!extension_loaded("yaml")){ if(!extension_loaded("yaml")){
console("[ERROR] Unable to find the YAML extension.", true, true, 0); $logger->critical("Unable to find the YAML extension.");
++$errors; ++$errors;
} }
if(!extension_loaded("zlib")){ if(!extension_loaded("zlib")){
console("[ERROR] Unable to find the Zlib extension.", true, true, 0); $logger->critical("Unable to find the Zlib extension.");
++$errors; ++$errors;
} }
if($errors > 0){ if($errors > 0){
console("[ERROR] Please use the installer provided on the homepage, or recompile PHP again.", true, true, 0); $logger->critical("Please use the installer provided on the homepage, or recompile PHP again.");
$logger->shutdown();
$logger->join();
exit(1); //Exit with error exit(1); //Exit with error
} }
@ -383,11 +323,13 @@ namespace pocketmine {
} }
if(substr(__FILE__, 0, 7) !== "phar://"){ if(substr(__FILE__, 0, 7) !== "phar://"){
console("[WARNING] Non-packaged PocketMine-MP installation detected, do not use on production."); $logger->warning("Non-packaged PocketMine-MP installation detected, do not use on production.");
} }
$server = new Server($autoloader, \pocketmine\PATH, \pocketmine\DATA, \pocketmine\PLUGIN_PATH); $server = new Server($autoloader, $logger, \pocketmine\PATH, \pocketmine\DATA, \pocketmine\PLUGIN_PATH);
$server->start(); $server->start();
$logger->shutdown();
$logger->join();
kill(getmypid()); kill(getmypid());
exit(0); exit(0);

View File

@ -84,6 +84,7 @@ use pocketmine\tile\Sign;
use pocketmine\tile\Tile; use pocketmine\tile\Tile;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Config; use pocketmine\utils\Config;
use pocketmine\utils\Logger;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
use pocketmine\utils\VersionString; use pocketmine\utils\VersionString;
@ -122,6 +123,9 @@ class Server{
/** @var TickScheduler */ /** @var TickScheduler */
private $tickScheduler = null; private $tickScheduler = null;
/** @var \pocketmine\utils\Logger */
private $logger;
/** @var CommandReader */ /** @var CommandReader */
private $console = null; private $console = null;
@ -444,6 +448,13 @@ class Server{
return $this->autoloader; return $this->autoloader;
} }
/**
* @return Logger
*/
public function getLogger(){
return $this->logger;
}
/** /**
* @return EntityMetadataStore * @return EntityMetadataStore
*/ */
@ -602,7 +613,7 @@ class Server{
$nbt["SpawnX"] = (int) $data->get("spawn")["x"]; $nbt["SpawnX"] = (int) $data->get("spawn")["x"];
$nbt["SpawnY"] = (int) $data->get("spawn")["y"]; $nbt["SpawnY"] = (int) $data->get("spawn")["y"];
$nbt["SpawnZ"] = (int) $data->get("spawn")["z"]; $nbt["SpawnZ"] = (int) $data->get("spawn")["z"];
console("[NOTICE] Old Player data found for \"" . $name . "\", upgrading profile"); $this->logger->notice("Old Player data found for \"" . $name . "\", upgrading profile");
foreach($data->get("inventory") as $slot => $item){ foreach($data->get("inventory") as $slot => $item){
if(count($item) === 3){ if(count($item) === 3){
$nbt->Inventory[$slot + 9] = new Compound(false, array( $nbt->Inventory[$slot + 9] = new Compound(false, array(
@ -641,7 +652,7 @@ class Server{
} }
unlink($path . "$name.yml"); unlink($path . "$name.yml");
}else{ }else{
console("[NOTICE] Player data not found for \"" . $name . "\", creating new profile"); $this->logger->notice("Player data not found for \"" . $name . "\", creating new profile");
} }
$this->saveOfflinePlayerData($name, $nbt); $this->saveOfflinePlayerData($name, $nbt);
@ -809,13 +820,13 @@ class Server{
if($this->isLevelLoaded($name)){ if($this->isLevelLoaded($name)){
return true; return true;
}elseif(!$this->isLevelGenerated($name)){ }elseif(!$this->isLevelGenerated($name)){
console("[NOTICE] Level \"" . $name . "\" not found"); $this->logger->notice("Level \"" . $name . "\" not found");
return false; return false;
} }
$path = $this->getDataPath() . "worlds/" . $name . "/"; $path = $this->getDataPath() . "worlds/" . $name . "/";
console("[INFO] Preparing level \"" . $name . "\""); $this->logger->info("Preparing level \"" . $name . "\"");
$level = new LevelFormat($path . "level.pmf"); $level = new LevelFormat($path . "level.pmf");
if(!$level->isLoaded){ if(!$level->isLoaded){
console("[ERROR] Could not load level \"" . $name . "\""); console("[ERROR] Could not load level \"" . $name . "\"");
@ -1175,14 +1186,16 @@ class Server{
/** /**
* @param \SplClassLoader $autoloader * @param \SplClassLoader $autoloader
* @param Logger $logger
* @param string $filePath * @param string $filePath
* @param string $dataPath * @param string $dataPath
* @param string $pluginPath * @param string $pluginPath
*/ */
public function __construct(\SplClassLoader $autoloader, $filePath, $dataPath, $pluginPath){ public function __construct(\SplClassLoader $autoloader, Logger $logger, $filePath, $dataPath, $pluginPath){
self::$instance = $this; self::$instance = $this;
$this->autoloader = $autoloader; $this->autoloader = $autoloader;
$this->logger = $logger;
$this->filePath = $filePath; $this->filePath = $filePath;
$this->dataPath = $dataPath; $this->dataPath = $dataPath;
$this->pluginPath = $pluginPath; $this->pluginPath = $pluginPath;
@ -1211,9 +1224,9 @@ class Server{
$this->console = new CommandReader(); $this->console = new CommandReader();
$version = new VersionString($this->getPocketMineVersion()); $version = new VersionString($this->getPocketMineVersion());
console("[INFO] Starting Minecraft: PE server version " . TextFormat::AQUA . $this->getVersion()); $this->logger->info("Starting Minecraft: PE server version " . TextFormat::AQUA . $this->getVersion());
console("[INFO] Loading properties..."); $this->logger->info("Loading properties...");
$this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, array( $this->properties = new Config($this->dataPath . "server.properties", Config::PROPERTIES, array(
"motd" => "Minecraft: PE Server", "motd" => "Minecraft: PE Server",
"server-port" => 19132, "server-port" => 19132,
@ -1250,7 +1263,7 @@ class Server{
$value = array("M" => 1, "G" => 1024); $value = array("M" => 1, "G" => 1024);
$real = ((int) substr($memory, 0, -1)) * $value[substr($memory, -1)]; $real = ((int) substr($memory, 0, -1)) * $value[substr($memory, -1)];
if($real < 128){ if($real < 128){
console("[WARNING] PocketMine-MP may not work right with less than 128MB of RAM", true, true, 0); $this->logger->warning("PocketMine-MP may not work right with less than 128MB of RAM", true, true, 0);
} }
@ini_set("memory_limit", $memory); @ini_set("memory_limit", $memory);
}else{ }else{
@ -1265,20 +1278,20 @@ class Server{
define("ADVANCED_CACHE", $this->getConfigBoolean("enable-advanced-cache", false)); define("ADVANCED_CACHE", $this->getConfigBoolean("enable-advanced-cache", false));
define("MAX_CHUNK_RATE", 20 / $this->getConfigInt("max-chunks-per-second", 7)); //Default rate ~448 kB/s define("MAX_CHUNK_RATE", 20 / $this->getConfigInt("max-chunks-per-second", 7)); //Default rate ~448 kB/s
if(ADVANCED_CACHE == true){ if(ADVANCED_CACHE == true){
console("[INFO] Advanced cache enabled"); $this->logger->info("Advanced cache enabled");
} }
if(defined("pocketmine\\DEBUG") and \pocketmine\DEBUG >= 0 and function_exists("cli_set_process_title")){ if(defined("pocketmine\\DEBUG") and \pocketmine\DEBUG >= 0 and function_exists("cli_set_process_title")){
@cli_set_process_title("PocketMine-MP " . $this->getPocketMineVersion()); @cli_set_process_title("PocketMine-MP " . $this->getPocketMineVersion());
} }
console("[INFO] Starting Minecraft PE server on " . ($this->getIp() === "" ? "*" : $this->getIp()) . ":" . $this->getPort()); $this->logger->info("Starting Minecraft PE server on " . ($this->getIp() === "" ? "*" : $this->getIp()) . ":" . $this->getPort());
define("BOOTUP_RANDOM", Utils::getRandomBytes(16)); define("BOOTUP_RANDOM", Utils::getRandomBytes(16));
$this->serverID = Binary::readLong(substr(Utils::getUniqueID(true, $this->getIp() . $this->getPort()), 0, 8)); $this->serverID = Binary::readLong(substr(Utils::getUniqueID(true, $this->getIp() . $this->getPort()), 0, 8));
$this->interface = new ThreadedHandler("255.255.255.255", $this->getPort(), $this->getIp() === "" ? "0.0.0.0" : $this->getIp()); $this->interface = new ThreadedHandler("255.255.255.255", $this->getPort(), $this->getIp() === "" ? "0.0.0.0" : $this->getIp());
console("[INFO] This server is running PocketMine-MP version " . ($version->isDev() ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET . " \"" . $this->getCodename() . "\" (API " . $this->getApiVersion() . ")", true, true, 0); $this->logger->info("This server is running PocketMine-MP version " . ($version->isDev() ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET . " \"" . $this->getCodename() . "\" (API " . $this->getApiVersion() . ")", true, true, 0);
console("[INFO] PocketMine-MP is distributed under the LGPL License", true, true, 0); $this->logger->info("PocketMine-MP is distributed under the LGPL License", true, true, 0);
$this->consoleSender = new ConsoleCommandSender(); $this->consoleSender = new ConsoleCommandSender();
$this->commandMap = new SimpleCommandMap($this); $this->commandMap = new SimpleCommandMap($this);
@ -1331,8 +1344,8 @@ class Server{
/* /*
//TODO //TODO
if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){ if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){
console("[INFO] Checking for new server version"); $this->logger->info("Checking for new server version");
console("[INFO] Last check: " . TextFormat::AQUA . date("Y-m-d H:i:s", $this->getProperty("last-update")) . "\x1b[0m"); $this->logger->info("Last check: " . TextFormat::AQUA . date("Y-m-d H:i:s", $this->getProperty("last-update")));
if($this->server->version->isDev()){ if($this->server->version->isDev()){
$info = json_decode(Utils::getURL("https://api.github.com/repos/PocketMine/PocketMine-MP/commits"), true); $info = json_decode(Utils::getURL("https://api.github.com/repos/PocketMine/PocketMine-MP/commits"), true);
if($info === false or !isset($info[0])){ if($info === false or !isset($info[0])){
@ -1341,13 +1354,13 @@ class Server{
$last = new \DateTime($info[0]["commit"]["committer"]["date"]); $last = new \DateTime($info[0]["commit"]["committer"]["date"]);
$last = $last->getTimestamp(); $last = $last->getTimestamp();
if($last >= $this->getProperty("last-update") and $this->getProperty("last-update") !== false and \pocketmine\GIT_COMMIT != $info[0]["sha"]){ if($last >= $this->getProperty("last-update") and $this->getProperty("last-update") !== false and \pocketmine\GIT_COMMIT != $info[0]["sha"]){
console("[NOTICE] " . TextFormat::YELLOW . "A new DEVELOPMENT version of PocketMine-MP has been released!"); $this->logger->notice("" . TextFormat::YELLOW . "A new DEVELOPMENT version of PocketMine-MP has been released!");
console("[NOTICE] " . TextFormat::YELLOW . "Commit \"" . $info[0]["commit"]["message"] . "\" [" . substr($info[0]["sha"], 0, 10) . "] by " . $info[0]["commit"]["committer"]["name"]); $this->logger->notice("" . TextFormat::YELLOW . "Commit \"" . $info[0]["commit"]["message"] . "\" [" . substr($info[0]["sha"], 0, 10) . "] by " . $info[0]["commit"]["committer"]["name"]);
console("[NOTICE] " . TextFormat::YELLOW . "Get it at PocketMine.net or at https://github.com/PocketMine/PocketMine-MP/archive/" . $info[0]["sha"] . ".zip"); $this->logger->notice("" . TextFormat::YELLOW . "Get it at PocketMine.net or at https://github.com/PocketMine/PocketMine-MP/archive/" . $info[0]["sha"] . ".zip");
console("[NOTICE] This message will disappear after issuing the command \"/update-done\""); $this->logger->notice("This message will disappear after issuing the command \"/update-done\"");
}else{ }else{
$this->setProperty("last-update", time()); $this->setProperty("last-update", time());
console("[INFO] " . TextFormat::AQUA . "This is the latest DEVELOPMENT version"); $this->logger->info("" . TextFormat::AQUA . "This is the latest DEVELOPMENT version");
} }
} }
}else{ }else{
@ -1360,13 +1373,13 @@ class Server{
$update = new VersionString($info[0]["name"]); $update = new VersionString($info[0]["name"]);
$updateN = $update->getNumber(); $updateN = $update->getNumber();
if($updateN > $newestN){ if($updateN > $newestN){
console("[NOTICE] " . TextFormat::GREEN . "A new STABLE version of PocketMine-MP has been released!"); $this->logger->notice("" . TextFormat::GREEN . "A new STABLE version of PocketMine-MP has been released!");
console("[NOTICE] " . TextFormat::GREEN . "Version \"" . $info[0]["name"] . "\" #" . $updateN); $this->logger->notice("" . TextFormat::GREEN . "Version \"" . $info[0]["name"] . "\" #" . $updateN);
console("[NOTICE] Get it at PocketMine.net or at " . $info[0]["zipball_url"]); $this->logger->notice("Get it at PocketMine.net or at " . $info[0]["zipball_url"]);
console("[NOTICE] This message will disappear as soon as you update"); $this->logger->notice("This message will disappear as soon as you update");
}else{ }else{
$this->setProperty("last-update", time()); $this->setProperty("last-update", time());
console("[INFO] " . TextFormat::AQUA . "This is the latest STABLE version"); $this->logger->info("" . TextFormat::AQUA . "This is the latest STABLE version");
} }
} }
} }
@ -1475,7 +1488,7 @@ class Server{
} }
public function reload(){ public function reload(){
console("[INFO] Saving levels..."); $this->logger->info("Saving levels...");
foreach($this->levels as $level){ foreach($this->levels as $level){
$level->save(); $level->save();
@ -1485,7 +1498,7 @@ class Server{
$this->pluginManager->clearPlugins(); $this->pluginManager->clearPlugins();
$this->commandMap->clearCommands(); $this->commandMap->clearCommands();
console("[INFO] Reloading properties..."); $this->logger->info("Reloading properties...");
$this->properties->reload(); $this->properties->reload();
$this->maxPlayers = $this->getConfigInt("max-players", 20); $this->maxPlayers = $this->getConfigInt("max-players", 20);
@ -1493,7 +1506,7 @@ class Server{
$value = array("M" => 1, "G" => 1024); $value = array("M" => 1, "G" => 1024);
$real = ((int) substr($memory, 0, -1)) * $value[substr($memory, -1)]; $real = ((int) substr($memory, 0, -1)) * $value[substr($memory, -1)];
if($real < 128){ if($real < 128){
console("[WARNING] PocketMine-MP may not work right with less than 128MB of RAM", true, true, 0); $this->logger->warning("PocketMine-MP may not work right with less than 128MB of RAM", true, true, 0);
} }
@ini_set("memory_limit", $memory); @ini_set("memory_limit", $memory);
}else{ }else{
@ -1530,7 +1543,7 @@ class Server{
} }
if($this->getConfigBoolean("upnp-forwarding", false) === true){ if($this->getConfigBoolean("upnp-forwarding", false) === true){
console("[INFO] [UPnP] Removing port forward..."); $this->logger->info("[UPnP] Removing port forward...");
UPnP::RemovePortForward($this->getPort()); UPnP::RemovePortForward($this->getPort());
} }
@ -1571,7 +1584,7 @@ class Server{
if($this->getConfigBoolean("upnp-forwarding", false) == true){ if($this->getConfigBoolean("upnp-forwarding", false) == true){
console("[INFO] [UPnP] Trying to port forward..."); $this->logger->info("[UPnP] Trying to port forward...");
UPnP::PortForward($this->getPort()); UPnP::PortForward($this->getPort());
} }
@ -1585,9 +1598,9 @@ class Server{
pcntl_signal(SIGHUP, array($this, "shutdown")); pcntl_signal(SIGHUP, array($this, "shutdown"));
} }
console("[INFO] Default game type: " . self::getGamemodeString($this->getGamemode())); //TODO: string name $this->logger->info("Default game type: " . self::getGamemodeString($this->getGamemode())); //TODO: string name
console('[INFO] Done (' . round(microtime(true) - \pocketmine\START_TIME, 3) . 's)! For help, type "help" or "?"'); $this->logger->info("Done (" . round(microtime(true) - \pocketmine\START_TIME, 3) . 's)! For help, type "help" or "?"');
if(Utils::getOS() === "win"){ //Workaround less usleep() waste if(Utils::getOS() === "win"){ //Workaround less usleep() waste
$this->tickProcessorWindows(); $this->tickProcessorWindows();
}else{ }else{
@ -1619,7 +1632,7 @@ class Server{
public function checkTicks(){ public function checkTicks(){
if($this->getTicksPerSecond() < 12){ if($this->getTicksPerSecond() < 12){
console("[WARNING] Can't keep up! Is the server overloaded?"); $this->logger->warning("Can't keep up! Is the server overloaded?");
} }
} }
@ -1639,7 +1652,7 @@ class Server{
return; return;
} }
ini_set("memory_limit", "-1"); //Fix error dump not dumped on memory problems ini_set("memory_limit", "-1"); //Fix error dump not dumped on memory problems
console("[SEVERE] An unrecoverable has occurred and the server has crashed. Creating an error dump"); $this->logger->emergency("An unrecoverable has occurred and the server has crashed. Creating an error dump");
$dump = "```\r\n# PocketMine-MP Error Dump " . date("D M j H:i:s T Y") . "\r\n"; $dump = "```\r\n# PocketMine-MP Error Dump " . date("D M j H:i:s T Y") . "\r\n";
$er = error_get_last(); $er = error_get_last();
$errorConversion = array( $errorConversion = array(
@ -1715,7 +1728,7 @@ class Server{
$dump .= "\r\n```"; $dump .= "\r\n```";
$name = "Error_Dump_" . date("D_M_j-H.i.s-T_Y"); $name = "Error_Dump_" . date("D_M_j-H.i.s-T_Y");
log($dump, $name, true, 0, true); log($dump, $name, true, 0, true);
console("[SEVERE] Please submit the \"{$name}.log\" file to the Bug Reporting page. Give as much info as you can.", true, true, 0); $this->logger->emergency("Please submit the \"{$name}.log\" file to the Bug Reporting page. Give as much info as you can.", true, true, 0);
} }
private function tickProcessor(){ private function tickProcessor(){
@ -1764,7 +1777,7 @@ class Server{
break; break;
case RakNetInfo::OPEN_CONNECTION_REQUEST_1: case RakNetInfo::OPEN_CONNECTION_REQUEST_1:
if($packet->structure !== RakNetInfo::STRUCTURE){ if($packet->structure !== RakNetInfo::STRUCTURE){
console("[DEBUG] Incorrect structure #" . $packet->structure . " from " . $packet->ip . ":" . $packet->port, true, true, 2); $this->logger->debug("Incorrect structure #" . $packet->structure . " from " . $packet->ip . ":" . $packet->port);
$pk = new RakNetPacket(RakNetInfo::INCOMPATIBLE_PROTOCOL_VERSION); $pk = new RakNetPacket(RakNetInfo::INCOMPATIBLE_PROTOCOL_VERSION);
$pk->serverID = $this->serverID; $pk->serverID = $this->serverID;
$pk->ip = $packet->ip; $pk->ip = $packet->ip;

View File

@ -25,6 +25,7 @@ use pocketmine\permission\PermissibleBase;
use pocketmine\permission\PermissionAttachment; use pocketmine\permission\PermissionAttachment;
use pocketmine\plugin\Plugin; use pocketmine\plugin\Plugin;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\utils\MainLogger;
class ConsoleCommandSender implements CommandSender{ class ConsoleCommandSender implements CommandSender{
@ -102,8 +103,7 @@ class ConsoleCommandSender implements CommandSender{
*/ */
public function sendMessage($message){ public function sendMessage($message){
foreach(explode("\n", trim($message)) as $line){ foreach(explode("\n", trim($message)) as $line){
$line = trim($line); MainLogger::getLogger()->info($line);
console($line);
} }
} }

View File

@ -161,7 +161,7 @@ class Level{
if($this === $this->server->getDefaultLevel() and $force !== true){ if($this === $this->server->getDefaultLevel() and $force !== true){
return false; return false;
} }
console("[INFO] Unloading level \"" . $this->getName() . "\""); $this->server->getLogger()->info("Unloading level \"" . $this->getName() . "\"");
$this->nextSave = PHP_INT_MAX; $this->nextSave = PHP_INT_MAX;
$this->save(); $this->save();
$defaultLevel = $this->server->getDefaultLevel(); $defaultLevel = $this->server->getDefaultLevel();

View File

@ -25,6 +25,7 @@ use pocketmine\level\format\pmf\LevelFormat;
use pocketmine\level\format\PocketChunkParser; use pocketmine\level\format\PocketChunkParser;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\utils\Config; use pocketmine\utils\Config;
use pocketmine\utils\MainLogger;
class LevelImport{ class LevelImport{
private $path; private $path;
@ -36,7 +37,7 @@ class LevelImport{
public function import(){ public function import(){
if(file_exists($this->path . "tileEntities.dat")){ //OldPM if(file_exists($this->path . "tileEntities.dat")){ //OldPM
$level = unserialize(file_get_contents($this->path . "level.dat")); $level = unserialize(file_get_contents($this->path . "level.dat"));
console("[INFO] Importing OldPM level \"" . $level["LevelName"] . "\" to PMF format"); MainLogger::getLogger()->info("Importing OldPM level \"" . $level["LevelName"] . "\" to PMF format");
$entities = new Config($this->path . "entities.yml", Config::YAML, unserialize(file_get_contents($this->path . "entities.dat"))); $entities = new Config($this->path . "entities.yml", Config::YAML, unserialize(file_get_contents($this->path . "entities.dat")));
$entities->save(); $entities->save();
$tiles = new Config($this->path . "tiles.yml", Config::YAML, unserialize(file_get_contents($this->path . "tileEntities.dat"))); $tiles = new Config($this->path . "tiles.yml", Config::YAML, unserialize(file_get_contents($this->path . "tileEntities.dat")));
@ -48,7 +49,7 @@ class LevelImport{
if($level["LevelName"] == ""){ if($level["LevelName"] == ""){
$level["LevelName"] = "world" . time(); $level["LevelName"] = "world" . time();
} }
console("[INFO] Importing Pocket level \"" . $level->LevelName . "\" to PMF format"); MainLogger::getLogger()->info("Importing Pocket level \"" . $level->LevelName . "\" to PMF format");
unset($level->Player); unset($level->Player);
$nbt->read(substr(file_get_contents($this->path . "entities.dat"), 12)); $nbt->read(substr(file_get_contents($this->path . "entities.dat"), 12));
$entities = $nbt->getData(); $entities = $nbt->getData();
@ -111,7 +112,7 @@ class LevelImport{
$pmf->setPopulated($X, $Z); $pmf->setPopulated($X, $Z);
$pmf->saveChunk($X, $Z); $pmf->saveChunk($X, $Z);
} }
console("[NOTICE] Importing level " . ceil(($Z + 1) / 0.16) . "%"); MainLogger::getLogger()->notice("Importing level " . ceil(($Z + 1) / 0.16) . "%");
} }
$chunks->map = null; $chunks->map = null;
$chunks = null; $chunks = null;

View File

@ -41,7 +41,6 @@ class PocketChunkParser{
private function loadLocationTable(){ private function loadLocationTable(){
$this->location = []; $this->location = [];
console("[DEBUG] Loading Chunk Location table...", true, true, 2);
for($offset = 0; $offset < 0x1000; $offset += 4){ for($offset = 0; $offset < 0x1000; $offset += 4){
$data = Binary::readLInt(substr($this->raw, $offset, 4)); $data = Binary::readLInt(substr($this->raw, $offset, 4));
$sectors = $data & 0xff; $sectors = $data & 0xff;
@ -136,7 +135,6 @@ class PocketChunkParser{
return false; return false;
} }
$this->loadLocationTable(); $this->loadLocationTable();
console("[DEBUG] Loading chunks...", true, true, 2);
for($x = 0; $x < 16; ++$x){ for($x = 0; $x < 16; ++$x){
$this->map[$x] = []; $this->map[$x] = [];
for($z = 0; $z < 16; ++$z){ for($z = 0; $z < 16; ++$z){
@ -144,13 +142,11 @@ class PocketChunkParser{
} }
} }
$this->raw = ""; $this->raw = "";
console("[DEBUG] Chunks loaded!", true, true, 2);
return true; return true;
} }
public function saveMap($final = false){ public function saveMap($final = false){
console("[DEBUG] Saving chunks...", true, true, 2);
$fp = fopen($this->file, "r+b"); $fp = fopen($this->file, "r+b");
flock($fp, LOCK_EX); flock($fp, LOCK_EX);
@ -165,7 +161,6 @@ class PocketChunkParser{
$original = filesize($this->file); $original = filesize($this->file);
file_put_contents($this->file . ".gz", gzdeflate(gzdeflate(file_get_contents($this->file), 9), 9)); //Double compression for flat maps file_put_contents($this->file . ".gz", gzdeflate(gzdeflate(file_get_contents($this->file), 9), 9)); //Double compression for flat maps
$compressed = filesize($this->file . ".gz"); $compressed = filesize($this->file . ".gz");
console("[DEBUG] Saved chunks.dat.gz with " . round(($compressed / $original) * 100, 2) . "% (" . round($compressed / 1024, 2) . "KB) of the original size", true, true, 2);
if($final === true){ if($final === true){
@unlink($this->file); @unlink($this->file);
} }

View File

@ -26,6 +26,7 @@ use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
use pocketmine\nbt\tag\Enum; use pocketmine\nbt\tag\Enum;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\MainLogger;
class LevelFormat extends PMF{ class LevelFormat extends PMF{
const VERSION = 2; const VERSION = 2;
@ -121,7 +122,7 @@ class LevelFormat extends PMF{
$this->seek(5); $this->seek(5);
$this->levelData["version"] = ord($this->read(1)); $this->levelData["version"] = ord($this->read(1));
if($this->levelData["version"] > self::VERSION){ if($this->levelData["version"] > self::VERSION){
console("[ERROR] New unsupported PMF Level format version #" . $this->levelData["version"] . ", current version is #" . self::VERSION); MainLogger::getLogger()->error("New unsupported PMF Level format version #" . $this->levelData["version"] . ", current version is #" . self::VERSION);
return false; return false;
} }
@ -161,7 +162,7 @@ class LevelFormat extends PMF{
} }
private function upgrade_From0_To1(){ private function upgrade_From0_To1(){
console("[NOTICE] Old PMF Level format version #0 detected, upgrading to version #1"); MainLogger::getLogger()->notice("Old PMF Level format version #0 detected, upgrading to version #1");
for($index = 0; $index < 256; ++$index){ for($index = 0; $index < 256; ++$index){
$X = $index & 0x0F; $X = $index & 0x0F;
$Z = $index >> 4; $Z = $index >> 4;
@ -186,7 +187,7 @@ class LevelFormat extends PMF{
} }
private function upgrade_From1_To2(){ private function upgrade_From1_To2(){
console("[NOTICE] Old PMF Level format version #1 detected, upgrading to version #2"); MainLogger::getLogger()->notice("Old PMF Level format version #1 detected, upgrading to version #2");
$nbt = new Compound("", array( $nbt = new Compound("", array(
new Enum("Entities", []), new Enum("Entities", []),
new Enum("TileEntities", []) new Enum("TileEntities", [])
@ -308,7 +309,7 @@ class LevelFormat extends PMF{
if(($this->chunkInfo[$index][0] & (1 << $Y)) !== 0){ if(($this->chunkInfo[$index][0] & (1 << $Y)) !== 0){
// 4096 + 2048 + 2048, Block Data, Meta, Light // 4096 + 2048 + 2048, Block Data, Meta, Light
if(strlen($this->chunks[$index][$Y] = substr($chunk, $offset, 8192)) < 8192){ if(strlen($this->chunks[$index][$Y] = substr($chunk, $offset, 8192)) < 8192){
console("[NOTICE] Empty corrupt chunk detected [$X,$Z,:$Y], recovering contents", true, true, 2); MainLogger::getLogger()->notice("Empty corrupt chunk detected [$X,$Z,:$Y], recovering contents");
$this->fillMiniChunk($X, $Z, $Y); $this->fillMiniChunk($X, $Z, $Y);
} }
$offset += 8192; $offset += 8192;

View File

@ -25,6 +25,8 @@
namespace pocketmine\level\format\pmf; namespace pocketmine\level\format\pmf;
use pocketmine\utils\MainLogger;
class PMF{ class PMF{
const VERSION = 0x01; const VERSION = 0x01;
@ -78,7 +80,7 @@ class PMF{
$this->type = ord($this->read(1)); $this->type = ord($this->read(1));
break; break;
default: default:
console("[ERROR] Tried loading non-supported PMF version " . $this->version . " on file " . $this->file); MainLogger::getLogger()->alert("Tried loading non-supported PMF version " . $this->version . " on file " . $this->file);
return false; return false;
} }

View File

@ -27,6 +27,7 @@ namespace pocketmine\network;
use pocketmine\network\query\QueryPacket; use pocketmine\network\query\QueryPacket;
use pocketmine\network\raknet\Info; use pocketmine\network\raknet\Info;
use pocketmine\network\raknet\Packet as RakNetPacket; use pocketmine\network\raknet\Packet as RakNetPacket;
use pocketmine\utils\MainLogger;
class ThreadedHandler extends \Thread{ class ThreadedHandler extends \Thread{
protected $bandwidthUp; protected $bandwidthUp;
@ -124,8 +125,8 @@ class ThreadedHandler extends \Thread{
@socket_set_option($this->socket, SOL_SOCKET, SO_SNDBUF, 1024 * 1024 * 2); //2MB @socket_set_option($this->socket, SOL_SOCKET, SO_SNDBUF, 1024 * 1024 * 2); //2MB
@socket_set_option($this->socket, SOL_SOCKET, SO_RCVBUF, 1024 * 1024); //1MB @socket_set_option($this->socket, SOL_SOCKET, SO_RCVBUF, 1024 * 1024); //1MB
}else{ }else{
console("[SEVERE] **** FAILED TO BIND TO " . $this->serverip . ":" . $this->port . "!", true, true, 0); MainLogger::getLogger()->critical("**** FAILED TO BIND TO " . $this->serverip . ":" . $this->port . "!", true, true, 0);
console("[SEVERE] Perhaps a server is already running on that port?", true, true, 0); MainLogger::getLogger()->critical("Perhaps a server is already running on that port?", true, true, 0);
exit(1); exit(1);
} }
socket_set_nonblock($this->socket); socket_set_nonblock($this->socket);

View File

@ -33,11 +33,11 @@ class QueryHandler{
private $socket, $server, $lastToken, $token, $longData, $timeout; private $socket, $server, $lastToken, $token, $longData, $timeout;
public function __construct(){ public function __construct(){
console("[INFO] Starting GS4 status listener");
$this->server = Server::getInstance(); $this->server = Server::getInstance();
$this->server->getLogger()->info("Starting GS4 status listener");
$addr = ($ip = $this->server->getIp()) != "" ? $ip : "0.0.0.0"; $addr = ($ip = $this->server->getIp()) != "" ? $ip : "0.0.0.0";
$port = $this->server->getPort(); $port = $this->server->getPort();
console("[INFO] Setting query port to $port"); $this->server->getLogger()->info("Setting query port to $port");
/* /*
The Query protocol is built on top of the existing Minecraft PE UDP network stack. The Query protocol is built on top of the existing Minecraft PE UDP network stack.
Because the 0xFE packet does not exist in the MCPE protocol, Because the 0xFE packet does not exist in the MCPE protocol,
@ -50,7 +50,7 @@ class QueryHandler{
$this->regenerateToken(); $this->regenerateToken();
$this->lastToken = $this->token; $this->lastToken = $this->token;
$this->regenerateInfo(); $this->regenerateInfo();
console("[INFO] Query running on $addr:$port"); $this->server->getLogger()->info("Query running on $addr:$port");
} }
public function regenerateInfo(){ public function regenerateInfo(){

View File

@ -28,6 +28,7 @@ namespace pocketmine\network\rcon;
use pocketmine\command\RemoteConsoleCommandSender; use pocketmine\command\RemoteConsoleCommandSender;
use pocketmine\scheduler\CallbackTask; use pocketmine\scheduler\CallbackTask;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\utils\MainLogger;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
@ -43,9 +44,9 @@ class RCON{
public function __construct($password, $port = 19132, $interface = "0.0.0.0", $threads = 1, $clientsPerThread = 50){ public function __construct($password, $port = 19132, $interface = "0.0.0.0", $threads = 1, $clientsPerThread = 50){
$this->workers = []; $this->workers = [];
$this->password = (string) $password; $this->password = (string) $password;
console("[INFO] Starting remote control listener"); MainLogger::getLogger()->info("Starting remote control listener");
if($this->password === ""){ if($this->password === ""){
console("[ERROR] RCON can't be started: Empty password"); MainLogger::getLogger()->critical("RCON can't be started: Empty password");
return; return;
} }
@ -53,7 +54,7 @@ class RCON{
$this->clientsPerThread = (int) max(1, $clientsPerThread); $this->clientsPerThread = (int) max(1, $clientsPerThread);
$this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if($this->socket === false or !socket_bind($this->socket, $interface, (int) $port) or !socket_listen($this->socket)){ if($this->socket === false or !socket_bind($this->socket, $interface, (int) $port) or !socket_listen($this->socket)){
console("[ERROR] RCON can't be started: " . socket_strerror(socket_last_error())); MainLogger::getLogger()->critical("RCON can't be started: " . socket_strerror(socket_last_error()));
return; return;
} }
@ -63,7 +64,7 @@ class RCON{
$this->workers[$n] = new RCONInstance($this->socket, $this->password, $this->clientsPerThread); $this->workers[$n] = new RCONInstance($this->socket, $this->password, $this->clientsPerThread);
} }
@socket_getsockname($this->socket, $addr, $port); @socket_getsockname($this->socket, $addr, $port);
console("[INFO] RCON running on $addr:$port"); MainLogger::getLogger()->info("RCON running on $addr:$port");
Server::getInstance()->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "check")), 3); Server::getInstance()->getScheduler()->scheduleRepeatingTask(new CallbackTask(array($this, "check")), 3);
} }
@ -83,7 +84,7 @@ class RCON{
$this->workers[$n] = new RCONInstance($this->socket, $this->password, $this->clientsPerThread); $this->workers[$n] = new RCONInstance($this->socket, $this->password, $this->clientsPerThread);
}elseif($this->workers[$n]->isWaiting()){ }elseif($this->workers[$n]->isWaiting()){
if($this->workers[$n]->response !== ""){ if($this->workers[$n]->response !== ""){
console($this->workers[$n]->response); MainLogger::getLogger()->info($this->workers[$n]->response);
$this->workers[$n]->notify(); $this->workers[$n]->notify();
}else{ }else{
Server::getInstance()->dispatchCommand($response = new RemoteConsoleCommandSender(), $this->workers[$n]->cmd); Server::getInstance()->dispatchCommand($response = new RemoteConsoleCommandSender(), $this->workers[$n]->cmd);

View File

@ -22,6 +22,7 @@
namespace pocketmine\permission; namespace pocketmine\permission;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\utils\MainLogger;
class BanList{ class BanList{
@ -141,7 +142,7 @@ class BanList{
} }
fclose($fp); fclose($fp);
}else{ }else{
console("[ERROR] Could not load ban list"); MainLogger::getLogger()->error("Could not load ban list");
} }
} }
@ -159,7 +160,7 @@ class BanList{
} }
fclose($fp); fclose($fp);
}else{ }else{
console("[ERROR] Could not save ban list"); MainLogger::getLogger()->error("Could not save ban list");
} }
} }

View File

@ -24,6 +24,7 @@ namespace pocketmine\plugin;
use pocketmine\event\plugin\PluginDisableEvent; use pocketmine\event\plugin\PluginDisableEvent;
use pocketmine\event\plugin\PluginEnableEvent; use pocketmine\event\plugin\PluginEnableEvent;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\utils\MainLogger;
/** /**
* Handles different types of plugins * Handles different types of plugins
@ -51,7 +52,7 @@ class PharPluginLoader implements PluginLoader{
*/ */
public function loadPlugin($file){ public function loadPlugin($file){
if(\Phar::isValidPharFilename($file) and ($description = $this->getPluginDescription($file)) instanceof PluginDescription){ if(\Phar::isValidPharFilename($file) and ($description = $this->getPluginDescription($file)) instanceof PluginDescription){
console("[INFO] Loading " . $description->getFullName()); MainLogger::getLogger()->info("Loading " . $description->getFullName());
$dataFolder = dirname($file) . DIRECTORY_SEPARATOR . $description->getName(); $dataFolder = dirname($file) . DIRECTORY_SEPARATOR . $description->getName();
if(file_exists($dataFolder) and !is_dir($dataFolder)){ if(file_exists($dataFolder) and !is_dir($dataFolder)){
throw new \Exception("Projected dataFolder '" . $dataFolder . "' for " . $description->getName() . " exists and is not a directory"); throw new \Exception("Projected dataFolder '" . $dataFolder . "' for " . $description->getName() . " exists and is not a directory");
@ -121,7 +122,7 @@ class PharPluginLoader implements PluginLoader{
*/ */
public function enablePlugin(Plugin $plugin){ public function enablePlugin(Plugin $plugin){
if($plugin instanceof PluginBase and !$plugin->isEnabled()){ if($plugin instanceof PluginBase and !$plugin->isEnabled()){
console("[INFO] Enabling " . $plugin->getDescription()->getFullName()); MainLogger::getLogger()->info("Enabling " . $plugin->getDescription()->getFullName());
$plugin->setEnabled(true); $plugin->setEnabled(true);
@ -134,7 +135,7 @@ class PharPluginLoader implements PluginLoader{
*/ */
public function disablePlugin(Plugin $plugin){ public function disablePlugin(Plugin $plugin){
if($plugin instanceof PluginBase and $plugin->isEnabled()){ if($plugin instanceof PluginBase and $plugin->isEnabled()){
console("[INFO] Disabling " . $plugin->getDescription()->getFullName()); MainLogger::getLogger()->info("Disabling " . $plugin->getDescription()->getFullName());
Server::getInstance()->getPluginManager()->callEvent(new PluginDisableEvent($plugin)); Server::getInstance()->getPluginManager()->callEvent(new PluginDisableEvent($plugin));

View File

@ -241,7 +241,7 @@ abstract class PluginBase implements Plugin{
public function saveConfig(){ public function saveConfig(){
if($this->getConfig()->save() === false){ if($this->getConfig()->save() === false){
console("[SEVERE] Could not save config to " . $this->configFile); $this->getLogger()->critical("Could not save config to " . $this->configFile);
} }
} }

View File

@ -21,7 +21,14 @@
namespace pocketmine\plugin; namespace pocketmine\plugin;
class PluginLogger{ use pocketmine\level\Level;
use pocketmine\Server;
use pocketmine\utils\Logger;
use pocketmine\utils\LogLevel;
use pocketmine\utils\MainLogger;
use pocketmine\utils\TextFormat;
class PluginLogger implements Logger{
private $pluginName; private $pluginName;
@ -33,12 +40,39 @@ class PluginLogger{
$this->pluginName = $prefix != null ? "[$prefix] " : "[" . $context->getDescription()->getName() . "] "; $this->pluginName = $prefix != null ? "[$prefix] " : "[" . $context->getDescription()->getName() . "] ";
} }
/** public function emergency($message){
* Logs a message to the console $this->log(LogLevel::EMERGENCY, $message);
* }
* @param string $message
*/ public function alert($message){
public function log($message){ $this->log(LogLevel::ALERT, $message);
console($this->pluginName . $message); }
public function critical($message){
$this->log(LogLevel::CRITICAL, $message);
}
public function error($message){
$this->log(LogLevel::ERROR, $message);
}
public function warning($message){
$this->log(LogLevel::WARNING, $message);
}
public function notice($message){
$this->log(LogLevel::NOTICE, $message);
}
public function info($message){
$this->log(LogLevel::INFO, $message);
}
public function debug($message){
$this->log(LogLevel::DEBUG, $message);
}
public function log($level, $message){
MainLogger::getLogger()->log($level, $this->pluginName . $message);
} }
} }

View File

@ -189,14 +189,14 @@ class PluginManager{
if($description instanceof PluginDescription){ if($description instanceof PluginDescription){
$name = $description->getName(); $name = $description->getName();
if(stripos($name, "pocketmine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){ if(stripos($name, "pocketmine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){
console("[ERROR] Could not load plugin '" . $name . "': restricted name"); $this->server->getLogger()->error("Could not load plugin '" . $name . "': restricted name");
continue; continue;
}elseif(strpos($name, " ") !== false){ }elseif(strpos($name, " ") !== false){
console("[WARNING] Plugin '" . $name . "' uses spaces in its name, this is discouraged"); $this->server->getLogger()->warning("Plugin '" . $name . "' uses spaces in its name, this is discouraged");
} }
if(isset($plugins[$name]) or $this->getPlugin($name) instanceof Plugin){ if(isset($plugins[$name]) or $this->getPlugin($name) instanceof Plugin){
console("[ERROR] Could not load duplicate plugin '" . $name . "': plugin exists"); $this->server->getLogger()->error("Could not load duplicate plugin '" . $name . "': plugin exists");
continue; continue;
} }
@ -220,7 +220,7 @@ class PluginManager{
} }
if($compatible === false){ if($compatible === false){
console("[ERROR] Could not load plugin '" . $name . "': API version not compatible"); $this->server->getLogger()->error("Could not load plugin '" . $name . "': API version not compatible");
continue; continue;
} }
@ -249,7 +249,7 @@ class PluginManager{
if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){ if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){
unset($dependencies[$name][$key]); unset($dependencies[$name][$key]);
}elseif(!isset($plugins[$dependency])){ }elseif(!isset($plugins[$dependency])){
console("[SEVERE] Could not load plugin '" . $name . "': Unknown dependency"); $this->server->getLogger()->critical("Could not load plugin '" . $name . "': Unknown dependency");
break; break;
} }
} }
@ -277,7 +277,7 @@ class PluginManager{
if($plugin = $this->loadPlugin($file) and $plugin instanceof Plugin){ if($plugin = $this->loadPlugin($file) and $plugin instanceof Plugin){
$loadedPlugins[$name] = $plugin; $loadedPlugins[$name] = $plugin;
}else{ }else{
console("[SEVERE] Could not load plugin '" . $name . "'"); $this->server->getLogger()->critical("Could not load plugin '" . $name . "'");
} }
} }
} }
@ -291,7 +291,7 @@ class PluginManager{
if($plugin = $this->loadPlugin($file) and $plugin instanceof Plugin){ if($plugin = $this->loadPlugin($file) and $plugin instanceof Plugin){
$loadedPlugins[$name] = $plugin; $loadedPlugins[$name] = $plugin;
}else{ }else{
console("[SEVERE] Could not load plugin '" . $name . "'"); $this->server->getLogger()->critical("Could not load plugin '" . $name . "'");
} }
} }
} }
@ -299,7 +299,7 @@ class PluginManager{
//No plugins loaded :( //No plugins loaded :(
if($missingDependency === true){ if($missingDependency === true){
foreach($plugins as $name => $file){ foreach($plugins as $name => $file){
console("[SEVERE] Could not load plugin '" . $name . "': circular dependency detected"); $this->server->getLogger()->critical("Could not load plugin '" . $name . "': circular dependency detected");
} }
$plugins = []; $plugins = [];
} }
@ -542,7 +542,7 @@ class PluginManager{
foreach($plugin->getDescription()->getCommands() as $key => $data){ foreach($plugin->getDescription()->getCommands() as $key => $data){
if(strpos($key, ":") !== false){ if(strpos($key, ":") !== false){
console("[SEVERE] Could not load command " . $key . " for plugin " . $plugin->getDescription()->getName()); $this->server->getLogger()->critical("Could not load command " . $key . " for plugin " . $plugin->getDescription()->getName());
continue; continue;
} }
if(is_array($data)){ if(is_array($data)){
@ -559,7 +559,7 @@ class PluginManager{
$aliasList = []; $aliasList = [];
foreach($data["aliases"] as $alias){ foreach($data["aliases"] as $alias){
if(strpos($alias, ":") !== false){ if(strpos($alias, ":") !== false){
console("[SEVERE] Could not load alias " . $alias . " for plugin " . $plugin->getDescription()->getName()); $this->server->getLogger()->critical("Could not load alias " . $alias . " for plugin " . $plugin->getDescription()->getName());
continue; continue;
} }
$aliasList[] = $alias; $aliasList[] = $alias;

View File

@ -410,7 +410,7 @@ class Config{
break; break;
} }
if(isset($this->config[$k])){ if(isset($this->config[$k])){
console("[NOTICE] [Config] Repeated property " . $k . " on file " . $this->file, true, true, 2); MainLogger::getLogger()->debug("[Config] Repeated property " . $k . " on file " . $this->file);
} }
$this->config[$k] = $v; $this->config[$k] = $v;
} }

View File

@ -0,0 +1,33 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\utils;
interface LogLevel{
const EMERGENCY = "emergency";
const ALERT = "alert";
const CRITICAL = "critical";
const ERROR = "error";
const WARNING = "warning";
const NOTICE = "notice";
const INFO = "info";
const DEBUG = "debug";
}

View File

@ -0,0 +1,93 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\utils;
interface Logger{
/**
* System is unusable
*
* @param string $message
*/
public function emergency($message);
/**
* Action must me taken immediately
*
* @param string $message
*/
public function alert($message);
/**
* Critical conditions
*
* @param string $message
*/
public function critical($message);
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
*/
public function error($message);
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
*/
public function warning($message);
/**
* Normal but significant events.
*
* @param string $message
*/
public function notice($message);
/**
* Inersting events.
*
* @param string $message
*/
public function info($message);
/**
* Detailed debug information.
*
* @param string $message
*/
public function debug($message);
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
*/
public function log($level, $message);
}

View File

@ -0,0 +1,163 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\utils;
class MainLogger extends \Thread implements Logger{
protected $logFile;
protected $logStream;
protected $shutdown;
protected $hasANSI;
private $logResource;
/** @var MainLogger */
public static $logger = null;
/**
* @param string $logFile
* @param bool $hasANSI
*
* @throws \RuntimeException
*/
public function __construct($logFile, $hasANSI = false){
if(static::$logger instanceof MainLogger){
throw new \RuntimeException("MainLogger has been already created");
}
static::$logger = $this;
@mkdir(basename($logFile), 0777, true);
$this->logFile = $logFile;
$this->hasANSI = (bool) $hasANSI;
$this->logStream = "";
$this->start(PTHREADS_INHERIT_NONE);
}
/**
* @return MainLogger
*/
public static function getLogger(){
return static::$logger;
}
public function emergency($message){
$this->send(TextFormat::RED . "[EMERGENCY] ". $message);
}
public function alert($message){
$this->send(TextFormat::RED . "[ALERT] ". $message);
}
public function critical($message){
$this->send(TextFormat::RED . "[CRITICAL] ". $message);
}
public function error($message){
$this->send(TextFormat::DARK_RED . "[ERROR] ". $message);
}
public function warning($message){
$this->send(TextFormat::YELLOW . "[WARNING] ". $message);
}
public function notice($message){
$this->send(TextFormat::AQUA . "[NOTICE] ". $message);
}
public function info($message){
$this->send(TextFormat::WHITE . "[INFO] ". $message);
}
public function debug($message){
$this->send(TextFormat::GRAY . "[DEBUG] ". $message);
}
public function log($level, $message){
switch($level){
case LogLevel::EMERGENCY:
$this->emergency($message);
break;
case LogLevel::ALERT:
$this->alert($message);
break;
case LogLevel::CRITICAL:
$this->critical($message);
break;
case LogLevel::ERROR:
$this->error($message);
break;
case LogLevel::WARNING:
$this->warning($message);
break;
case LogLevel::NOTICE:
$this->notice($message);
break;
case LogLevel::INFO:
$this->info($message);
break;
case LogLevel::DEBUG:
$this->debug($message);
break;
}
}
public function shutdown(){
$this->shutdown = true;
}
protected function send($message){
$now = time();
$message = TextFormat::toANSI(TextFormat::AQUA . date("H:i:s", $now) . TextFormat::RESET . " " . $message . TextFormat::RESET . PHP_EOL);
$cleanMessage = TextFormat::clean(preg_replace('/\x1b\[[0-9;]*m/', "", $message));
if(!$this->hasANSI){
echo $cleanMessage;
}else{
echo $message;
}
$this->logStream .= date("Y-m-d", $now) . " " . $cleanMessage;
}
public function run(){
$this->shutdown = false;
$this->logResource = fopen($this->logFile, "a+b");
if(!is_resource($this->logResource)){
throw new \RuntimeException("Couldn't open log file");
}
flock($this->logResource, LOCK_EX);
while($this->shutdown === false){
if(strlen($this->logStream) >= 4096){
$this->synchronized(function(){
$chunks = strlen($this->logStream) >> 12;
$chunk = substr($this->logStream, 0, $chunks << 12);
$this->logStream = substr($this->logStream, $chunks << 12);
fwrite($this->logResource, $chunk);
});
}else{
usleep(250000); //sleep for 0.25 seconds
}
}
if(strlen($this->logStream) > 0){
fwrite($this->logResource, $this->logStream);
}
flock($this->logResource, LOCK_UN);
fclose($this->logResource);
}
}

View File

@ -0,0 +1,163 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
namespace pocketmine\utils;
class MainLogger extends \Thread implements Logger{
protected $logFile;
protected $logStream;
protected $shutdown;
protected $hasANSI;
private $logResource;
/** @var MainLogger */
public static $logger = null;
/**
* @param string $logFile
* @param bool $hasANSI
*
* @throws \RuntimeException
*/
public function __construct($logFile, $hasANSI = false){
if(static::$logger instanceof MainLogger){
throw new \RuntimeException("MainLogger has been already created");
}
static::$logger = $this;
@mkdir(basename($logFile), 0777, true);
$this->logFile = $logFile;
$this->hasANSI = (bool) $hasANSI;
$this->logStream = "";
$this->start(PTHREADS_INHERIT_NONE);
}
/**
* @return MainLogger
*/
public static function getLogger(){
return static::$logger;
}
public function emergency($message){
$this->send(TextFormat::RED . "[EMERGENCY] ". $message);
}
public function alert($message){
$this->send(TextFormat::RED . "[ALERT] ". $message);
}
public function critical($message){
$this->send(TextFormat::RED . "[CRITICAL] ". $message);
}
public function error($message){
$this->send(TextFormat::DARK_RED . "[ERROR] ". $message);
}
public function warning($message){
$this->send(TextFormat::YELLOW . "[WARNING] ". $message);
}
public function notice($message){
$this->send(TextFormat::AQUA . "[NOTICE] ". $message);
}
public function info($message){
$this->send(TextFormat::WHITE . "[INFO] ". $message);
}
public function debug($message){
$this->send(TextFormat::GRAY . "[DEBUG] ". $message);
}
public function log($level, $message){
switch($level){
case LogLevel::EMERGENCY:
$this->emergency($message);
break;
case LogLevel::ALERT:
$this->alert($message);
break;
case LogLevel::CRITICAL:
$this->critical($message);
break;
case LogLevel::ERROR:
$this->error($message);
break;
case LogLevel::WARNING:
$this->warning($message);
break;
case LogLevel::NOTICE:
$this->notice($message);
break;
case LogLevel::INFO:
$this->info($message);
break;
case LogLevel::DEBUG:
$this->debug($message);
break;
}
}
public function shutdown(){
$this->shutdown = true;
}
protected function send($message){
$now = time();
$message = TextFormat::toANSI(TextFormat::AQUA . date("H:i:s", $now) . TextFormat::RESET . " " . $message . TextFormat::RESET . PHP_EOL);
$cleanMessage = TextFormat::clean(preg_replace('/\x1b\[[0-9;]*m/', "", $message));
if(!$this->hasANSI){
echo $cleanMessage;
}else{
echo $message;
}
$this->logStream .= date("Y-m-d", $now) . " " . $cleanMessage;
}
public function run(){
$this->shutdown = false;
$this->logResource = fopen($this->logFile, "a+b");
if(!is_resource($this->logResource)){
throw new \RuntimeException("Couldn't open log file");
}
flock($this->logResource, LOCK_EX);
while($this->shutdown === false){
if(strlen($this->logStream) >= 4096){
$this->synchronized(function(){
$chunks = strlen($this->logStream) >> 12;
$chunk = substr($this->logStream, 0, $chunks << 12);
$this->logStream = substr($this->logStream, $chunks << 12);
fwrite($this->logResource, $chunk);
});
}else{
usleep(250000); //sleep for 0.25 seconds
}
}
if(strlen($this->logStream) > 0){
fwrite($this->logResource, $this->logStream);
}
flock($this->logResource, LOCK_UN);
fclose($this->logResource);
}
}