mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-05 11:27:07 +00:00
Removed ServerOld, ServerAPI
This commit is contained in:
parent
0f42cd9243
commit
95628227b0
@ -1262,6 +1262,51 @@ class Server{
|
||||
}
|
||||
|
||||
$this->enablePlugins(PluginLoadOrder::POSTWORLD);
|
||||
|
||||
/*
|
||||
//TODO
|
||||
if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){
|
||||
console("[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");
|
||||
if($this->server->version->isDev()){
|
||||
$info = json_decode(Utils::getURL("https://api.github.com/repos/PocketMine/PocketMine-MP/commits"), true);
|
||||
if($info === false or !isset($info[0])){
|
||||
console("[ERROR] Github API error");
|
||||
}else{
|
||||
$last = new \DateTime($info[0]["commit"]["committer"]["date"]);
|
||||
$last = $last->getTimestamp();
|
||||
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!");
|
||||
console("[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");
|
||||
console("[NOTICE] This message will disappear after issuing the command \"/update-done\"");
|
||||
}else{
|
||||
$this->setProperty("last-update", time());
|
||||
console("[INFO] " . TextFormat::AQUA . "This is the latest DEVELOPMENT version");
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$info = json_decode(Utils::getURL("https://api.github.com/repos/PocketMine/PocketMine-MP/tags"), true);
|
||||
if($info === false or !isset($info[0])){
|
||||
console("[ERROR] Github API error");
|
||||
}else{
|
||||
$newest = new VersionString(VERSION);
|
||||
$newestN = $newest->getNumber();
|
||||
$update = new VersionString($info[0]["name"]);
|
||||
$updateN = $update->getNumber();
|
||||
if($updateN > $newestN){
|
||||
console("[NOTICE] " . TextFormat::GREEN . "A new STABLE version of PocketMine-MP has been released!");
|
||||
console("[NOTICE] " . TextFormat::GREEN . "Version \"" . $info[0]["name"] . "\" #" . $updateN);
|
||||
console("[NOTICE] Get it at PocketMine.net or at " . $info[0]["zipball_url"]);
|
||||
console("[NOTICE] This message will disappear as soon as you update");
|
||||
}else{
|
||||
$this->setProperty("last-update", time());
|
||||
console("[INFO] " . TextFormat::AQUA . "This is the latest STABLE version");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1352,6 +1397,9 @@ class Server{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdowns the server correctly
|
||||
*/
|
||||
public function shutdown(){
|
||||
$this->isRunning = false;
|
||||
}
|
||||
@ -1382,16 +1430,15 @@ class Server{
|
||||
}
|
||||
|
||||
$this->tickCounter = 0;
|
||||
register_tick_function(array($this, "tick"));
|
||||
/*
|
||||
register_shutdown_function(array($this, "dumpError"));
|
||||
register_shutdown_function(array($this, "close"));
|
||||
|
||||
//register_shutdown_function(array($this, "dumpError"));
|
||||
register_shutdown_function(array($this, "shutdown"));
|
||||
if(function_exists("pcntl_signal")){
|
||||
//pcntl_signal(SIGTERM, array($this, "close"));
|
||||
pcntl_signal(SIGINT, array($this, "close"));
|
||||
pcntl_signal(SIGHUP, array($this, "close"));
|
||||
//pcntl_signal(SIGTERM, array($this, "shutdown"));
|
||||
pcntl_signal(SIGINT, array($this, "shutdown"));
|
||||
pcntl_signal(SIGHUP, array($this, "shutdown"));
|
||||
}
|
||||
*/
|
||||
|
||||
console("[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 "?"');
|
||||
@ -1452,6 +1499,107 @@ class Server{
|
||||
}
|
||||
}
|
||||
|
||||
public function checkTicks(){
|
||||
if($this->getTicksPerSecond() < 12){
|
||||
console("[WARNING] Can't keep up! Is the server overloaded?");
|
||||
}
|
||||
}
|
||||
|
||||
public function checkMemory(){
|
||||
//TODO
|
||||
$info = $this->debugInfo();
|
||||
$data = $info["memory_usage"] . "," . $info["players"] . "," . $info["entities"];
|
||||
$i = count($this->memoryStats) - 1;
|
||||
if($i < 0 or $this->memoryStats[$i] !== $data){
|
||||
$this->memoryStats[] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
public function dumpError(){
|
||||
//TODO
|
||||
if($this->stop === true){
|
||||
return;
|
||||
}
|
||||
ini_set("memory_limit", "-1"); //Fix error dump not dumped on memory problems
|
||||
console("[SEVERE] An unrecovereable has ocurred 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";
|
||||
$er = error_get_last();
|
||||
$errorConversion = array(
|
||||
E_ERROR => "E_ERROR",
|
||||
E_WARNING => "E_WARNING",
|
||||
E_PARSE => "E_PARSE",
|
||||
E_NOTICE => "E_NOTICE",
|
||||
E_CORE_ERROR => "E_CORE_ERROR",
|
||||
E_CORE_WARNING => "E_CORE_WARNING",
|
||||
E_COMPILE_ERROR => "E_COMPILE_ERROR",
|
||||
E_COMPILE_WARNING => "E_COMPILE_WARNING",
|
||||
E_USER_ERROR => "E_USER_ERROR",
|
||||
E_USER_WARNING => "E_USER_WARNING",
|
||||
E_USER_NOTICE => "E_USER_NOTICE",
|
||||
E_STRICT => "E_STRICT",
|
||||
E_RECOVERABLE_ERROR => "E_RECOVERABLE_ERROR",
|
||||
E_DEPRECATED => "E_DEPRECATED",
|
||||
E_USER_DEPRECATED => "E_USER_DEPRECATED",
|
||||
);
|
||||
$er["type"] = isset($errorConversion[$er["type"]]) ? $errorConversion[$er["type"]] : $er["type"];
|
||||
$dump .= "Error: " . var_export($er, true) . "\r\n\r\n";
|
||||
if(stripos($er["file"], "plugin") !== false){
|
||||
$dump .= "THIS ERROR WAS CAUSED BY A PLUGIN. REPORT IT TO THE PLUGIN DEVELOPER.\r\n";
|
||||
}
|
||||
|
||||
$dump .= "Code: \r\n";
|
||||
$file = @file($er["file"], FILE_IGNORE_NEW_LINES);
|
||||
for($l = max(0, $er["line"] - 10); $l < $er["line"] + 10; ++$l){
|
||||
$dump .= "[" . ($l + 1) . "] " . @$file[$l] . "\r\n";
|
||||
}
|
||||
$dump .= "\r\n\r\n";
|
||||
$dump .= "Backtrace: \r\n";
|
||||
foreach(getTrace() as $line){
|
||||
$dump .= "$line\r\n";
|
||||
}
|
||||
$dump .= "\r\n\r\n";
|
||||
$version = new VersionString();
|
||||
$dump .= "PocketMine-MP version: " . $version . " #" . $version->getNumber() . " [Protocol " . Info::CURRENT_PROTOCOL . "; API " . API_VERSION . "]\r\n";
|
||||
$dump .= "Git commit: " . GIT_COMMIT . "\r\n";
|
||||
$dump .= "uname -a: " . php_uname("a") . "\r\n";
|
||||
$dump .= "PHP Version: " . phpversion() . "\r\n";
|
||||
$dump .= "Zend version: " . zend_version() . "\r\n";
|
||||
$dump .= "OS : " . PHP_OS . ", " . Utils::getOS() . "\r\n";
|
||||
$dump .= "Debug Info: " . var_export($this->debugInfo(false), true) . "\r\n\r\n\r\n";
|
||||
global $arguments;
|
||||
$dump .= "Parameters: " . var_export($arguments, true) . "\r\n\r\n\r\n";
|
||||
$p = $this->api->getProperties();
|
||||
if($p["rcon.password"] != ""){
|
||||
$p["rcon.password"] = "******";
|
||||
}
|
||||
$dump .= "server.properties: " . var_export($p, true) . "\r\n\r\n\r\n";
|
||||
if(class_exists("pocketmine\\plugin\\PluginManager", false)){
|
||||
$dump .= "Loaded plugins:\r\n";
|
||||
foreach(PluginManager::getPlugins() as $p){
|
||||
$d = $p->getDescription();
|
||||
$dump .= $d->getName() . " " . $d->getVersion() . " by " . implode(", ", $d->getAuthors()) . "\r\n";
|
||||
}
|
||||
$dump .= "\r\n\r\n";
|
||||
}
|
||||
|
||||
$extensions = array();
|
||||
foreach(get_loaded_extensions() as $ext){
|
||||
$extensions[$ext] = phpversion($ext);
|
||||
}
|
||||
|
||||
$dump .= "Loaded Modules: " . var_export($extensions, true) . "\r\n";
|
||||
$this->checkMemory();
|
||||
$dump .= "Memory Usage Tracking: \r\n" . chunk_split(base64_encode(gzdeflate(implode(";", $this->memoryStats), 9))) . "\r\n";
|
||||
ob_start();
|
||||
phpinfo();
|
||||
$dump .= "\r\nphpinfo(): \r\n" . chunk_split(base64_encode(gzdeflate(ob_get_contents(), 9))) . "\r\n";
|
||||
ob_end_clean();
|
||||
$dump .= "\r\n```";
|
||||
$name = "Error_Dump_" . date("D_M_j-H.i.s-T_Y");
|
||||
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);
|
||||
}
|
||||
|
||||
private function tickProcessor(){
|
||||
$lastLoop = 0;
|
||||
while($this->isRunning){
|
||||
|
@ -1,363 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use pocketmine\network\query\QueryHandler;
|
||||
use pocketmine\network\rcon\RCON;
|
||||
use pocketmine\network\upnp\UPnP;
|
||||
use pocketmine\plugin\PluginManager;
|
||||
use pocketmine\utils\Config;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\VersionString;
|
||||
|
||||
class ServerAPI{
|
||||
public $restart = false;
|
||||
private static $serverRequest = false;
|
||||
private $asyncCalls = array();
|
||||
private $server;
|
||||
private $config;
|
||||
private $apiList = array();
|
||||
private $asyncCnt = 0;
|
||||
private $rcon;
|
||||
|
||||
public $query;
|
||||
|
||||
//TODO: Instead of hard-coding functions, use PHPDoc-compatible methods to load APIs.
|
||||
|
||||
/** @var ConsoleAPI */
|
||||
public $console;
|
||||
|
||||
/** @var LevelAPI */
|
||||
public $level;
|
||||
|
||||
/** @var BlockAPI */
|
||||
public $block;
|
||||
|
||||
/** @var ChatAPI */
|
||||
public $chat;
|
||||
|
||||
/** @var BanAPI */
|
||||
public $ban;
|
||||
|
||||
/** @var TimeAPI */
|
||||
public $time;
|
||||
|
||||
/** @var PlayerAPI */
|
||||
public $player;
|
||||
|
||||
/**
|
||||
* @return Server
|
||||
*/
|
||||
public static function request(){
|
||||
return self::$serverRequest;
|
||||
}
|
||||
|
||||
public function start(){
|
||||
return $this->run();
|
||||
}
|
||||
|
||||
public function run(){
|
||||
$this->load();
|
||||
|
||||
return $this->init();
|
||||
}
|
||||
|
||||
public function load(){
|
||||
@mkdir(\pocketmine\DATA . "players/", 0755);
|
||||
@mkdir(\pocketmine\DATA . "worlds/", 0755);
|
||||
@mkdir(\pocketmine\DATA . "plugins/", 0755);
|
||||
|
||||
$version = new VersionString();
|
||||
console("[INFO] Starting Minecraft: PE server version " . TextFormat::AQUA . MINECRAFT_VERSION);
|
||||
|
||||
console("[INFO] Loading properties...");
|
||||
$this->config = new Config(\pocketmine\DATA . "server.properties", Config::PROPERTIES, array(
|
||||
"server-name" => "Minecraft: PE Server",
|
||||
"description" => "Server made using PocketMine-MP",
|
||||
"motd" => "Welcome @player to this server!",
|
||||
"server-port" => 19132,
|
||||
"server-type" => "normal",
|
||||
"memory-limit" => "128M",
|
||||
"last-update" => false,
|
||||
"white-list" => false,
|
||||
"announce-player-achievements" => true,
|
||||
"spawn-protection" => 16,
|
||||
"view-distance" => 8,
|
||||
"max-players" => 20,
|
||||
"allow-flight" => false,
|
||||
"spawn-animals" => true,
|
||||
"spawn-mobs" => true,
|
||||
"gamemode" => 0,
|
||||
"hardcore" => false,
|
||||
"pvp" => true,
|
||||
"difficulty" => 1,
|
||||
"generator-settings" => "",
|
||||
"level-name" => "world",
|
||||
"level-seed" => "",
|
||||
"level-type" => "DEFAULT",
|
||||
"enable-query" => true,
|
||||
"enable-rcon" => false,
|
||||
"rcon.password" => substr(base64_encode(Utils::getRandomBytes(20, false)), 3, 10),
|
||||
"auto-save" => true,
|
||||
));
|
||||
|
||||
$this->parseProperties();
|
||||
|
||||
//Load advanced properties
|
||||
define("pocketmine\\DEBUG", $this->getProperty("debug", 1));
|
||||
define("ADVANCED_CACHE", $this->getProperty("enable-advanced-cache", false));
|
||||
define("MAX_CHUNK_RATE", 20 / $this->getProperty("max-chunks-per-second", 7)); //Default rate ~448 kB/s
|
||||
if(ADVANCED_CACHE == true){
|
||||
console("[INFO] Advanced cache enabled");
|
||||
}
|
||||
if($this->getProperty("upnp-forwarding") == true){
|
||||
console("[INFO] [UPnP] Trying to port forward...");
|
||||
UPnP::PortForward($this->getProperty("server-port"));
|
||||
}
|
||||
$this->server = new Server($this->getProperty("server-name"), $this->getProperty("gamemode"), ($seed = $this->getProperty("level-seed")) != "" ? (int) $seed : false, $this->getProperty("server-port"), ($ip = $this->getProperty("server-ip")) != "" ? $ip : "0.0.0.0");
|
||||
$this->server->api = $this;
|
||||
self::$serverRequest = $this->server;
|
||||
console("[INFO] This server is running PocketMine-MP version " . ($version->isDev() ? TextFormat::YELLOW : "") . VERSION . TextFormat::RESET . " \"" . CODENAME . "\" (API " . API_VERSION . ")", true, true, 0);
|
||||
console("[INFO] PocketMine-MP is distributed under the LGPL License", true, true, 0);
|
||||
|
||||
if($this->getProperty("last-update") === false or ($this->getProperty("last-update") + 3600) < time()){
|
||||
console("[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");
|
||||
if($this->server->version->isDev()){
|
||||
$info = json_decode(Utils::getURL("https://api.github.com/repos/PocketMine/PocketMine-MP/commits"), true);
|
||||
if($info === false or !isset($info[0])){
|
||||
console("[ERROR] Github API error");
|
||||
}else{
|
||||
$last = new \DateTime($info[0]["commit"]["committer"]["date"]);
|
||||
$last = $last->getTimestamp();
|
||||
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!");
|
||||
console("[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");
|
||||
console("[NOTICE] This message will disappear after issuing the command \"/update-done\"");
|
||||
}else{
|
||||
$this->setProperty("last-update", time());
|
||||
console("[INFO] " . TextFormat::AQUA . "This is the latest DEVELOPMENT version");
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$info = json_decode(Utils::getURL("https://api.github.com/repos/PocketMine/PocketMine-MP/tags"), true);
|
||||
if($info === false or !isset($info[0])){
|
||||
console("[ERROR] Github API error");
|
||||
}else{
|
||||
$newest = new VersionString(VERSION);
|
||||
$newestN = $newest->getNumber();
|
||||
$update = new VersionString($info[0]["name"]);
|
||||
$updateN = $update->getNumber();
|
||||
if($updateN > $newestN){
|
||||
console("[NOTICE] " . TextFormat::GREEN . "A new STABLE version of PocketMine-MP has been released!");
|
||||
console("[NOTICE] " . TextFormat::GREEN . "Version \"" . $info[0]["name"] . "\" #" . $updateN);
|
||||
console("[NOTICE] Get it at PocketMine.net or at " . $info[0]["zipball_url"]);
|
||||
console("[NOTICE] This message will disappear as soon as you update");
|
||||
}else{
|
||||
$this->setProperty("last-update", time());
|
||||
console("[INFO] " . TextFormat::AQUA . "This is the latest STABLE version");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->loadProperties();
|
||||
|
||||
|
||||
$this->apiList[] = $this->console = new ConsoleAPI();
|
||||
$this->apiList[] = $this->level = new LevelAPI();
|
||||
|
||||
$this->apiList[] = $this->block = new BlockAPI();
|
||||
$this->apiList[] = $this->chat = new ChatAPI();
|
||||
$this->apiList[] = $this->ban = new BanAPI();
|
||||
$this->apiList[] = $this->player = new PlayerAPI();
|
||||
$this->apiList[] = $this->time = new TimeAPI();
|
||||
|
||||
foreach($this->apiList as $ob){
|
||||
if(is_callable(array($ob, "init"))){
|
||||
$ob->init(); //Fails sometimes!!!
|
||||
}
|
||||
}
|
||||
|
||||
console("[INFO] Loaded " . count(PluginManager::loadPlugins(\pocketmine\DATA . "plugins/")) . " plugin(s).");
|
||||
|
||||
}
|
||||
|
||||
public function async(callable $callable, $params = array(), $remove = false){
|
||||
$cnt = $this->asyncCnt++;
|
||||
$this->asyncCalls[$cnt] = new \Async($callable, $params);
|
||||
|
||||
return $remove === true ? $this->getAsync($cnt) : $cnt;
|
||||
}
|
||||
|
||||
public function getAsync($id){
|
||||
if(!isset($this->asyncCalls[$id])){
|
||||
return false;
|
||||
}
|
||||
$ob = $this->asyncCalls[$id];
|
||||
unset($this->asyncCalls[$id]);
|
||||
|
||||
return $ob;
|
||||
}
|
||||
|
||||
public function __destruct(){
|
||||
foreach($this->apiList as $i => $ob){
|
||||
if(method_exists($ob, "__destruct")){
|
||||
$ob->__destruct();
|
||||
unset($this->apiList[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function writeProperties(){
|
||||
$this->config->save();
|
||||
}
|
||||
|
||||
public function init(){
|
||||
if(!(self::$serverRequest instanceof Server)){
|
||||
self::$serverRequest = $this->server;
|
||||
}
|
||||
|
||||
|
||||
if($this->getProperty("send-usage", true) !== false){
|
||||
$this->server->schedule(6000, array($this, "sendUsage"), array(), true); //Send the info after 5 minutes have passed
|
||||
$this->sendUsage();
|
||||
}
|
||||
if($this->getProperty("auto-save") === true){
|
||||
$this->server->schedule(18000, array($this, "autoSave"), array(), true);
|
||||
}
|
||||
if(!defined("NO_THREADS") and $this->getProperty("enable-rcon") === true){
|
||||
$this->rcon = new RCON($this->getProperty("rcon.password", ""), $this->getProperty("rcon.port", $this->getProperty("server-port")), ($ip = $this->getProperty("server-ip")) != "" ? $ip : "0.0.0.0", $this->getProperty("rcon.threads", 1), $this->getProperty("rcon.clients-per-thread", 50));
|
||||
}
|
||||
|
||||
if($this->getProperty("enable-query") === true){
|
||||
$this->query = new QueryHandler();
|
||||
}
|
||||
|
||||
$this->schedule(2, array($this, "checkTickUpdates"), array(), true);
|
||||
$this->server->init();
|
||||
unregister_tick_function(array($this->server, "tick"));
|
||||
$this->console->__destruct();
|
||||
if($this->rcon instanceof RCON){
|
||||
$this->rcon->stop();
|
||||
}
|
||||
$this->__destruct();
|
||||
if($this->getProperty("upnp-forwarding") === true){
|
||||
console("[INFO] [UPnP] Removing port forward...");
|
||||
UPnP::RemovePortForward($this->getProperty("server-port"));
|
||||
}
|
||||
|
||||
return $this->restart;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
public function asyncOperation($t, $d, $c = null){
|
||||
return $this->server->asyncOperation($t, $d, $c);
|
||||
}
|
||||
|
||||
public function addHandler($e, $c, $p = 5){
|
||||
return $this->server->addHandler($e, $c, $p);
|
||||
}
|
||||
|
||||
public function dhandle($e, $d){
|
||||
return $this->server->handle($e, $d);
|
||||
}
|
||||
|
||||
public function handle($e, &$d){
|
||||
return $this->server->handle($e, $d);
|
||||
}
|
||||
|
||||
public function schedule($t, $c, $d, $r = false, $e = "server.schedule"){
|
||||
return $this->server->schedule($t, $c, $d, $r, $e);
|
||||
}
|
||||
|
||||
public function event($e, $d){
|
||||
return $this->server->event($e, $d);
|
||||
}
|
||||
|
||||
public function trigger($e, $d){
|
||||
return $this->server->trigger($e, $d);
|
||||
}
|
||||
|
||||
public function deleteEvent($id){
|
||||
return $this->server->deleteEvent($id);
|
||||
}
|
||||
|
||||
public function getProperties(){
|
||||
return $this->config->getAll();
|
||||
}
|
||||
|
||||
public function getProperty($name, $default = false){
|
||||
$v = getopt("", array("$name::"));
|
||||
if(isset($v[$name]) !== false){ //Allow for command-line arguments
|
||||
$v = $v[$name];
|
||||
switch(strtolower(trim($v))){
|
||||
case "":
|
||||
case "on":
|
||||
case "true":
|
||||
case "yes":
|
||||
$v = true;
|
||||
break;
|
||||
case "off":
|
||||
case "false":
|
||||
case "no":
|
||||
$v = false;
|
||||
break;
|
||||
}
|
||||
switch($name){
|
||||
case "last-update":
|
||||
if($v === false){
|
||||
$v = time();
|
||||
}else{
|
||||
$v = (int) $v;
|
||||
}
|
||||
break;
|
||||
case "gamemode":
|
||||
case "max-players":
|
||||
case "server-port":
|
||||
case "debug":
|
||||
case "difficulty":
|
||||
$v = (int) $v;
|
||||
break;
|
||||
}
|
||||
|
||||
return $v;
|
||||
}
|
||||
|
||||
return ($this->config->exists($name) ? $this->config->get($name) : $default);
|
||||
}
|
||||
|
||||
public function setProperty($name, $value, $save = true){
|
||||
$this->config->set($name, $value);
|
||||
if($save == true){
|
||||
$this->writeProperties();
|
||||
}
|
||||
$this->loadProperties();
|
||||
}
|
||||
|
||||
public function getList(){
|
||||
return $this->apiList;
|
||||
}
|
||||
}
|
@ -1,735 +0,0 @@
|
||||
<?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/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* PocketMine-MP is the Minecraft: PE multiplayer server software
|
||||
* Homepage: http://www.pocketmine.net/
|
||||
*/
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\network\Packet;
|
||||
use pocketmine\network\protocol\Info;
|
||||
use pocketmine\network\raknet\Info as RakNetInfo;
|
||||
use pocketmine\network\raknet\Packet as RakNetPacket;
|
||||
use pocketmine\plugin\PluginManager;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\VersionString;
|
||||
|
||||
class ServerOld{
|
||||
/** @var Server */
|
||||
private static $instance;
|
||||
|
||||
public $tCnt;
|
||||
public $serverID;
|
||||
public $interface;
|
||||
public $database;
|
||||
public $version;
|
||||
public $invisible;
|
||||
public $tickMeasure;
|
||||
public $preparedSQL;
|
||||
public $spawn;
|
||||
public $whitelist;
|
||||
public $seed;
|
||||
public $stop;
|
||||
public $gamemode;
|
||||
public $difficulty;
|
||||
public $name;
|
||||
public $maxClients;
|
||||
public $eidCnt;
|
||||
public $custom;
|
||||
public $description;
|
||||
public $motd;
|
||||
public $port;
|
||||
public $saveEnabled;
|
||||
|
||||
private $rcon;
|
||||
private $query;
|
||||
|
||||
private $serverip;
|
||||
private $evCnt;
|
||||
private $handCnt;
|
||||
private $events;
|
||||
private $eventsID;
|
||||
private $handlers;
|
||||
private $serverType;
|
||||
private $lastTick;
|
||||
private $doTick;
|
||||
private $ticks;
|
||||
private $memoryStats;
|
||||
private $schedule;
|
||||
private $asyncThread;
|
||||
private $async = array();
|
||||
private $asyncID = 0;
|
||||
|
||||
/**
|
||||
* @return Server
|
||||
*/
|
||||
public static function getInstance(){
|
||||
if(isset(self::$instance)){
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function load(){
|
||||
$this->version = new VersionString();
|
||||
if(defined("pocketmine\\DEBUG") and \pocketmine\DEBUG >= 0 and function_exists("cli_set_process_title")){
|
||||
@cli_set_process_title("PocketMine-MP " . \pocketmine\VERSION);
|
||||
}
|
||||
console("[INFO] Starting Minecraft PE server on " . ($this->serverip === "0.0.0.0" ? "*" : $this->serverip) . ":" . $this->port);
|
||||
define("BOOTUP_RANDOM", Utils::getRandomBytes(16));
|
||||
$this->serverID = $this->serverID === false ? Utils::readLong(substr(Utils::getUniqueID(true, $this->serverip . $this->port), 8)) : $this->serverID;
|
||||
$this->seed = $this->seed === false ? Utils::readInt(Utils::getRandomBytes(4, false)) : $this->seed;
|
||||
$this->startDatabase();
|
||||
$this->api = false;
|
||||
$this->tCnt = 1;
|
||||
$this->events = array();
|
||||
$this->eventsID = array();
|
||||
$this->handlers = array();
|
||||
$this->invisible = false;
|
||||
$this->difficulty = 1;
|
||||
$this->custom = array();
|
||||
$this->evCnt = 1;
|
||||
$this->handCnt = 1;
|
||||
$this->eidCnt = 1;
|
||||
$this->maxClients = 20;
|
||||
$this->schedule = array();
|
||||
$this->scheduleCnt = 1;
|
||||
$this->description = "";
|
||||
$this->memoryStats = array();
|
||||
$this->spawn = false;
|
||||
$this->saveEnabled = true;
|
||||
$this->whitelist = false;
|
||||
$this->tickMeasure = array_fill(0, 40, 0);
|
||||
$this->setType("normal");
|
||||
$this->interface = new Handler("255.255.255.255", $this->port, $this->serverip);
|
||||
$this->stop = false;
|
||||
$this->ticks = 0;
|
||||
if(!defined("NO_THREADS")){
|
||||
$this->asyncThread = new \AsyncMultipleQueue();
|
||||
}
|
||||
}
|
||||
|
||||
function __construct($name, $gamemode = 0, $seed = false, $port = 19132, $serverip = "0.0.0.0"){
|
||||
$this->port = (int) $port;
|
||||
$this->doTick = true;
|
||||
$this->gamemode = (int) $gamemode;
|
||||
$this->name = $name;
|
||||
$this->motd = "Welcome to " . $name;
|
||||
$this->serverID = false;
|
||||
$this->seed = $seed;
|
||||
$this->serverip = $serverip;
|
||||
self::$instance = $this;
|
||||
$this->load();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getTPS(){
|
||||
$v = array_values($this->tickMeasure);
|
||||
$tps = 40 / ($v[39] - $v[0]);
|
||||
|
||||
return round($tps, 4);
|
||||
}
|
||||
|
||||
public function titleTick(){
|
||||
$time = microtime(true);
|
||||
if(defined("pocketmine\\DEBUG") and \pocketmine\DEBUG >= 0 and \pocketmine\ANSI === true){
|
||||
echo "\x1b]0;PocketMine-MP " . VERSION . " | Online " . count(Player::$list) . "/" . $this->maxClients . " | RAM " . round((memory_get_usage() / 1024) / 1024, 2) . "MB | U " . round(($this->interface->bandwidth[1] / max(1, $time - $this->interface->bandwidth[2])) / 1024, 2) . " D " . round(($this->interface->bandwidth[0] / max(1, $time - $this->interface->bandwidth[2])) / 1024, 2) . " kB/s | TPS " . $this->getTPS() . "\x07";
|
||||
}
|
||||
$this->interface->bandwidth = array(0, 0, $time);
|
||||
}
|
||||
|
||||
public function loadEvents(){
|
||||
if(\pocketmine\ANSI === true){
|
||||
$this->schedule(30, array($this, "titleTick"), array(), true);
|
||||
}
|
||||
$this->schedule(20 * 15, array($this, "checkTicks"), array(), true);
|
||||
$this->schedule(20 * 60, array($this, "checkMemory"), array(), true);
|
||||
$this->schedule(20 * 45, "pocketmine\\utils\\Cache::cleanup", array(), true);
|
||||
$this->schedule(20, array($this, "asyncOperationChecker"), array(), true);
|
||||
}
|
||||
|
||||
public function checkTicks(){
|
||||
if($this->getTPS() < 12){
|
||||
console("[WARNING] Can't keep up! Is the server overloaded?");
|
||||
}
|
||||
}
|
||||
|
||||
public function checkMemory(){
|
||||
$info = $this->debugInfo();
|
||||
$data = $info["memory_usage"] . "," . $info["players"] . "," . $info["entities"];
|
||||
$i = count($this->memoryStats) - 1;
|
||||
if($i < 0 or $this->memoryStats[$i] !== $data){
|
||||
$this->memoryStats[] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
public function startDatabase(){
|
||||
$this->preparedSQL = new \stdClass();
|
||||
$this->preparedSQL->entity = new \stdClass();
|
||||
$this->database = new \SQLite3(":memory:", SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE);
|
||||
$this->query("PRAGMA journal_mode = OFF;");
|
||||
$this->query("PRAGMA encoding = \"UTF-8\";");
|
||||
$this->query("PRAGMA secure_delete = OFF;");
|
||||
$this->query("CREATE TABLE actions (ID INTEGER PRIMARY KEY, interval NUMERIC, last NUMERIC, code TEXT, repeat NUMERIC);");
|
||||
$this->query("CREATE TABLE handlers (ID INTEGER PRIMARY KEY, name TEXT, priority NUMERIC);");
|
||||
$this->query("CREATE TABLE blockUpdates (level TEXT, x INTEGER, y INTEGER, z INTEGER, type INTEGER, delay NUMERIC);");
|
||||
$this->query("CREATE TABLE recipes (id INTEGER PRIMARY KEY, type NUMERIC, recipe TEXT);");
|
||||
$this->query("PRAGMA synchronous = OFF;");
|
||||
$this->preparedSQL->selectHandlers = $this->database->prepare("SELECT DISTINCT ID FROM handlers WHERE name = :name ORDER BY priority DESC;");
|
||||
$this->preparedSQL->selectActions = $this->database->prepare("SELECT ID,code,repeat FROM actions WHERE last <= (:time - interval);");
|
||||
$this->preparedSQL->updateAction = $this->database->prepare("UPDATE actions SET last = :time WHERE ID = :id;");
|
||||
}
|
||||
|
||||
public function query($sql, $fetch = false){
|
||||
$result = $this->database->query($sql) or console("[ERROR] [SQL Error] " . $this->database->lastErrorMsg() . ". Query: " . $sql, true, true, 0);
|
||||
if($fetch === true and ($result instanceof \SQLite3Result)){
|
||||
$result = $result->fetchArray(SQLITE3_ASSOC);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function debugInfo($console = false){
|
||||
$info = array();
|
||||
$info["tps"] = $this->getTPS();
|
||||
$info["memory_usage"] = round((memory_get_usage() / 1024) / 1024, 2) . "MB";
|
||||
$info["memory_peak_usage"] = round((memory_get_peak_usage() / 1024) / 1024, 2) . "MB";
|
||||
$info["entities"] = count(Entity::$list);
|
||||
$info["players"] = count(Player::$list);
|
||||
$info["events"] = count($this->eventsID);
|
||||
$info["handlers"] = $this->query("SELECT count(ID) as count FROM handlers;", true);
|
||||
$info["handlers"] = $info["handlers"]["count"];
|
||||
$info["actions"] = $this->query("SELECT count(ID) as count FROM actions;", true);
|
||||
$info["actions"] = $info["actions"]["count"];
|
||||
$info["garbage"] = gc_collect_cycles();
|
||||
$this->handle("server.debug", $info);
|
||||
if($console === true){
|
||||
console("[DEBUG] TPS: " . $info["tps"] . ", Memory usage: " . $info["memory_usage"] . " (Peak " . $info["memory_peak_usage"] . "), Entities: " . $info["entities"] . ", Events: " . $info["events"] . ", Handlers: " . $info["handlers"] . ", Actions: " . $info["actions"] . ", Garbage: " . $info["garbage"], true, true, 2);
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $reason
|
||||
*/
|
||||
public function close($reason = "server stop"){
|
||||
if($this->stop !== true){
|
||||
if(is_int($reason)){
|
||||
$reason = "signal stop";
|
||||
}
|
||||
if(($this->api instanceof ServerAPI) === true){
|
||||
if(($this->api->chat instanceof ChatAPI) === true){
|
||||
Player::broadcastMessage("Stopping server...");
|
||||
}
|
||||
}
|
||||
$this->stop = true;
|
||||
$this->trigger("server.close", $reason);
|
||||
$this->interface->close();
|
||||
|
||||
if(!defined("NO_THREADS")){
|
||||
@$this->asyncThread->stop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setType($type = "normal"){
|
||||
switch(trim(strtolower($type))){
|
||||
case "normal":
|
||||
case "demo":
|
||||
$this->serverType = "MCCPP;Demo;";
|
||||
break;
|
||||
case "minecon":
|
||||
$this->serverType = "MCCPP;MINECON;";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function asyncOperation($type, array $data, callable $callable = null){
|
||||
if(defined("NO_THREADS")){
|
||||
return false;
|
||||
}
|
||||
$d = "";
|
||||
$type = (int) $type;
|
||||
switch($type){
|
||||
case ASYNC_CURL_GET:
|
||||
$d .= Utils::writeShort(strlen($data["url"])) . $data["url"] . (isset($data["timeout"]) ? Utils::writeShort($data["timeout"]) : Utils::writeShort(10));
|
||||
break;
|
||||
case ASYNC_CURL_POST:
|
||||
$d .= Utils::writeShort(strlen($data["url"])) . $data["url"] . (isset($data["timeout"]) ? Utils::writeShort($data["timeout"]) : Utils::writeShort(10));
|
||||
$d .= Utils::writeShort(count($data["data"]));
|
||||
foreach($data["data"] as $key => $value){
|
||||
$d .= Utils::writeShort(strlen($key)) . $key . Utils::writeInt(strlen($value)) . $value;
|
||||
}
|
||||
break;
|
||||
case ASYNC_FUNCTION:
|
||||
$params = serialize($data["arguments"]);
|
||||
$d .= Utils::writeShort(strlen($data["function"])) . $data["function"] . Utils::writeInt(strlen($params)) . $params;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
$ID = $this->asyncID++;
|
||||
$this->async[$ID] = $callable;
|
||||
$this->asyncThread->input .= Utils::writeInt($ID) . Utils::writeShort($type) . $d;
|
||||
|
||||
return $ID;
|
||||
}
|
||||
|
||||
public function asyncOperationChecker(){
|
||||
if(defined("NO_THREADS")){
|
||||
return false;
|
||||
}
|
||||
if(isset($this->asyncThread->output{5})){
|
||||
$offset = 0;
|
||||
$ID = Utils::readInt(substr($this->asyncThread->output, $offset, 4));
|
||||
$offset += 4;
|
||||
$type = Utils::readShort(substr($this->asyncThread->output, $offset, 2));
|
||||
$offset += 2;
|
||||
$data = array();
|
||||
switch($type){
|
||||
case ASYNC_CURL_GET:
|
||||
case ASYNC_CURL_POST:
|
||||
$len = Utils::readInt(substr($this->asyncThread->output, $offset, 4));
|
||||
$offset += 4;
|
||||
$data["result"] = substr($this->asyncThread->output, $offset, $len);
|
||||
$offset += $len;
|
||||
break;
|
||||
case ASYNC_FUNCTION:
|
||||
$len = Utils::readInt(substr($this->asyncThread->output, $offset, 4));
|
||||
$offset += 4;
|
||||
$data["result"] = unserialize(substr($this->asyncThread->output, $offset, $len));
|
||||
$offset += $len;
|
||||
break;
|
||||
}
|
||||
$this->asyncThread->output = substr($this->asyncThread->output, $offset);
|
||||
if(isset($this->async[$ID]) and $this->async[$ID] !== null and is_callable($this->async[$ID])){
|
||||
if(is_array($this->async[$ID])){
|
||||
$method = $this->async[$ID][1];
|
||||
$result = $this->async[$ID][0]->$method($data, $type, $ID);
|
||||
}else{
|
||||
$result = $this->async[$ID]($data, $type, $ID);
|
||||
}
|
||||
}
|
||||
unset($this->async[$ID]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $event
|
||||
* @param callable $callable
|
||||
* @param integer $priority
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function addHandler($event, callable $callable, $priority = 5){
|
||||
if(!is_callable($callable)){
|
||||
return false;
|
||||
}
|
||||
$priority = (int) $priority;
|
||||
$hnid = $this->handCnt++;
|
||||
$this->handlers[$hnid] = $callable;
|
||||
$this->query("INSERT INTO handlers (ID, name, priority) VALUES (" . $hnid . ", '" . str_replace("'", "\\'", $event) . "', " . $priority . ");");
|
||||
console("[INTERNAL] New handler " . (is_array($callable) ? get_class($callable[0]) . "::" . $callable[1] : $callable) . " to special event " . $event . " (ID " . $hnid . ")", true, true, 3);
|
||||
|
||||
return $hnid;
|
||||
}
|
||||
|
||||
public function dhandle($e, $d){
|
||||
return $this->handle($e, $d);
|
||||
}
|
||||
|
||||
public function handle($event, &$data){
|
||||
$this->preparedSQL->selectHandlers->reset();
|
||||
$this->preparedSQL->selectHandlers->clear();
|
||||
$this->preparedSQL->selectHandlers->bindValue(":name", $event, SQLITE3_TEXT);
|
||||
$handlers = $this->preparedSQL->selectHandlers->execute();
|
||||
$result = null;
|
||||
if($handlers instanceof \SQLite3Result){
|
||||
$call = array();
|
||||
while(($hn = $handlers->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
$call[(int) $hn["ID"]] = true;
|
||||
}
|
||||
$handlers->finalize();
|
||||
foreach($call as $hnid => $boolean){
|
||||
if($result !== false and $result !== true){
|
||||
$handler = $this->handlers[$hnid];
|
||||
if(is_array($handler)){
|
||||
$method = $handler[1];
|
||||
$result = $handler[0]->$method($data, $event);
|
||||
}else{
|
||||
$result = $handler($data, $event);
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($result !== false){
|
||||
$this->trigger($event, $data);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function eventHandler($data, $event){
|
||||
switch($event){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @return string
|
||||
*/
|
||||
public function getGamemode(){
|
||||
switch($this->gamemode){
|
||||
case 0:
|
||||
return "survival";
|
||||
case 1:
|
||||
return "creative";
|
||||
case 2:
|
||||
return "adventure";
|
||||
case 3:
|
||||
return "view";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function init(){
|
||||
register_tick_function(array($this, "tick"));
|
||||
declare(ticks = 5000); //Minimum TPS for main thread locks
|
||||
|
||||
$this->loadEvents();
|
||||
register_shutdown_function(array($this, "dumpError"));
|
||||
register_shutdown_function(array($this, "close"));
|
||||
if(function_exists("pcntl_signal")){
|
||||
pcntl_signal(SIGTERM, array($this, "close"));
|
||||
pcntl_signal(SIGINT, array($this, "close"));
|
||||
pcntl_signal(SIGHUP, array($this, "close"));
|
||||
}
|
||||
console("[INFO] Default game type: " . strtoupper($this->getGamemode()));
|
||||
$this->trigger("server.start", microtime(true));
|
||||
console('[INFO] Done (' . round(microtime(true) - \pocketmine\START_TIME, 3) . 's)! For help, type "help" or "?"');
|
||||
$this->process();
|
||||
}
|
||||
|
||||
public function dumpError(){
|
||||
if($this->stop === true){
|
||||
return;
|
||||
}
|
||||
ini_set("memory_limit", "-1"); //Fix error dump not dumped on memory problems
|
||||
console("[SEVERE] An unrecovereable has ocurred 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";
|
||||
$er = error_get_last();
|
||||
$errorConversion = array(
|
||||
E_ERROR => "E_ERROR",
|
||||
E_WARNING => "E_WARNING",
|
||||
E_PARSE => "E_PARSE",
|
||||
E_NOTICE => "E_NOTICE",
|
||||
E_CORE_ERROR => "E_CORE_ERROR",
|
||||
E_CORE_WARNING => "E_CORE_WARNING",
|
||||
E_COMPILE_ERROR => "E_COMPILE_ERROR",
|
||||
E_COMPILE_WARNING => "E_COMPILE_WARNING",
|
||||
E_USER_ERROR => "E_USER_ERROR",
|
||||
E_USER_WARNING => "E_USER_WARNING",
|
||||
E_USER_NOTICE => "E_USER_NOTICE",
|
||||
E_STRICT => "E_STRICT",
|
||||
E_RECOVERABLE_ERROR => "E_RECOVERABLE_ERROR",
|
||||
E_DEPRECATED => "E_DEPRECATED",
|
||||
E_USER_DEPRECATED => "E_USER_DEPRECATED",
|
||||
);
|
||||
$er["type"] = isset($errorConversion[$er["type"]]) ? $errorConversion[$er["type"]] : $er["type"];
|
||||
$dump .= "Error: " . var_export($er, true) . "\r\n\r\n";
|
||||
if(stripos($er["file"], "plugin") !== false){
|
||||
$dump .= "THIS ERROR WAS CAUSED BY A PLUGIN. REPORT IT TO THE PLUGIN DEVELOPER.\r\n";
|
||||
}
|
||||
|
||||
$dump .= "Code: \r\n";
|
||||
$file = @file($er["file"], FILE_IGNORE_NEW_LINES);
|
||||
for($l = max(0, $er["line"] - 10); $l < $er["line"] + 10; ++$l){
|
||||
$dump .= "[" . ($l + 1) . "] " . @$file[$l] . "\r\n";
|
||||
}
|
||||
$dump .= "\r\n\r\n";
|
||||
$dump .= "Backtrace: \r\n";
|
||||
foreach(getTrace() as $line){
|
||||
$dump .= "$line\r\n";
|
||||
}
|
||||
$dump .= "\r\n\r\n";
|
||||
$version = new VersionString();
|
||||
$dump .= "PocketMine-MP version: " . $version . " #" . $version->getNumber() . " [Protocol " . Info::CURRENT_PROTOCOL . "; API " . API_VERSION . "]\r\n";
|
||||
$dump .= "Git commit: " . GIT_COMMIT . "\r\n";
|
||||
$dump .= "uname -a: " . php_uname("a") . "\r\n";
|
||||
$dump .= "PHP Version: " . phpversion() . "\r\n";
|
||||
$dump .= "Zend version: " . zend_version() . "\r\n";
|
||||
$dump .= "OS : " . PHP_OS . ", " . Utils::getOS() . "\r\n";
|
||||
$dump .= "Debug Info: " . var_export($this->debugInfo(false), true) . "\r\n\r\n\r\n";
|
||||
global $arguments;
|
||||
$dump .= "Parameters: " . var_export($arguments, true) . "\r\n\r\n\r\n";
|
||||
$p = $this->api->getProperties();
|
||||
if($p["rcon.password"] != ""){
|
||||
$p["rcon.password"] = "******";
|
||||
}
|
||||
$dump .= "server.properties: " . var_export($p, true) . "\r\n\r\n\r\n";
|
||||
if(class_exists("pocketmine\\plugin\\PluginManager", false)){
|
||||
$dump .= "Loaded plugins:\r\n";
|
||||
foreach(PluginManager::getPlugins() as $p){
|
||||
$d = $p->getDescription();
|
||||
$dump .= $d->getName() . " " . $d->getVersion() . " by " . implode(", ", $d->getAuthors()) . "\r\n";
|
||||
}
|
||||
$dump .= "\r\n\r\n";
|
||||
}
|
||||
|
||||
$extensions = array();
|
||||
foreach(get_loaded_extensions() as $ext){
|
||||
$extensions[$ext] = phpversion($ext);
|
||||
}
|
||||
|
||||
$dump .= "Loaded Modules: " . var_export($extensions, true) . "\r\n";
|
||||
$this->checkMemory();
|
||||
$dump .= "Memory Usage Tracking: \r\n" . chunk_split(base64_encode(gzdeflate(implode(";", $this->memoryStats), 9))) . "\r\n";
|
||||
ob_start();
|
||||
phpinfo();
|
||||
$dump .= "\r\nphpinfo(): \r\n" . chunk_split(base64_encode(gzdeflate(ob_get_contents(), 9))) . "\r\n";
|
||||
ob_end_clean();
|
||||
$dump .= "\r\n```";
|
||||
$name = "Error_Dump_" . date("D_M_j-H.i.s-T_Y");
|
||||
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);
|
||||
}
|
||||
|
||||
public function tick(){
|
||||
$time = microtime(true);
|
||||
if($this->lastTick <= ($time - 0.05)){
|
||||
$this->tickMeasure[] = $this->lastTick = $time;
|
||||
unset($this->tickMeasure[key($this->tickMeasure)]);
|
||||
++$this->ticks;
|
||||
|
||||
return $this->tickerFunction($time);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function clientID($ip, $port){
|
||||
return crc32($ip . $port) ^ crc32($port . $ip . BOOTUP_RANDOM);
|
||||
//return $ip . ":" . $port;
|
||||
}
|
||||
|
||||
public function packetHandler(Packet $packet){
|
||||
$data =& $packet;
|
||||
$CID = Server::clientID($packet->ip, $packet->port);
|
||||
if(isset(Player::$list[$CID])){
|
||||
if($packet instanceof RakNetPacket){
|
||||
Player::$list[$CID]->handlePacket($packet);
|
||||
}
|
||||
}else{
|
||||
switch($packet->pid()){
|
||||
case RakNetInfo::UNCONNECTED_PING:
|
||||
case RakNetInfo::UNCONNECTED_PING_OPEN_CONNECTIONS:
|
||||
if($this->invisible === true){
|
||||
$pk = new RakNetPacket(RakNetInfo::UNCONNECTED_PONG);
|
||||
$pk->pingID = $packet->pingID;
|
||||
$pk->serverID = $this->serverID;
|
||||
$pk->serverType = $this->serverType;
|
||||
$pk->ip = $packet->ip;
|
||||
$pk->port = $packet->port;
|
||||
$this->send($pk);
|
||||
break;
|
||||
}
|
||||
if(!isset($this->custom["times_" . $CID])){
|
||||
$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));
|
||||
$pk = new RakNetPacket(RakNetInfo::UNCONNECTED_PONG);
|
||||
$pk->pingID = $packet->pingID;
|
||||
$pk->serverID = $this->serverID;
|
||||
$pk->serverType = $this->serverType . $this->name . " [" . count(Player::$list) . "/" . $this->maxClients . "] " . $txt;
|
||||
$pk->ip = $packet->ip;
|
||||
$pk->port = $packet->port;
|
||||
$this->send($pk);
|
||||
$this->custom["times_" . $CID] = ($this->custom["times_" . $CID] + 1) % strlen($this->description);
|
||||
break;
|
||||
case RakNetInfo::OPEN_CONNECTION_REQUEST_1:
|
||||
if($packet->structure !== RakNetInfo::STRUCTURE){
|
||||
console("[DEBUG] Incorrect structure #" . $packet->structure . " from " . $packet->ip . ":" . $packet->port, true, true, 2);
|
||||
$pk = new RakNetPacket(RakNetInfo::INCOMPATIBLE_PROTOCOL_VERSION);
|
||||
$pk->serverID = $this->serverID;
|
||||
$pk->ip = $packet->ip;
|
||||
$pk->port = $packet->port;
|
||||
$this->send($pk);
|
||||
}else{
|
||||
$pk = new RakNetPacket(RakNetInfo::OPEN_CONNECTION_REPLY_1);
|
||||
$pk->serverID = $this->serverID;
|
||||
$pk->mtuSize = strlen($packet->buffer);
|
||||
$pk->ip = $packet->ip;
|
||||
$pk->port = $packet->port;
|
||||
$this->send($pk);
|
||||
}
|
||||
break;
|
||||
case RakNetInfo::OPEN_CONNECTION_REQUEST_2:
|
||||
if($this->invisible === true){
|
||||
break;
|
||||
}
|
||||
|
||||
new Player($packet->clientID, $packet->ip, $packet->port, $packet->mtuSize); //New Session!
|
||||
$pk = new RakNetPacket(RakNetInfo::OPEN_CONNECTION_REPLY_2);
|
||||
$pk->serverID = $this->serverID;
|
||||
$pk->serverPort = $this->port;
|
||||
$pk->mtuSize = $packet->mtuSize;
|
||||
$pk->ip = $packet->ip;
|
||||
$pk->port = $packet->port;
|
||||
$this->send($pk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function send(Packet $packet){
|
||||
return $this->interface->writePacket($packet);
|
||||
}
|
||||
|
||||
public function process(){
|
||||
$lastLoop = 0;
|
||||
while($this->stop === false){
|
||||
$packet = $this->interface->readPacket();
|
||||
if($packet instanceof Packet){
|
||||
$this->packetHandler($packet);
|
||||
$lastLoop = 0;
|
||||
}
|
||||
if(($ticks = $this->tick()) === 0){
|
||||
++$lastLoop;
|
||||
if($lastLoop < 16){
|
||||
usleep(1);
|
||||
}elseif($lastLoop < 128){
|
||||
usleep(1000);
|
||||
}elseif($lastLoop < 256){
|
||||
usleep(2000);
|
||||
}else{
|
||||
usleep(4000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function trigger($event, $data = ""){
|
||||
if(isset($this->events[$event])){
|
||||
foreach($this->events[$event] as $evid => $ev){
|
||||
if(!is_callable($ev)){
|
||||
$this->deleteEvent($evid);
|
||||
continue;
|
||||
}
|
||||
if(is_array($ev)){
|
||||
$method = $ev[1];
|
||||
$ev[0]->$method($data, $event);
|
||||
}else{
|
||||
$ev($data, $event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function schedule($ticks, callable $callback, $data = array(), $repeat = false, $eventName = "server.schedule"){
|
||||
if(!is_callable($callback)){
|
||||
return false;
|
||||
}
|
||||
$chcnt = $this->scheduleCnt++;
|
||||
$this->schedule[$chcnt] = array($callback, $data, $eventName);
|
||||
$this->query("INSERT INTO actions (ID, interval, last, repeat) VALUES(" . $chcnt . ", " . ($ticks / 20) . ", " . microtime(true) . ", " . (((bool) $repeat) === true ? 1 : 0) . ");");
|
||||
|
||||
return $chcnt;
|
||||
}
|
||||
|
||||
public function tickerFunction($time){
|
||||
//actions that repeat every x time will go here
|
||||
$this->preparedSQL->selectActions->reset();
|
||||
$this->preparedSQL->selectActions->bindValue(":time", $time, SQLITE3_FLOAT);
|
||||
$actions = $this->preparedSQL->selectActions->execute();
|
||||
|
||||
$actionCount = 0;
|
||||
if($actions instanceof \SQLite3Result){
|
||||
while(($action = $actions->fetchArray(SQLITE3_ASSOC)) !== false){
|
||||
$cid = $action["ID"];
|
||||
$this->preparedSQL->updateAction->reset();
|
||||
$this->preparedSQL->updateAction->bindValue(":time", $time, SQLITE3_FLOAT);
|
||||
$this->preparedSQL->updateAction->bindValue(":id", $cid, SQLITE3_INTEGER);
|
||||
$this->preparedSQL->updateAction->execute();
|
||||
if(!@is_callable($this->schedule[$cid][0])){
|
||||
$return = false;
|
||||
}else{
|
||||
++$actionCount;
|
||||
$return = call_user_func($this->schedule[$cid][0], $this->schedule[$cid][1], $this->schedule[$cid][2]);
|
||||
}
|
||||
|
||||
if($action["repeat"] == 0 or $return === false){
|
||||
$this->query("DELETE FROM actions WHERE ID = " . $action["ID"] . ";");
|
||||
$this->schedule[$cid] = null;
|
||||
unset($this->schedule[$cid]);
|
||||
}
|
||||
}
|
||||
$actions->finalize();
|
||||
}
|
||||
|
||||
return $actionCount;
|
||||
}
|
||||
|
||||
public function event($event, callable $func){
|
||||
if(!is_callable($func)){
|
||||
return false;
|
||||
}
|
||||
$evid = $this->evCnt++;
|
||||
if(!isset($this->events[$event])){
|
||||
$this->events[$event] = array();
|
||||
}
|
||||
$this->events[$event][$evid] = $func;
|
||||
$this->eventsID[$evid] = $event;
|
||||
console("[INTERNAL] Attached " . (is_array($func) ? get_class($func[0]) . "::" . $func[1] : $func) . " to event " . $event . " (ID " . $evid . ")", true, true, 3);
|
||||
|
||||
return $evid;
|
||||
}
|
||||
|
||||
public function deleteEvent($id){
|
||||
$id = (int) $id;
|
||||
if(isset($this->eventsID[$id])){
|
||||
$ev = $this->eventsID[$id];
|
||||
$this->eventsID[$id] = null;
|
||||
unset($this->eventsID[$id]);
|
||||
$this->events[$ev][$id] = null;
|
||||
unset($this->events[$ev][$id]);
|
||||
if(count($this->events[$ev]) === 0){
|
||||
unset($this->events[$ev]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user