From a8359f29a81a9cc6836b14535a3256f06853482b Mon Sep 17 00:00:00 2001 From: williamtdr Date: Fri, 11 Jul 2014 09:07:24 -0500 Subject: [PATCH 01/18] Fix #1615 Players in creative cannot die from non-magic (plugin/console) causes. --- src/pocketmine/entity/Living.php | 123 ++++++++++++++++--------------- 1 file changed, 63 insertions(+), 60 deletions(-) diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index 27bba8bcc..93347507c 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -34,73 +34,76 @@ use pocketmine\item\Item; abstract class Living extends Entity implements Damageable{ - protected $gravity = 0.08; - protected $drag = 0.02; + protected $gravity = 0.08; + protected $drag = 0.02; - protected function initEntity(){ - if(isset($this->namedtag->HealF)){ - $this->namedtag->Health = new Short("Health", (int) $this->namedtag["HealF"]); - unset($this->namedtag->HealF); - } + protected function initEntity(){ + if(isset($this->namedtag->HealF)){ + $this->namedtag->Health = new Short("Health", (int) $this->namedtag["HealF"]); + unset($this->namedtag->HealF); + } - if(!isset($this->namedtag->Health) or !($this->namedtag->Health instanceof Short)){ - $this->namedtag->Health = new Short("Health", $this->getMaxHealth()); - } + if(!isset($this->namedtag->Health) or !($this->namedtag->Health instanceof Short)){ + $this->namedtag->Health = new Short("Health", $this->getMaxHealth()); + } - $this->setHealth($this->namedtag["Health"]); - } + $this->setHealth($this->namedtag["Health"]); + } - public function saveNBT(){ - parent::saveNBT(); - $this->namedtag->Health = new Short("Health", $this->getHealth()); - } + public function saveNBT(){ + parent::saveNBT(); + $this->namedtag->Health = new Short("Health", $this->getHealth()); + } - public abstract function getName(); + public abstract function getName(); - public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){ - //TODO: attack tick limit - $pk = new EntityEventPacket(); - $pk->eid = $this->getID(); - $pk->event = 2; //Ouch! - Server::broadcastPacket($this->hasSpawned, $pk); - $this->setLastDamageCause($source); - $motion = new Vector3(0, 0, 0); - if($source instanceof EntityDamageByEntityEvent){ - $e = $source->getDamager(); - $deltaX = $this->x - $e->x; - $deltaZ = $this->z - $e->z; - $yaw = atan2($deltaX, $deltaZ); - $motion->x = sin($yaw) * 0.5; - $motion->z = cos($yaw) * 0.5; - } - $this->setMotion($motion); - $this->setHealth($this->getHealth() - $damage); + public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){ + //TODO: attack tick limit + if($this instanceof Player && $this->getGamemode() === 1 && $source != EntityDamageEvent::CAUSE_MAGIC) { + return; + } + $pk = new EntityEventPacket(); + $pk->eid = $this->getID(); + $pk->event = 2; //Ouch! + Server::broadcastPacket($this->hasSpawned, $pk); + $this->setLastDamageCause($source); + $motion = new Vector3(0, 0, 0); + if($source instanceof EntityDamageByEntityEvent){ + $e = $source->getDamager(); + $deltaX = $this->x - $e->x; + $deltaZ = $this->z - $e->z; + $yaw = atan2($deltaX, $deltaZ); + $motion->x = sin($yaw) * 0.5; + $motion->z = cos($yaw) * 0.5; + } + $this->setMotion($motion); + $this->setHealth($this->getHealth() - $damage); - } + } - public function heal($amount){ - $this->server->getPluginManager()->callEvent($ev = new EntityRegainHealthEvent($this, $amount)); - if($ev->isCancelled()){ - return; - } - $this->setHealth($this->getHealth() + $amount); - } + public function heal($amount){ + $this->server->getPluginManager()->callEvent($ev = new EntityRegainHealthEvent($this, $amount)); + if($ev->isCancelled()){ + return; + } + $this->setHealth($this->getHealth() + $amount); + } - public function kill(){ - if($this->dead){ - return; - } - parent::kill(); - $this->server->getPluginManager()->callEvent($ev = new EntityDeathEvent($this, $this->getDrops())); - foreach($ev->getDrops() as $item){ - $this->getLevel()->dropItem($this, $item); - } - } + public function kill(){ + if($this->dead){ + return; + } + parent::kill(); + $this->server->getPluginManager()->callEvent($ev = new EntityDeathEvent($this, $this->getDrops())); + foreach($ev->getDrops() as $item){ + $this->getLevel()->dropItem($this, $item); + } + } - /** - * @return Item[] - */ - public function getDrops(){ - return []; - } -} \ No newline at end of file + /** + * @return Item[] + */ + public function getDrops(){ + return []; + } +} From 3e882ef40d5dc8d69bc7027497bcc08740a2c29c Mon Sep 17 00:00:00 2001 From: williamtdr Date: Fri, 11 Jul 2014 09:12:19 -0500 Subject: [PATCH 02/18] Revert "Fix #1615" This reverts commit a8359f29a81a9cc6836b14535a3256f06853482b. --- src/pocketmine/entity/Living.php | 123 +++++++++++++++---------------- 1 file changed, 60 insertions(+), 63 deletions(-) diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index 93347507c..27bba8bcc 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -34,76 +34,73 @@ use pocketmine\item\Item; abstract class Living extends Entity implements Damageable{ - protected $gravity = 0.08; - protected $drag = 0.02; + protected $gravity = 0.08; + protected $drag = 0.02; - protected function initEntity(){ - if(isset($this->namedtag->HealF)){ - $this->namedtag->Health = new Short("Health", (int) $this->namedtag["HealF"]); - unset($this->namedtag->HealF); - } + protected function initEntity(){ + if(isset($this->namedtag->HealF)){ + $this->namedtag->Health = new Short("Health", (int) $this->namedtag["HealF"]); + unset($this->namedtag->HealF); + } - if(!isset($this->namedtag->Health) or !($this->namedtag->Health instanceof Short)){ - $this->namedtag->Health = new Short("Health", $this->getMaxHealth()); - } + if(!isset($this->namedtag->Health) or !($this->namedtag->Health instanceof Short)){ + $this->namedtag->Health = new Short("Health", $this->getMaxHealth()); + } - $this->setHealth($this->namedtag["Health"]); - } + $this->setHealth($this->namedtag["Health"]); + } - public function saveNBT(){ - parent::saveNBT(); - $this->namedtag->Health = new Short("Health", $this->getHealth()); - } + public function saveNBT(){ + parent::saveNBT(); + $this->namedtag->Health = new Short("Health", $this->getHealth()); + } - public abstract function getName(); + public abstract function getName(); - public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){ - //TODO: attack tick limit - if($this instanceof Player && $this->getGamemode() === 1 && $source != EntityDamageEvent::CAUSE_MAGIC) { - return; - } - $pk = new EntityEventPacket(); - $pk->eid = $this->getID(); - $pk->event = 2; //Ouch! - Server::broadcastPacket($this->hasSpawned, $pk); - $this->setLastDamageCause($source); - $motion = new Vector3(0, 0, 0); - if($source instanceof EntityDamageByEntityEvent){ - $e = $source->getDamager(); - $deltaX = $this->x - $e->x; - $deltaZ = $this->z - $e->z; - $yaw = atan2($deltaX, $deltaZ); - $motion->x = sin($yaw) * 0.5; - $motion->z = cos($yaw) * 0.5; - } - $this->setMotion($motion); - $this->setHealth($this->getHealth() - $damage); + public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){ + //TODO: attack tick limit + $pk = new EntityEventPacket(); + $pk->eid = $this->getID(); + $pk->event = 2; //Ouch! + Server::broadcastPacket($this->hasSpawned, $pk); + $this->setLastDamageCause($source); + $motion = new Vector3(0, 0, 0); + if($source instanceof EntityDamageByEntityEvent){ + $e = $source->getDamager(); + $deltaX = $this->x - $e->x; + $deltaZ = $this->z - $e->z; + $yaw = atan2($deltaX, $deltaZ); + $motion->x = sin($yaw) * 0.5; + $motion->z = cos($yaw) * 0.5; + } + $this->setMotion($motion); + $this->setHealth($this->getHealth() - $damage); - } + } - public function heal($amount){ - $this->server->getPluginManager()->callEvent($ev = new EntityRegainHealthEvent($this, $amount)); - if($ev->isCancelled()){ - return; - } - $this->setHealth($this->getHealth() + $amount); - } + public function heal($amount){ + $this->server->getPluginManager()->callEvent($ev = new EntityRegainHealthEvent($this, $amount)); + if($ev->isCancelled()){ + return; + } + $this->setHealth($this->getHealth() + $amount); + } - public function kill(){ - if($this->dead){ - return; - } - parent::kill(); - $this->server->getPluginManager()->callEvent($ev = new EntityDeathEvent($this, $this->getDrops())); - foreach($ev->getDrops() as $item){ - $this->getLevel()->dropItem($this, $item); - } - } + public function kill(){ + if($this->dead){ + return; + } + parent::kill(); + $this->server->getPluginManager()->callEvent($ev = new EntityDeathEvent($this, $this->getDrops())); + foreach($ev->getDrops() as $item){ + $this->getLevel()->dropItem($this, $item); + } + } - /** - * @return Item[] - */ - public function getDrops(){ - return []; - } -} + /** + * @return Item[] + */ + public function getDrops(){ + return []; + } +} \ No newline at end of file From 61043d2e0d80466c14d15822b642f84000632387 Mon Sep 17 00:00:00 2001 From: williamtdr Date: Fri, 11 Jul 2014 09:14:49 -0500 Subject: [PATCH 03/18] Fix #1615 Players in creative cannot die from non-magic (plugin/console) causes. --- src/pocketmine/entity/Living.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index 27bba8bcc..dbe4112e3 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -58,6 +58,9 @@ abstract class Living extends Entity implements Damageable{ public abstract function getName(); public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){ + if($this instanceof Player and ($this->getGamemode() & 0x01) === 1 and $source != EntityDamageEvent::CAUSE_MAGIC) { + return; + } //TODO: attack tick limit $pk = new EntityEventPacket(); $pk->eid = $this->getID(); @@ -103,4 +106,4 @@ abstract class Living extends Entity implements Damageable{ public function getDrops(){ return []; } -} \ No newline at end of file +} From 5e47dda0a877fe425808d909002d9f913ebca2cd Mon Sep 17 00:00:00 2001 From: williamtdr Date: Fri, 11 Jul 2014 09:18:15 -0500 Subject: [PATCH 04/18] Enable death through void, suicide --- src/pocketmine/entity/Living.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index dbe4112e3..8993eca5d 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -58,7 +58,7 @@ abstract class Living extends Entity implements Damageable{ public abstract function getName(); public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){ - if($this instanceof Player and ($this->getGamemode() & 0x01) === 1 and $source != EntityDamageEvent::CAUSE_MAGIC) { + if($this instanceof Player and ($this->getGamemode() & 0x01) === 1 and $source != EntityDamageEvent::CAUSE_MAGIC and $source != EntityDamageEvent::CAUSE_SUICIDE and $source != EntityDamageEvent::CAUSE_VOID) { return; } //TODO: attack tick limit From 7624eda7b12f7b766c48a747efa7b731ab873131 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Fri, 11 Jul 2014 16:24:04 +0200 Subject: [PATCH 05/18] Update damage sources for creative mode players --- src/pocketmine/entity/Living.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index 8993eca5d..fa20a507d 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -58,9 +58,23 @@ abstract class Living extends Entity implements Damageable{ public abstract function getName(); public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){ - if($this instanceof Player and ($this->getGamemode() & 0x01) === 1 and $source != EntityDamageEvent::CAUSE_MAGIC and $source != EntityDamageEvent::CAUSE_SUICIDE and $source != EntityDamageEvent::CAUSE_VOID) { - return; + + if($this instanceof Player and ($this->getGamemode() & 0x01) === 1){ + if($source instanceof EntityDamageEvent){ + $cause = $source->getCause(); + }else{ + $cause = $source; + } + + if( + $cause !== EntityDamageEvent::CAUSE_MAGIC + and $cause !== EntityDamageEvent::CAUSE_SUICIDE + and $cause !== EntityDamageEvent::CAUSE_VOID + ){ + return; + } } + //TODO: attack tick limit $pk = new EntityEventPacket(); $pk->eid = $this->getID(); From a6e22de6a3d58fd5b848a2b211f1b7bbc5778a6b Mon Sep 17 00:00:00 2001 From: williamtdr Date: Fri, 11 Jul 2014 10:19:28 -0500 Subject: [PATCH 06/18] Possible fix for #1628 --- src/pocketmine/command/defaults/SpawnpointCommand.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pocketmine/command/defaults/SpawnpointCommand.php b/src/pocketmine/command/defaults/SpawnpointCommand.php index 42acf1868..4fbf13c6e 100644 --- a/src/pocketmine/command/defaults/SpawnpointCommand.php +++ b/src/pocketmine/command/defaults/SpawnpointCommand.php @@ -66,9 +66,9 @@ class SpawnpointCommand extends VanillaCommand{ if(count($args) === 4){ if($level !== null){ - $x = (int) $this->getRelativeDouble($sender->x, $sender, $args[1]); - $y = (int) $this->getRelativeDouble($sender->y, $sender, $args[2], 0, 128); - $z = (int) $this->getRelativeDouble($sender->z, $sender, $args[3]); + $x = (int) $this->getRelativeDouble($sender->getX(), $sender, $args[1]); + $y = (int) $this->getRelativeDouble($sender->getY(), $sender, $args[2], 0, 128); + $z = (int) $this->getRelativeDouble($sender->getZ(), $sender, $args[3]); $target->setSpawn(new Position($x, $y, $z, $level)); Command::broadcastCommandMessage($sender, "Set " . $target->getName() . "'s spawnpoint to " . $x . ", " . $y . ", " . $z); @@ -76,7 +76,7 @@ class SpawnpointCommand extends VanillaCommand{ } }elseif(count($args) <= 1){ if($sender instanceof Player){ - $pos = new Position((int) $sender->x, (int) $sender->y, (int) $sender->z, $sender->getLevel()); + $pos = new Position((int) $sender->getX(), (int) $sender->getY(), (int) $sender->getZ(), $sender->getLevel()); $target->setSpawn($pos); Command::broadcastCommandMessage($sender, "Set " . $target->getName() . "'s spawnpoint to " . $pos->x . ", " . $pos->y . ", " . $pos->z); From dd729ced68f91c2682791d8f64262fe7b885cc37 Mon Sep 17 00:00:00 2001 From: williamtdr Date: Fri, 11 Jul 2014 10:21:58 -0500 Subject: [PATCH 07/18] Revert "Possible fix for #1628" This reverts commit a6e22de6a3d58fd5b848a2b211f1b7bbc5778a6b. --- src/pocketmine/command/defaults/SpawnpointCommand.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pocketmine/command/defaults/SpawnpointCommand.php b/src/pocketmine/command/defaults/SpawnpointCommand.php index 4fbf13c6e..42acf1868 100644 --- a/src/pocketmine/command/defaults/SpawnpointCommand.php +++ b/src/pocketmine/command/defaults/SpawnpointCommand.php @@ -66,9 +66,9 @@ class SpawnpointCommand extends VanillaCommand{ if(count($args) === 4){ if($level !== null){ - $x = (int) $this->getRelativeDouble($sender->getX(), $sender, $args[1]); - $y = (int) $this->getRelativeDouble($sender->getY(), $sender, $args[2], 0, 128); - $z = (int) $this->getRelativeDouble($sender->getZ(), $sender, $args[3]); + $x = (int) $this->getRelativeDouble($sender->x, $sender, $args[1]); + $y = (int) $this->getRelativeDouble($sender->y, $sender, $args[2], 0, 128); + $z = (int) $this->getRelativeDouble($sender->z, $sender, $args[3]); $target->setSpawn(new Position($x, $y, $z, $level)); Command::broadcastCommandMessage($sender, "Set " . $target->getName() . "'s spawnpoint to " . $x . ", " . $y . ", " . $z); @@ -76,7 +76,7 @@ class SpawnpointCommand extends VanillaCommand{ } }elseif(count($args) <= 1){ if($sender instanceof Player){ - $pos = new Position((int) $sender->getX(), (int) $sender->getY(), (int) $sender->getZ(), $sender->getLevel()); + $pos = new Position((int) $sender->x, (int) $sender->y, (int) $sender->z, $sender->getLevel()); $target->setSpawn($pos); Command::broadcastCommandMessage($sender, "Set " . $target->getName() . "'s spawnpoint to " . $pos->x . ", " . $pos->y . ", " . $pos->z); From 67b0c4bc2ea27cb79ec146392132af2221a92103 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sat, 12 Jul 2014 02:26:06 +0200 Subject: [PATCH 08/18] Added base timings --- src/pocketmine/Server.php | 8 +- src/pocketmine/command/Command.php | 7 +- src/pocketmine/command/SimpleCommandMap.php | 4 + .../command/defaults/TimingsCommand.php | 141 ++++++++++++++++ src/pocketmine/event/TimingsHandler.php | 151 ++++++++++++++++++ .../permission/DefaultPermissions.php | 1 + src/pocketmine/plugin/MethodEventExecutor.php | 4 + src/pocketmine/plugin/PluginManager.php | 27 +++- src/pocketmine/plugin/RegisteredListener.php | 26 ++- src/pocketmine/resources/pocketmine.yml | 1 + 10 files changed, 361 insertions(+), 9 deletions(-) create mode 100644 src/pocketmine/command/defaults/TimingsCommand.php create mode 100644 src/pocketmine/event/TimingsHandler.php diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 6c045bde5..d3f207202 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -36,6 +36,7 @@ use pocketmine\event\HandlerList; use pocketmine\event\level\LevelInitEvent; use pocketmine\event\level\LevelLoadEvent; use pocketmine\event\server\ServerCommandEvent; +use pocketmine\event\TimingsHandler; use pocketmine\inventory\CraftingManager; use pocketmine\inventory\InventoryType; use pocketmine\inventory\Recipe; @@ -1354,7 +1355,7 @@ class Server{ $this->filePath = $filePath; $this->dataPath = $dataPath; $this->pluginPath = $pluginPath; - @mkdir($this->dataPath . "worlds/", 0777); + @mkdir($this->dataPath . "worlds/", 0777, true); @mkdir($this->dataPath . "players/", 0777); @mkdir($this->pluginPath, 0777); @@ -1474,8 +1475,10 @@ class Server{ Item::init(); $this->craftingManager = new CraftingManager(); + PluginManager::$pluginParentTimer = new TimingsHandler("** Plugins"); $this->pluginManager = new PluginManager($this, $this->commandMap); $this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender); + $this->pluginManager->setUseTimings($this->getProperty("settings.enable-profiling", false)); $this->pluginManager->registerInterface("pocketmine\\plugin\\PharPluginLoader"); $this->pluginManager->loadPlugins($this->pluginPath); @@ -1664,6 +1667,7 @@ class Server{ $this->pluginManager->loadPlugins($this->pluginPath); $this->enablePlugins(PluginLoadOrder::STARTUP); $this->enablePlugins(PluginLoadOrder::POSTWORLD); + TimingsHandler::reload(); } /** @@ -2009,6 +2013,8 @@ class Server{ } } + TimingsHandler::tick(); + $this->tickMeasure = (($time = microtime(true)) - $this->tickTime); $this->tickTime = $time; $this->nextTick = 0.05 * (0.05 / max(0.05, $this->tickMeasure)) + $time; diff --git a/src/pocketmine/command/Command.php b/src/pocketmine/command/Command.php index d2a65b670..898820f85 100644 --- a/src/pocketmine/command/Command.php +++ b/src/pocketmine/command/Command.php @@ -24,6 +24,7 @@ */ namespace pocketmine\command; +use pocketmine\event\TimingsHandler; use pocketmine\Server; use pocketmine\utils\TextFormat; @@ -62,6 +63,9 @@ abstract class Command{ /** @var string */ private $permissionMessage = null; + /** @var TimingsHandler */ + public $timings; + /** * @param string $name * @param string $description @@ -76,6 +80,7 @@ abstract class Command{ $this->usageMessage = $usageMessage === null ? "/" . $name : $usageMessage; $this->aliases = $aliases; $this->activeAliases = (array) $aliases; + $this->timings = new TimingsHandler("** Command: ". $name); } /** @@ -156,8 +161,8 @@ abstract class Command{ public function setLabel($name){ $this->nextLabel = $name; if(!$this->isRegistered()){ + $this->timings = new TimingsHandler("** Command: ". $name); $this->label = $name; - return true; } diff --git a/src/pocketmine/command/SimpleCommandMap.php b/src/pocketmine/command/SimpleCommandMap.php index efb51a7f6..2847b52cb 100644 --- a/src/pocketmine/command/SimpleCommandMap.php +++ b/src/pocketmine/command/SimpleCommandMap.php @@ -51,6 +51,7 @@ use pocketmine\command\defaults\StopCommand; use pocketmine\command\defaults\TeleportCommand; use pocketmine\command\defaults\TellCommand; use pocketmine\command\defaults\TimeCommand; +use pocketmine\command\defaults\TimingsCommand; use pocketmine\command\defaults\VanillaCommand; use pocketmine\command\defaults\VersionCommand; use pocketmine\command\defaults\WhitelistCommand; @@ -102,6 +103,7 @@ class SimpleCommandMap implements CommandMap{ $this->register("pocketmine", new SetWorldSpawnCommand("setworldspawn")); $this->register("pocketmine", new TeleportCommand("tp")); $this->register("pocketmine", new TimeCommand("time")); + $this->register("pocketmine", new TimingsCommand("timings")); $this->register("pocketmine", new ReloadCommand("reload")); if($this->server->getProperty("debug.commands", false) === true){ @@ -175,7 +177,9 @@ class SimpleCommandMap implements CommandMap{ return false; } + $target->timings->startTiming(); $target->execute($sender, $sentCommandLabel, $args); + $target->timings->stopTiming(); return true; } diff --git a/src/pocketmine/command/defaults/TimingsCommand.php b/src/pocketmine/command/defaults/TimingsCommand.php new file mode 100644 index 000000000..59a21135a --- /dev/null +++ b/src/pocketmine/command/defaults/TimingsCommand.php @@ -0,0 +1,141 @@ +" + ); + $this->setPermission("pocketmine.command.timings"); + } + + public function execute(CommandSender $sender, $currentAlias, array $args){ + if(!$this->testPermission($sender)){ + return true; + } + + if(count($args) !== 1){ + $sender->sendMessage(TextFormat::RED . "Usage: " . $this->usageMessage); + return true; + } + + $mode = strtolower($args[0]); + + if($mode === "on"){ + $sender->getServer()->getPluginManager()->setUseTimings(true); + TimingsHandler::reload(); + $sender->sendMessage("Enabled Timings & Reset"); + return true; + }elseif($mode === "off"){ + $sender->getServer()->getPluginManager()->setUseTimings(false); + $sender->sendMessage("Disabled Timings"); + } + + if(!$sender->getServer()->getPluginManager()->useTimings()){ + $sender->sendMessage("Please enable timings by typing /timings on"); + return true; + } + + $paste = $mode === "paste"; + + if($mode === "reset"){ + TimingsHandler::reload(); + $sender->sendMessage("Timings reset"); + /*foreach(HandlerList::getHandlerLists() as $handlerList){ + foreach($handlerList->getRegisteredListeners() as $listener){ + if($listener instanceof TimedRegisteredListener){ + $listener->reset(); + } + } + }*/ + }elseif($mode === "merged" or $mode === "report" or $paste){ + + $sampleTime = microtime(true) - self::$timingStart; + $index = 0; + $timingFolder = $sender->getServer()->getDataPath() . "timings/"; + @mkdir($timingFolder, 0777); + $timings = $timingFolder . "timings.txt"; + while(file_exists($timings)){ + $timings = $timingFolder . "timings" . (++$index) . ".txt"; + } + + $fileTimings = $paste ? fopen("php://temp", "r+b") : fopen($timings, "a+b"); + + TimingsHandler::printTimings($fileTimings); + + fwrite($fileTimings, "Sample time ". round($sampleTime * 1000000000) ." (". $sampleTime ."s)" . PHP_EOL); + + if($paste){ + fseek($fileTimings, 0); + $data = [ + "public" => false, + "description" => "PocketMine-MP Timings", + "files" => [ + "timings.txt" => [ + "content" => stream_get_contents($fileTimings) + ] + ] + ]; + + $ch = curl_init("https://api.github.com/gists"); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); + curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_SLASHES)); + curl_setopt($ch, CURLOPT_AUTOREFERER, true); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json", "User-Agent: PocketMine-MP ".$sender->getServer()->getPocketMineVersion()]); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $ret = curl_exec($ch); + $data = json_decode($ret); + curl_close($ch); + if($data === false or $data === null or !isset($data->html_url)){ + $sender->sendMessage("An error happened while pasting the report"); + return true; + } + $timings = $data->html_url; + } + + fclose($fileTimings); + $sender->sendMessage("Timings written to ". $timings); + $sender->sendMessage("Paste contents of file into form at http://aikar.co/timings.php to read results."); + } + + return true; + } +} \ No newline at end of file diff --git a/src/pocketmine/event/TimingsHandler.php b/src/pocketmine/event/TimingsHandler.php new file mode 100644 index 000000000..38a02e0e0 --- /dev/null +++ b/src/pocketmine/event/TimingsHandler.php @@ -0,0 +1,151 @@ +name = $name; + if($parent instanceof TimingsHandler){ + $this->parent = $parent; + } + + self::$HANDLERS[spl_object_hash($this)] = $this; + } + + public static function printTimings($fp){ + fwrite($fp, "Minecraft" . PHP_EOL); + + foreach(self::$HANDLERS as $timings){ + $time = $timings->totalTime; + $count = $timings->count; + if($count === 0){ + continue; + } + + $avg = $time / $count; + + fwrite($fp, " " . $timings->name ." Time: ". round($time * 1000000000) ." Count: ". $count ." Avg: ". round($avg * 1000000000) ." Violations: ". $timings->violations . PHP_EOL); + } + + fwrite($fp, "# Version " . Server::getInstance()->getVersion() . PHP_EOL); + fwrite($fp, "# PocketMine-MP " . Server::getInstance()->getPocketMineVersion() . PHP_EOL); + + $entities = 0; + $livingEntities = 0; + foreach(Server::getInstance()->getLevels() as $level){ + $entities += count($level->getEntities()); + foreach($level->getEntities() as $e){ + if($e instanceof Living){ + ++$livingEntities; + } + } + } + + fwrite($fp, "# Entities ". $entities . PHP_EOL); + fwrite($fp, "# LivingEntities ". $livingEntities . PHP_EOL); + } + + public static function reload(){ + if(Server::getInstance()->getPluginManager()->useTimings()){ + foreach(self::$HANDLERS as $timings){ + $timings->reset(); + } + TimingsCommand::$timingStart = microtime(true); + } + } + + public static function tick(){ + if(PluginManager::$useTimings){ + foreach(self::$HANDLERS as $timings){ + if($timings->curTickTotal > 0.05){ + $timings->violations += ceil($timings->curTickTotal / 0.05); + } + $timings->curTickTotal = 0; + $timings->timingDepth = 0; + } + } + } + + public function startTiming(){ + if(PluginManager::$useTimings and ++$this->timingDepth === 1){ + $this->start = microtime(true); + if($this->parent instanceof TimingsHandler and ++$this->parent->timingDepth === 1){ + $this->parent->start = $this->start; + } + } + } + + public function stopTiming(){ + if(PluginManager::$useTimings){ + if(--$this->timingDepth !== 0 or $this->start === 0){ + return; + } + + $diff = microtime(true) - $this->start; + $this->totalTime += $diff; + $this->curTickTotal += $diff; + $this->count++; + $this->start = 0; + if($this->parent instanceof TimingsHandler){ + $this->parent->stopTiming(); + } + } + } + + public function reset(){ + $this->count = 0; + $this->violations = 0; + $this->curTickTotal = 0; + $this->totalTime = 0; + $this->start = 0; + $this->timingDepth = 0; + } + + public function remove(){ + unset(self::$HANDLERS[spl_object_hash($this)]); + } + +} \ No newline at end of file diff --git a/src/pocketmine/permission/DefaultPermissions.php b/src/pocketmine/permission/DefaultPermissions.php index c9b7ad036..45fda6efe 100644 --- a/src/pocketmine/permission/DefaultPermissions.php +++ b/src/pocketmine/permission/DefaultPermissions.php @@ -107,6 +107,7 @@ abstract class DefaultPermissions{ self::registerPermission(new Permission(self::ROOT . ".command.defaultgamemode", "Allows the user to change the default gamemode", Permission::DEFAULT_OP), $commands); self::registerPermission(new Permission(self::ROOT . ".command.seed", "Allows the user to view the seed of the world", Permission::DEFAULT_OP), $commands); self::registerPermission(new Permission(self::ROOT . ".command.status", "Allows the user to view the server performance", Permission::DEFAULT_OP), $commands); + self::registerPermission(new Permission(self::ROOT . ".command.timings", "Allows the user to records timings for all plugin events", Permission::DEFAULT_OP), $commands); self::registerPermission(new Permission(self::ROOT . ".command.spawnpoint", "Allows the user to change player's spawnpoint", Permission::DEFAULT_OP), $commands); self::registerPermission(new Permission(self::ROOT . ".command.setworldspawn", "Allows the user to change the world spawn", Permission::DEFAULT_OP), $commands); diff --git a/src/pocketmine/plugin/MethodEventExecutor.php b/src/pocketmine/plugin/MethodEventExecutor.php index a735f2954..43137db8e 100644 --- a/src/pocketmine/plugin/MethodEventExecutor.php +++ b/src/pocketmine/plugin/MethodEventExecutor.php @@ -35,4 +35,8 @@ class MethodEventExecutor implements EventExecutor{ public function execute(Listener $listener, Event $event){ call_user_func(array($listener, $this->method), $event); } + + public function getMethod(){ + return $this->method; + } } \ No newline at end of file diff --git a/src/pocketmine/plugin/PluginManager.php b/src/pocketmine/plugin/PluginManager.php index 3d55c638f..91f36c073 100644 --- a/src/pocketmine/plugin/PluginManager.php +++ b/src/pocketmine/plugin/PluginManager.php @@ -21,12 +21,14 @@ namespace pocketmine\plugin; +use pocketmine\command\defaults\TimingsCommand; use pocketmine\command\PluginCommand; use pocketmine\command\SimpleCommandMap; use pocketmine\event\Event; use pocketmine\event\EventPriority; use pocketmine\event\HandlerList; use pocketmine\event\Listener; +use pocketmine\event\TimingsHandler; use pocketmine\permission\Permissible; use pocketmine\permission\Permission; use pocketmine\Server; @@ -82,6 +84,11 @@ class PluginManager{ */ protected $fileAssociations = []; + /** @var TimingsHandler */ + public static $pluginParentTimer; + + public static $useTimings = false; + /** * @param Server $server * @param SimpleCommandMap $commandMap @@ -306,8 +313,10 @@ class PluginManager{ } } + TimingsCommand::$timingStart = microtime(true); return $loadedPlugins; }else{ + TimingsCommand::$timingStart = microtime(true); return []; } } @@ -699,7 +708,9 @@ class PluginManager{ throw new \Exception("Plugin attempted to register " . $event . " while not enabled"); } - $this->getEventListeners($event)->register(new RegisteredListener($listener, $executor, $priority, $plugin, $ignoreCancelled)); + $timings = new TimingsHandler("Plugin: ".$plugin->getDescription()->getName()." Event: ".get_class($listener)."::".($executor instanceof MethodEventExecutor ? $executor->getMethod() : "???")."(".(new \ReflectionClass($event))->getShortName().")", self::$pluginParentTimer); + + $this->getEventListeners($event)->register(new RegisteredListener($listener, $executor, $priority, $plugin, $ignoreCancelled, $timings)); } /** @@ -715,4 +726,18 @@ class PluginManager{ return $event::$handlerList; } + /** + * @return bool + */ + public function useTimings(){ + return self::$useTimings; + } + + /** + * @param bool $use + */ + public function setUseTimings($use){ + self::$useTimings = (bool) $use; + } + } diff --git a/src/pocketmine/plugin/RegisteredListener.php b/src/pocketmine/plugin/RegisteredListener.php index b24e01e5e..e613ee7c7 100644 --- a/src/pocketmine/plugin/RegisteredListener.php +++ b/src/pocketmine/plugin/RegisteredListener.php @@ -24,6 +24,7 @@ namespace pocketmine\plugin; use pocketmine\event\Cancellable; use pocketmine\event\Event; use pocketmine\event\Listener; +use pocketmine\event\TimingsHandler; class RegisteredListener{ @@ -42,19 +43,26 @@ class RegisteredListener{ /** @var bool */ private $ignoreCancelled; + /** @var TimingsHandler */ + private $timings; + + + /** - * @param Listener $listener - * @param EventExecutor $executor - * @param int $priority - * @param Plugin $plugin - * @param boolean $ignoreCancelled + * @param Listener $listener + * @param EventExecutor $executor + * @param int $priority + * @param Plugin $plugin + * @param boolean $ignoreCancelled + * @param TimingsHandler $timings */ - public function __construct(Listener $listener, EventExecutor $executor, $priority, Plugin $plugin, $ignoreCancelled){ + public function __construct(Listener $listener, EventExecutor $executor, $priority, Plugin $plugin, $ignoreCancelled, TimingsHandler $timings){ $this->listener = $listener; $this->priority = $priority; $this->plugin = $plugin; $this->executor = $executor; $this->ignoreCancelled = $ignoreCancelled; + $this->timings = $timings; } /** @@ -85,7 +93,13 @@ class RegisteredListener{ if($event instanceof Cancellable and $event->isCancelled() and $this->isIgnoringCancelled()){ return; } + $this->timings->startTiming(); $this->executor->execute($this->listener, $event); + $this->timings->stopTiming(); + } + + public function __destruct(){ + $this->timings->remove(); } /** diff --git a/src/pocketmine/resources/pocketmine.yml b/src/pocketmine/resources/pocketmine.yml index a932e6269..77957cea1 100644 --- a/src/pocketmine/resources/pocketmine.yml +++ b/src/pocketmine/resources/pocketmine.yml @@ -7,6 +7,7 @@ settings: plugin-profiling: false query-plugins: true deprecated-verbose: true + enable-profiling: false advanced-cache: false upnp-forwarding: false send-usage: true From 0bfa9506d1414a57a339838e185f96af534412a6 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sat, 12 Jul 2014 02:26:41 +0200 Subject: [PATCH 09/18] Updated API version to 1.1.0 (backwards-compatible) --- src/pocketmine/PocketMine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index b860b519e..6c6639ac3 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -74,7 +74,7 @@ namespace pocketmine { use raklib\RakLib; const VERSION = "Alpha_1.4dev"; - const API_VERSION = "1.0.0"; + const API_VERSION = "1.1.0"; const CODENAME = "絶好(Zekkou)ケーキ(Cake)"; const MINECRAFT_VERSION = "v0.9.0 alpha"; const PHP_VERSION = "5.5"; From 9bdd294a66c0c5d4166ca3363ad376cc1b5ef2d3 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sat, 12 Jul 2014 14:09:29 +0200 Subject: [PATCH 10/18] Implemented global, tasks timings --- src/pocketmine/Player.php | 3 + src/pocketmine/Server.php | 22 ++- src/pocketmine/event/LevelTimings.php | 103 +++++++++++ src/pocketmine/event/Timings.php | 182 +++++++++++++++++++ src/pocketmine/level/Level.php | 15 +- src/pocketmine/resources/pocketmine.yml | 1 - src/pocketmine/scheduler/ServerScheduler.php | 5 +- src/pocketmine/scheduler/TaskHandler.php | 31 +++- 8 files changed, 348 insertions(+), 14 deletions(-) create mode 100644 src/pocketmine/event/LevelTimings.php create mode 100644 src/pocketmine/event/Timings.php diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 3442075b4..6f2bcf0bf 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -47,6 +47,7 @@ use pocketmine\event\player\PlayerQuitEvent; use pocketmine\event\player\PlayerRespawnEvent; use pocketmine\event\server\DataPacketReceiveEvent; use pocketmine\event\server\DataPacketSendEvent; +use pocketmine\event\Timings; use pocketmine\inventory\BaseTransaction; use pocketmine\inventory\BigShapelessRecipe; use pocketmine\inventory\CraftingTransactionGroup; @@ -1845,7 +1846,9 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ break; } if(substr($ev->getMessage(), 0, 1) === "/"){ //Command + Timings::$playerCommandTimer->startTiming(); $this->server->dispatchCommand($ev->getPlayer(), substr($ev->getMessage(), 1)); + Timings::$playerCommandTimer->stopTiming(); }else{ $this->server->getPluginManager()->callEvent($ev = new PlayerChatEvent($this, $ev->getMessage())); if(!$ev->isCancelled()){ diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index d3f207202..98059cff7 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -36,6 +36,7 @@ use pocketmine\event\HandlerList; use pocketmine\event\level\LevelInitEvent; use pocketmine\event\level\LevelLoadEvent; use pocketmine\event\server\ServerCommandEvent; +use pocketmine\event\Timings; use pocketmine\event\TimingsHandler; use pocketmine\inventory\CraftingManager; use pocketmine\inventory\InventoryType; @@ -1476,6 +1477,7 @@ class Server{ $this->craftingManager = new CraftingManager(); PluginManager::$pluginParentTimer = new TimingsHandler("** Plugins"); + Timings::init(); $this->pluginManager = new PluginManager($this, $this->commandMap); $this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender); $this->pluginManager->setUseTimings($this->getProperty("settings.enable-profiling", false)); @@ -1599,10 +1601,15 @@ class Server{ } public function checkConsole(){ + Timings::$serverCommandTimer->startTiming(); if(($line = $this->console->getLine()) !== null){ $this->pluginManager->callEvent($ev = new ServerCommandEvent($this->consoleSender, $line)); + if($ev->isCancelled()){ + return; + } $this->dispatchCommand($this->consoleSender, $ev->getCommand()); } + Timings::$serverCommandTimer->stopTiming(); } /** @@ -1623,7 +1630,6 @@ class Server{ }else{ $sender->sendMessage("Unknown command. Type \"help\" for help."); } - return false; } @@ -1935,13 +1941,15 @@ class Server{ public function doAutoSave(){ - /*foreach($this->getOnlinePlayers() as $player){ + Timings::$worldSaveTimer->startTiming(); + foreach($this->getOnlinePlayers() as $player){ $player->save(); - }*/ + } foreach($this->getLevels() as $level){ - $level->save(); + $level->save(false); } + Timings::$worldSaveTimer->stopTiming(); } public function doLevelGC(){ @@ -1999,11 +2007,15 @@ class Server{ return false; } + Timings::$serverTickTimer->startTiming(); + $this->inTick = true; //Fix race conditions ++$this->tickCounter; $this->checkConsole(); + Timings::$schedulerTimer->startTiming(); $this->scheduler->mainThreadHeartbeat($this->tickCounter); + Timings::$schedulerTimer->stopTiming(); $this->checkTickUpdates($this->tickCounter); if(($this->tickCounter & 0b1111) === 0){ @@ -2020,6 +2032,8 @@ class Server{ $this->nextTick = 0.05 * (0.05 / max(0.05, $this->tickMeasure)) + $time; $this->inTick = false; + Timings::$serverTickTimer->stopTiming(); + return true; } diff --git a/src/pocketmine/event/LevelTimings.php b/src/pocketmine/event/LevelTimings.php new file mode 100644 index 000000000..e4787caf7 --- /dev/null +++ b/src/pocketmine/event/LevelTimings.php @@ -0,0 +1,103 @@ +getFolderName() . " - "; + + $this->mobSpawn = new TimingsHandler("** ". $name ."mobSpawn"); + $this->doChunkUnload = new TimingsHandler("** ". $name ."doChunkUnload"); + $this->doTickPending = new TimingsHandler("** ". $name ."doTickPending"); + $this->doTickTiles = new TimingsHandler("** ". $name ."doTickTiles"); + $this->doVillages = new TimingsHandler("** ". $name ."doVillages"); + $this->doChunkMap = new TimingsHandler("** ". $name ."doChunkMap"); + $this->doSounds = new TimingsHandler("** ". $name ."doSounds"); + $this->doChunkGC = new TimingsHandler("** ". $name ."doChunkGC"); + $this->doPortalForcer = new TimingsHandler("** ". $name ."doPortalForcer"); + $this->entityTick = new TimingsHandler("** ". $name ."entityTick"); + $this->tileEntityTick = new TimingsHandler("** ". $name ."tileEntityTick"); + $this->tileEntityPending = new TimingsHandler("** ". $name ."tileEntityPending"); + + $this->syncChunkLoadTimer = new TimingsHandler("** ". $name ."syncChunkLoad"); + $this->syncChunkLoadDataTimer = new TimingsHandler("** ". $name ."syncChunkLoad - Data"); + $this->syncChunkLoadStructuresTimer = new TimingsHandler("** ". $name ."syncChunkLoad - Structures"); + $this->syncChunkLoadEntitiesTimer = new TimingsHandler("** ". $name ."syncChunkLoad - Entities"); + $this->syncChunkLoadTileEntitiesTimer = new TimingsHandler("** ". $name ."syncChunkLoad - TileEntities"); + $this->syncChunkLoadTileTicksTimer = new TimingsHandler("** ". $name ."syncChunkLoad - TileTicks"); + $this->syncChunkLoadPostTimer = new TimingsHandler("** ". $name ."syncChunkLoad - Post"); + + $this->tracker = new TimingsHandler($name ."tracker"); + $this->doTick = new TimingsHandler($name ."doTick"); + $this->tickEntities = new TimingsHandler($name ."tickEntities"); + } + +} \ No newline at end of file diff --git a/src/pocketmine/event/Timings.php b/src/pocketmine/event/Timings.php new file mode 100644 index 000000000..51262411a --- /dev/null +++ b/src/pocketmine/event/Timings.php @@ -0,0 +1,182 @@ +getTask(); + if($ftask instanceof PluginTask and $ftask->getOwner() !== null){ + $plugin = $ftask->getOwner()->getDescription()->getName(); + }elseif($task->timingName !== null){ + $plugin = "Scheduler"; + }else{ + $plugin = "Unknown"; + } + + $taskname = $task->getTaskName(); + + $name = "Task: ". $plugin." Runnable: ". $taskname; + + if($period > 0){ + $name .= "(interval:".$period.")"; + }else{ + $name .= "(Single)"; + } + + if(!isset(self::$pluginTaskTimingMap[$name])){ + self::$pluginTaskTimingMap[$name] = new TimingsHandler($name, self::$schedulerSyncTimer); + } + + return self::$pluginTaskTimingMap[$name]; + } + + /** + * @param Entity $entity + * + * @return TimingsHandler + */ + public static function getEntityTimings(Entity $entity){ + $entityType = (new \ReflectionClass($entity))->getShortName(); + if(!isset(self::$entityTypeTimingMap[$entityType])){ + self::$entityTypeTimingMap[$entityType] = new TimingsHandler("** tickEntity - ". $entityType, self::$activatedEntityTimer); + } + + return self::$entityTypeTimingMap[$entityType]; + } + + /** + * @param Tile $tile + * + * @return TimingsHandler + */ + public static function getTileEntityTimings(Tile $tile){ + $tileType = (new \ReflectionClass($tile))->getShortName(); + if(!isset(self::$tileEntityTypeTimingMap[$tileType])){ + self::$tileEntityTypeTimingMap[$tileType] = new TimingsHandler("** tickTileEntity - ". $tileType, self::$tickTileEntityTimer); + } + + return self::$tileEntityTypeTimingMap[$tileType]; + } + +} \ No newline at end of file diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 5253ecd95..6722b2ed3 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -33,6 +33,7 @@ use pocketmine\event\block\BlockPlaceEvent; use pocketmine\event\level\LevelSaveEvent; use pocketmine\event\level\LevelUnloadEvent; use pocketmine\event\level\SpawnChangeEvent; +use pocketmine\event\LevelTimings; use pocketmine\event\player\PlayerInteractEvent; use pocketmine\item\Item; use pocketmine\level\format\Chunk; @@ -157,6 +158,9 @@ class Level implements ChunkManager, Metadatable{ Block::BEETROOT_BLOCK, ]; + /** @var LevelTimings */ + public $timings; + /** * Returns the chunk unique hash/key * @@ -208,6 +212,7 @@ class Level implements ChunkManager, Metadatable{ $this->chunksPerTick = (int) $this->server->getProperty("chunk-ticking.per-tick", 128); $this->chunkTickList = []; $this->clearChunksOnTick = (bool) $this->server->getProperty("chunk-ticking.clear-tick-list", true); + $this->timings = new LevelTimings($this); } /** @@ -386,6 +391,8 @@ class Level implements ChunkManager, Metadatable{ */ public function doTick($currentTick){ + $this->timings->doTick->startTiming(); + if(($currentTick % 200) === 0){ $this->checkTime(); } @@ -450,9 +457,7 @@ class Level implements ChunkManager, Metadatable{ $this->processChunkRequest(); - if($this->nextSave < microtime(true)){ - $this->save(false); - } + $this->timings->doTick->stopTiming(); } private function tickChunks(){ @@ -1677,6 +1682,8 @@ class Level implements ChunkManager, Metadatable{ } public function doChunkGarbageCollection(){ + $this->timings->doChunkGC->startTiming(); + $X = null; $Z = null; @@ -1703,6 +1710,8 @@ class Level implements ChunkManager, Metadatable{ } } + + $this->timings->doChunkGC->stopTiming(); } diff --git a/src/pocketmine/resources/pocketmine.yml b/src/pocketmine/resources/pocketmine.yml index 77957cea1..94c07ee80 100644 --- a/src/pocketmine/resources/pocketmine.yml +++ b/src/pocketmine/resources/pocketmine.yml @@ -4,7 +4,6 @@ settings: shutdown-message: "Server closed" - plugin-profiling: false query-plugins: true deprecated-verbose: true enable-profiling: false diff --git a/src/pocketmine/scheduler/ServerScheduler.php b/src/pocketmine/scheduler/ServerScheduler.php index 8e77034a5..ccf33361f 100644 --- a/src/pocketmine/scheduler/ServerScheduler.php +++ b/src/pocketmine/scheduler/ServerScheduler.php @@ -178,7 +178,7 @@ class ServerScheduler{ $period = 1; } - return $this->handle(new TaskHandler($task, $this->nextId(), $delay, $period)); + return $this->handle(new TaskHandler(!($task instanceof PluginTask) ? "Scheduler" : null, $task, $this->nextId(), $delay, $period)); } private function handle(TaskHandler $handler){ @@ -201,12 +201,15 @@ class ServerScheduler{ public function mainThreadHeartbeat($currentTick){ $this->currentTick = $currentTick; while($this->isReady($this->currentTick)){ + /** @var TaskHandler $task */ $task = $this->queue->extract(); if($task->isCancelled()){ unset($this->tasks[$task->getTaskId()]); continue; }else{ + $task->timings->startTiming(); $task->run($this->currentTick); + $task->timings->stopTiming(); } if($task->isRepeating()){ $task->setNextRun($this->currentTick + $task->getPeriod()); diff --git a/src/pocketmine/scheduler/TaskHandler.php b/src/pocketmine/scheduler/TaskHandler.php index 4cd09563b..e34ca8bb8 100644 --- a/src/pocketmine/scheduler/TaskHandler.php +++ b/src/pocketmine/scheduler/TaskHandler.php @@ -21,6 +21,8 @@ namespace pocketmine\scheduler; +use pocketmine\event\Timings; + class TaskHandler{ /** @var Task */ @@ -41,17 +43,25 @@ class TaskHandler{ /** @var bool */ protected $cancelled = false; + /** @var \pocketmine\event\TimingsHandler */ + public $timings; + + public $timingName = null; + /** - * @param Task $task - * @param int $taskId - * @param int $delay - * @param int $period + * @param string $timingName + * @param Task $task + * @param int $taskId + * @param int $delay + * @param int $period */ - public function __construct(Task $task, $taskId, $delay = -1, $period = -1){ + public function __construct($timingName, Task $task, $taskId, $delay = -1, $period = -1){ $this->task = $task; $this->taskId = $taskId; $this->delay = $delay; $this->period = $period; + $this->timingName = $timingName === null ? "Unknown" : $timingName; + $this->timings = Timings::getPluginTaskTimings($this, $period); } /** @@ -127,6 +137,7 @@ class TaskHandler{ public function remove(){ $this->cancelled = true; $this->task->setHandler(null); + $this->timings->remove(); } /** @@ -135,4 +146,14 @@ class TaskHandler{ public function run($currentTick){ $this->task->onRun($currentTick); } + + /** + * @return string + */ + public function getTaskName(){ + if($this->timingName !== null){ + return $this->timingName; + } + return get_class($this->task); + } } \ No newline at end of file From 52b0e8b1ee532c443afb883b154408842fe74786 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sat, 12 Jul 2014 14:17:35 +0200 Subject: [PATCH 11/18] Updated RakLib, fixes random upload increase --- src/raklib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raklib b/src/raklib index 577c371aa..05eacdf02 160000 --- a/src/raklib +++ b/src/raklib @@ -1 +1 @@ -Subproject commit 577c371aa07bd2aa3cedc3b7d4bcdc1d54999c70 +Subproject commit 05eacdf026567d32564ae9fbaf6e7ed184bb0f24 From 0d55d5c653df83e45a5b436bf7401c70445c9e22 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sat, 12 Jul 2014 14:36:22 +0200 Subject: [PATCH 12/18] Fixed typo --- src/raklib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raklib b/src/raklib index 05eacdf02..df53c0844 160000 --- a/src/raklib +++ b/src/raklib @@ -1 +1 @@ -Subproject commit 05eacdf026567d32564ae9fbaf6e7ed184bb0f24 +Subproject commit df53c0844231a2ddc340dcd13a77944ca8822d27 From 9a4ead54e3c5e857053df30158ef18b9415cc0f6 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sat, 12 Jul 2014 15:23:06 +0200 Subject: [PATCH 13/18] Added more timings --- src/pocketmine/Server.php | 38 ++++++------------- src/pocketmine/entity/Entity.php | 4 ++ src/pocketmine/entity/Living.php | 7 ++++ src/pocketmine/level/Level.php | 11 +++++- src/pocketmine/level/format/anvil/Anvil.php | 3 ++ .../level/format/anvil/RegionLoader.php | 3 +- .../level/format/generic/BaseChunk.php | 5 ++- src/pocketmine/tile/Tile.php | 5 +++ src/raklib | 2 +- 9 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 98059cff7..158e5cc8f 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1753,35 +1753,10 @@ class Server{ $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 - // $this->tickProcessorWindows(); - //}else{ - $this->tickProcessor(); - //} + $this->tickProcessor(); $this->forceShutdown(); } - /*private function tickProcessorWindows(){ - $lastLoop = 0; - while($this->isRunning){ - foreach($this->interfaces as $interface){ - if($interface->process()){ - $lastLoop = 0; - } - } - $this->generationManager->handlePackets(); - - if(($ticks = $this->tick()) !== true){ - ++$lastLoop; - if($lastLoop > 8){ - usleep(1000); - } - }else{ - $lastLoop = 0; - } - } - }*/ - public function checkTicks(){ if($this->getTicksPerSecond() < 12){ $this->logger->warning("Can't keep up! Is the server overloaded?"); @@ -1885,13 +1860,17 @@ class Server{ private function tickProcessor(){ $lastLoop = 0; + $connectionTimer = Timings::$connectionTimer; while($this->isRunning){ + $connectionTimer->startTiming(); foreach($this->interfaces as $interface){ if($interface->process()){ $lastLoop = 0; } } + $connectionTimer->stopTiming(); + $this->generationManager->handlePackets(); ++$lastLoop; @@ -1913,22 +1892,29 @@ class Server{ } private function checkTickUpdates($currentTick){ + + //TODO: move this to each Level + //Update entities that need update if(count(Entity::$needUpdate) > 0){ + Timings::$tickEntityTimer->startTiming(); foreach(Entity::$needUpdate as $id => $entity){ if($entity->onUpdate() === false){ unset(Entity::$needUpdate[$id]); } } + Timings::$tickEntityTimer->stopTiming(); } //Update tiles that need update if(count(Tile::$needUpdate) > 0){ + Timings::$tickTileEntityTimer->startTiming(); foreach(Tile::$needUpdate as $id => $tile){ if($tile->onUpdate() === false){ unset(Tile::$needUpdate[$id]); } } + Timings::$tickTileEntityTimer->stopTiming(); } //TODO: Add level blocks diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index 0eef27859..e988cc426 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -33,6 +33,7 @@ use pocketmine\event\entity\EntityMotionEvent; use pocketmine\event\entity\EntityMoveEvent; use pocketmine\event\entity\EntitySpawnEvent; use pocketmine\event\entity\EntityTeleportEvent; +use pocketmine\event\Timings; use pocketmine\level\format\Chunk; use pocketmine\level\Level; use pocketmine\level\Position; @@ -669,6 +670,8 @@ abstract class Entity extends Position implements Metadatable{ return; } + Timings::$entityMoveTimer->startTiming(); + $ox = $this->x; $oy = $this->y; $oz = $this->z; @@ -832,6 +835,7 @@ abstract class Entity extends Position implements Metadatable{ //TODO: vehicle collision events (first we need to spawn them!) + Timings::$entityMoveTimer->stopTiming(); } diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index 27bba8bcc..e50680569 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -26,6 +26,7 @@ use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDeathEvent; use pocketmine\event\entity\EntityRegainHealthEvent; +use pocketmine\event\Timings; use pocketmine\math\Vector3; use pocketmine\nbt\tag\Short; use pocketmine\network\protocol\EntityEventPacket; @@ -97,6 +98,12 @@ abstract class Living extends Entity implements Damageable{ } } + public function entityBaseTick(){ + Timings::$timerEntityBaseTick->startTiming(); + parent::entityBaseTick(); + Timings::$timerEntityBaseTick->stopTiming(); + } + /** * @return Item[] */ diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 6722b2ed3..383aed897 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -447,13 +447,17 @@ class Level implements ChunkManager, Metadatable{ $X = null; $Z = null; - //Do chunk updates + //Do block updates + $this->timings->doTickPending->startTiming(); while($this->updateQueue->count() > 0 and $this->updateQueue->current()["priority"] <= $currentTick){ $block = $this->getBlock($this->updateQueue->extract()["data"]); $block->onUpdate(self::BLOCK_UPDATE_SCHEDULED); } + $this->timings->doTickPending->stopTiming(); + $this->timings->doTickTiles->startTiming(); $this->tickChunks(); + $this->timings->doTickTiles->stopTiming(); $this->processChunkRequest(); @@ -1486,7 +1490,9 @@ class Level implements ChunkManager, Metadatable{ if($chunk instanceof Chunk){ return true; }else{ + $this->timings->syncChunkLoadTimer->startTiming(); $this->provider->loadChunk($x, $z); + $this->timings->syncChunkLoadTimer->stopTiming(); return $this->provider->getChunk($x, $z) instanceof Chunk; } @@ -1514,10 +1520,13 @@ class Level implements ChunkManager, Metadatable{ if($safe === true and $this->isChunkInUse($x, $z)){ return false; } + $this->timings->doChunkUnload->startTiming(); $this->provider->unloadChunk($x, $z, $safe); Cache::remove("world:" . $this->getID() . ":$x:$z"); + $this->timings->doChunkUnload->stopTiming(); + return true; } diff --git a/src/pocketmine/level/format/anvil/Anvil.php b/src/pocketmine/level/format/anvil/Anvil.php index bdf9e0eda..4f0bbd131 100644 --- a/src/pocketmine/level/format/anvil/Anvil.php +++ b/src/pocketmine/level/format/anvil/Anvil.php @@ -117,7 +117,10 @@ class Anvil extends BaseLevelProvider{ $regionX = $regionZ = null; self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); $this->loadRegion($regionX, $regionZ); + + $this->level->timings->syncChunkLoadDataTimer->startTiming(); $chunk = $this->getRegion($regionX, $regionZ)->readChunk($chunkX - $regionX * 32, $chunkZ - $regionZ * 32, $create); //generate empty chunk if not loaded + $this->level->timings->syncChunkLoadDataTimer->stopTiming(); if($chunk instanceof Chunk){ $this->chunks[$index] = $chunk; diff --git a/src/pocketmine/level/format/anvil/RegionLoader.php b/src/pocketmine/level/format/anvil/RegionLoader.php index f9ddb3cc8..20063ee89 100644 --- a/src/pocketmine/level/format/anvil/RegionLoader.php +++ b/src/pocketmine/level/format/anvil/RegionLoader.php @@ -116,13 +116,14 @@ class RegionLoader{ $this->writeLocationIndex($index); }elseif($compression !== self::COMPRESSION_ZLIB and $compression !== self::COMPRESSION_GZIP){ trigger_error("Invalid compression type", E_USER_WARNING); - return false; } $nbt = new NBT(NBT::BIG_ENDIAN); $nbt->readCompressed(fread($this->filePointer, $length - 1), $compression); $chunk = $nbt->getData(); + + if(!isset($chunk->Level) or !($chunk->Level instanceof Compound)){ return false; } diff --git a/src/pocketmine/level/format/generic/BaseChunk.php b/src/pocketmine/level/format/generic/BaseChunk.php index 9e6d8109c..ef1394465 100644 --- a/src/pocketmine/level/format/generic/BaseChunk.php +++ b/src/pocketmine/level/format/generic/BaseChunk.php @@ -98,6 +98,7 @@ abstract class BaseChunk implements Chunk{ $this->biomeColors = array_fill(0, 256, Binary::readInt("\x00\x85\xb2\x4a")); } + $this->getLevel()->getLevel()->timings->syncChunkLoadEntitiesTimer->startTiming(); foreach($entities as $nbt){ if($nbt instanceof Compound){ if(!isset($nbt->id)){ @@ -115,8 +116,9 @@ abstract class BaseChunk implements Chunk{ } } } + $this->getLevel()->getLevel()->timings->syncChunkLoadEntitiesTimer->stopTiming(); - + $this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->startTiming(); foreach($tiles as $nbt){ if($nbt instanceof Compound){ if(!isset($nbt->id)){ @@ -135,6 +137,7 @@ abstract class BaseChunk implements Chunk{ } } } + $this->getLevel()->getLevel()->timings->syncChunkLoadTileEntitiesTimer->stopTiming(); } public function getX(){ diff --git a/src/pocketmine/tile/Tile.php b/src/pocketmine/tile/Tile.php index a20fe7f21..593dce1a2 100644 --- a/src/pocketmine/tile/Tile.php +++ b/src/pocketmine/tile/Tile.php @@ -25,6 +25,7 @@ */ namespace pocketmine\tile; +use pocketmine\event\Timings; use pocketmine\level\format\Chunk; use pocketmine\level\Position; use pocketmine\nbt\tag\Compound; @@ -57,6 +58,9 @@ abstract class Tile extends Position{ protected $lastUpdate; protected $server; + /** @var \pocketmine\event\TimingsHandler */ + public $tickTimer; + public function __construct(Chunk $chunk, Compound $nbt){ $this->server = $chunk->getLevel()->getLevel()->getServer(); $this->chunk = $chunk; @@ -72,6 +76,7 @@ abstract class Tile extends Position{ $this->chunk->addTile($this); $this->getLevel()->addTile($this); + $this->tickTimer = Timings::getTileEntityTimings($this); } public function getID(){ diff --git a/src/raklib b/src/raklib index 577c371aa..df53c0844 160000 --- a/src/raklib +++ b/src/raklib @@ -1 +1 @@ -Subproject commit 577c371aa07bd2aa3cedc3b7d4bcdc1d54999c70 +Subproject commit df53c0844231a2ddc340dcd13a77944ca8822d27 From 35ea9708a5ecfcd1a0b846852ad940edf686363e Mon Sep 17 00:00:00 2001 From: KnownUnown Date: Sat, 12 Jul 2014 11:36:03 -0500 Subject: [PATCH 14/18] Fix formality mistake Contractions such as "I've" should not be used in formal writing. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7ad91d78f..8e560f707 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ Before contributing to PocketMine-MP, please read this. Also, take a look if your contribution fits the PocketMine-MP goals below. -## I've a question +## I have a question * For questions, please refer to the _#pocketmine_ or _#mcpedevs_ IRC channel on Freenode. There is a [WebIRC](http://webchat.freenode.net?channels=pocketmine,mcpedevs&uio=d4) if you want. * You can ask directly to _[@PocketMine](https://twitter.com/PocketMine)_ in Twitter, but don't expect an inmediate reply. From a7944502cdf7f9f1645e645741c3543168f40393 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sat, 12 Jul 2014 19:27:51 +0200 Subject: [PATCH 15/18] Added small things --- src/pocketmine/PocketMine.php | 2 +- src/pocketmine/Server.php | 5 +++- src/pocketmine/level/Level.php | 11 +++++-- src/pocketmine/level/format/anvil/Anvil.php | 14 +++++++-- .../scheduler/PHPGarbageCollectionTask.php | 30 +++++++++++++++++++ src/pocketmine/scheduler/ServerScheduler.php | 2 +- 6 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 src/pocketmine/scheduler/PHPGarbageCollectionTask.php diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index 6c6639ac3..7e44e9699 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -135,7 +135,7 @@ namespace pocketmine { } } - gc_enable(); + gc_disable(); error_reporting(E_ALL | E_STRICT); ini_set("allow_url_fopen", 1); ini_set("display_errors", 1); diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 158e5cc8f..3857bb578 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -73,6 +73,7 @@ use pocketmine\plugin\Plugin; use pocketmine\plugin\PluginLoadOrder; use pocketmine\plugin\PluginManager; use pocketmine\scheduler\CallbackTask; +use pocketmine\scheduler\PHPGarbageCollectionTask; use pocketmine\scheduler\SendUsageTask; use pocketmine\scheduler\ServerScheduler; use pocketmine\tile\Tile; @@ -1521,9 +1522,11 @@ class Server{ } if($this->getProperty("chunk-gc.period-in-ticks", 600) > 0){ - $this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask(array($this, "doLevelGC")), $this->getProperty("chunk-gc.period-in-ticks", 600), $this->getProperty("chunk-gc.period-in-ticks", 600)); + $this->scheduler->scheduleDelayedRepeatingTask(new CallbackTask([$this, "doLevelGC"]), $this->getProperty("chunk-gc.period-in-ticks", 600), $this->getProperty("chunk-gc.period-in-ticks", 600)); } + $this->scheduler->scheduleRepeatingTask(new PHPGarbageCollectionTask(), 100); + $this->enablePlugins(PluginLoadOrder::POSTWORLD); } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 383aed897..a2fa2d341 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -341,7 +341,7 @@ class Level implements ChunkManager, Metadatable{ */ public function freeAllChunks(Player $player){ foreach($this->usedChunks as $i => $c){ - unset($this->usedChunks[$i][spl_object_hash($player)]); + unset($this->usedChunks[$i][$player->getID()]); } } @@ -354,7 +354,7 @@ class Level implements ChunkManager, Metadatable{ * @param Player $player */ public function freeChunk($X, $Z, Player $player){ - unset($this->usedChunks[Level::chunkHash($X, $Z)][$player->getID()]); + unset($this->usedChunks[$index = Level::chunkHash($X, $Z)][$player->getID()]); $this->unloadChunkRequest($X, $Z, true); } @@ -1523,6 +1523,7 @@ class Level implements ChunkManager, Metadatable{ $this->timings->doChunkUnload->startTiming(); $this->provider->unloadChunk($x, $z, $safe); + unset($this->usedChunks[Level::chunkHash($x, $z)]); Cache::remove("world:" . $this->getID() . ":$x:$z"); $this->timings->doChunkUnload->stopTiming(); @@ -1682,7 +1683,7 @@ class Level implements ChunkManager, Metadatable{ } public function regenerateChunk($x, $z){ - $this->unloadChunk($x, $z); + $this->unloadChunk($x, $z, false); $this->cancelUnloadChunkRequest($x, $z); @@ -1714,6 +1715,10 @@ class Level implements ChunkManager, Metadatable{ if(count($c) === 0){ Level::getXZ($i, $X, $Z); if(!$this->isSpawnChunk($X, $Z)){ + if($this->getAutoSave()){ + $this->provider->saveChunk($X, $Z); + } + $this->unloadChunk($X, $Z, true); } } diff --git a/src/pocketmine/level/format/anvil/Anvil.php b/src/pocketmine/level/format/anvil/Anvil.php index 4f0bbd131..f866c6c96 100644 --- a/src/pocketmine/level/format/anvil/Anvil.php +++ b/src/pocketmine/level/format/anvil/Anvil.php @@ -130,8 +130,8 @@ class Anvil extends BaseLevelProvider{ } public function unloadChunk($x, $z, $safe = true){ + $chunk = $this->getChunk($x, $z, false); if($safe === true and $this->isChunkLoaded($x, $z)){ - $chunk = $this->getChunk($x, $z); foreach($chunk->getEntities() as $entity){ if($entity instanceof Player){ return false; @@ -139,7 +139,17 @@ class Anvil extends BaseLevelProvider{ } } - unset($this->chunks[Level::chunkHash($x, $z)]); + foreach($chunk->getEntities() as $entity){ + $entity->close(); + } + + foreach($chunk->getTiles() as $tile){ + $tile->close(); + } + + $this->chunks[$index = Level::chunkHash($x, $z)] = null; + + unset($this->chunks[$index]); return true; } diff --git a/src/pocketmine/scheduler/PHPGarbageCollectionTask.php b/src/pocketmine/scheduler/PHPGarbageCollectionTask.php new file mode 100644 index 000000000..3adfabffe --- /dev/null +++ b/src/pocketmine/scheduler/PHPGarbageCollectionTask.php @@ -0,0 +1,30 @@ +handle(new TaskHandler(!($task instanceof PluginTask) ? "Scheduler" : null, $task, $this->nextId(), $delay, $period)); + return $this->handle(new TaskHandler(get_class($task), $task, $this->nextId(), $delay, $period)); } private function handle(TaskHandler $handler){ From e29ddadd2f4854a065cf3ad6056301d5dfa43411 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sun, 13 Jul 2014 01:04:10 +0200 Subject: [PATCH 16/18] Fixed #1642 --- src/pocketmine/Player.php | 3 +- src/pocketmine/Server.php | 1 + src/pocketmine/entity/Entity.php | 34 ++++++++------ src/pocketmine/entity/Human.php | 79 +++++++++++++++++--------------- 4 files changed, 65 insertions(+), 52 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 6f2bcf0bf..136cb52f6 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -505,9 +505,10 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{ $this->dataPacket($pk); $this->getLevel()->freeChunk($x, $z, $this); unset($this->usedChunks[$index]); + + $this->orderChunks(); } unset($this->loadQueue[$index]); - $this->orderChunks(); } /** diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 3857bb578..7aaae93d8 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1479,6 +1479,7 @@ class Server{ PluginManager::$pluginParentTimer = new TimingsHandler("** Plugins"); Timings::init(); + $this->pluginManager = new PluginManager($this, $this->commandMap); $this->pluginManager->subscribeToPermission(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $this->consoleSender); $this->pluginManager->setUseTimings($this->getProperty("settings.enable-profiling", false)); diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index e988cc426..169d53aa7 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -43,6 +43,8 @@ use pocketmine\metadata\Metadatable; use pocketmine\metadata\MetadataValue; use pocketmine\nbt\tag\Byte; use pocketmine\nbt\tag\Compound; +use pocketmine\nbt\tag\Double; +use pocketmine\nbt\tag\Enum; use pocketmine\nbt\tag\Float; use pocketmine\nbt\tag\Short; use pocketmine\network\protocol\MoveEntityPacket; @@ -202,22 +204,28 @@ abstract class Entity extends Position implements Metadatable{ } public function saveNBT(){ - $this->namedtag["Pos"][0] = $this->x; - $this->namedtag["Pos"][1] = $this->y; - $this->namedtag["Pos"][2] = $this->z; + $this->namedtag->Pos = new Enum("Pos", [ + new Double(0, $this->x), + new Double(1, $this->y), + new Double(2, $this->z) + ]); - $this->namedtag["Motion"][0] = $this->motionX; - $this->namedtag["Motion"][1] = $this->motionY; - $this->namedtag["Motion"][2] = $this->motionZ; + $this->namedtag->Motion = new Enum("Motion", [ + new Double(0, $this->motionX), + new Double(1, $this->motionY), + new Double(2, $this->motionZ) + ]); - $this->namedtag["Rotation"][0] = $this->yaw; - $this->namedtag["Rotation"][1] = $this->pitch; + $this->namedtag->Rotation = new Enum("Rotation", [ + new Float(0, $this->yaw), + new Float(1, $this->pitch) + ]); - $this->namedtag["FallDistance"] = $this->fallDistance; - $this->namedtag["Fire"] = $this->fireTicks; - $this->namedtag["Air"] = $this->airTicks; - $this->namedtag["OnGround"] = $this->onGround == true ? 1 : 0; - $this->namedtag["Invulnerable"] = $this->invulnerable == true ? 1 : 0; + $this->namedtag->FallDistance = new Float("FallDistance", $this->fallDistance); + $this->namedtag->Fire = new Short("Fire", $this->fireTicks); + $this->namedtag->Air = new Short("Air", $this->airTicks); + $this->namedtag->OnGround = new Byte("OnGround", $this->onGround == true ? 1 : 0); + $this->namedtag->Invulnerable = new Byte("Invulnerable", $this->invulnerable == true ? 1 : 0); } protected abstract function initEntity(); diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 1e7d4eded..1415a521a 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -21,6 +21,7 @@ namespace pocketmine\entity; +use pocketmine\inventory\Inventory; use pocketmine\inventory\InventoryHolder; use pocketmine\inventory\PlayerInventory; use pocketmine\item\Item; @@ -83,47 +84,36 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ parent::saveNBT(); $this->namedtag->Inventory = new Enum("Inventory", []); $this->namedtag->Inventory->setTagType(NBT::TAG_Compound); - for($slot = 0; $slot < 9; ++$slot){ - $hotbarSlot = $this->inventory->getHotbarSlotIndex($slot); - if($hotbarSlot !== -1){ - $item = $this->inventory->getItem($hotbarSlot); - if($item->getID() !== 0 and $item->getCount() > 0){ - $this->namedtag->Inventory[$slot] = new Compound(false, array( - new Byte("Count", $item->getCount()), - new Short("Damage", $item->getDamage()), - new Byte("Slot", $slot), - new Byte("TrueSlot", $hotbarSlot), - new Short("id", $item->getID()), - )); - continue; + if($this->inventory instanceof PlayerInventory){ + for($slot = 0; $slot < 9; ++$slot){ + $hotbarSlot = $this->inventory->getHotbarSlotIndex($slot); + if($hotbarSlot !== -1){ + $item = $this->inventory->getItem($hotbarSlot); + if($item->getID() !== 0 and $item->getCount() > 0){ + $this->namedtag->Inventory[$slot] = new Compound(false, array( + new Byte("Count", $item->getCount()), + new Short("Damage", $item->getDamage()), + new Byte("Slot", $slot), + new Byte("TrueSlot", $hotbarSlot), + new Short("id", $item->getID()), + )); + continue; + } } + $this->namedtag->Inventory[$slot] = new Compound(false, array( + new Byte("Count", 0), + new Short("Damage", 0), + new Byte("Slot", $slot), + new Byte("TrueSlot", -1), + new Short("id", 0), + )); } - $this->namedtag->Inventory[$slot] = new Compound(false, array( - new Byte("Count", 0), - new Short("Damage", 0), - new Byte("Slot", $slot), - new Byte("TrueSlot", -1), - new Short("id", 0), - )); - } - //Normal inventory - $slotCount = Player::SURVIVAL_SLOTS + 9; - //$slotCount = (($this instanceof Player and ($this->gamemode & 0x01) === 1) ? Player::CREATIVE_SLOTS : Player::SURVIVAL_SLOTS) + 9; - for($slot = 9; $slot < $slotCount; ++$slot){ - $item = $this->inventory->getItem($slot - 9); - $this->namedtag->Inventory[$slot] = new Compound(false, array( - new Byte("Count", $item->getCount()), - new Short("Damage", $item->getDamage()), - new Byte("Slot", $slot), - new Short("id", $item->getID()), - )); - } - - //Armor - for($slot = 100; $slot < 104; ++$slot){ - $item = $this->inventory->getItem($this->inventory->getSize() + $slot - 100); - if($item instanceof Item and $item->getID() !== Item::AIR){ + //Normal inventory + $slotCount = Player::SURVIVAL_SLOTS + 9; + //$slotCount = (($this instanceof Player and ($this->gamemode & 0x01) === 1) ? Player::CREATIVE_SLOTS : Player::SURVIVAL_SLOTS) + 9; + for($slot = 9; $slot < $slotCount; ++$slot){ + $item = $this->inventory->getItem($slot - 9); $this->namedtag->Inventory[$slot] = new Compound(false, array( new Byte("Count", $item->getCount()), new Short("Damage", $item->getDamage()), @@ -131,6 +121,19 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ new Short("id", $item->getID()), )); } + + //Armor + for($slot = 100; $slot < 104; ++$slot){ + $item = $this->inventory->getItem($this->inventory->getSize() + $slot - 100); + if($item instanceof Item and $item->getID() !== Item::AIR){ + $this->namedtag->Inventory[$slot] = new Compound(false, array( + new Byte("Count", $item->getCount()), + new Short("Damage", $item->getDamage()), + new Byte("Slot", $slot), + new Short("id", $item->getID()), + )); + } + } } } From fdb7fa36b87e48d7586c763261682443ad2a27e3 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Sun, 13 Jul 2014 01:10:16 +0200 Subject: [PATCH 17/18] Fixed #1641 --- src/raklib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raklib b/src/raklib index df53c0844..243e611b9 160000 --- a/src/raklib +++ b/src/raklib @@ -1 +1 @@ -Subproject commit df53c0844231a2ddc340dcd13a77944ca8822d27 +Subproject commit 243e611b935242ca33c082fee83c0f1f5cddaaf7 From 47503d84c234d3fbc6d02c140a54a126abe76317 Mon Sep 17 00:00:00 2001 From: PEMapModder Date: Sun, 13 Jul 2014 13:43:09 +0800 Subject: [PATCH 18/18] Added doccomment for Vector3::add() and Vector3::subtract() This is to avoid IDEs thinking that argument 1 for `Vector3::subtract()` must be an int. (But the fact is `Vector3` is OK too) --- src/pocketmine/math/Vector3.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/math/Vector3.php b/src/pocketmine/math/Vector3.php index 736c0ceb5..b44c0896c 100644 --- a/src/pocketmine/math/Vector3.php +++ b/src/pocketmine/math/Vector3.php @@ -80,6 +80,11 @@ class Vector3{ return $this->z; } + /** + * @param Vector3|int $x + * @param int $y + * @param int $z + */ public function add($x, $y = 0, $z = 0){ if($x instanceof Vector3){ return $this->add($x->x, $x->y, $x->z); @@ -88,6 +93,12 @@ class Vector3{ } } + /** + * @param Vector3|int $x + * @param int $y + * @param int $z + * @return Vector3 + */ public function subtract($x = 0, $y = 0, $z = 0){ if($x instanceof Vector3){ return $this->add(-$x->x, -$x->y, -$x->z); @@ -190,4 +201,4 @@ class Vector3{ return "Vector3(x=" . $this->x . ",y=" . $this->y . ",z=" . $this->z . ")"; } -} \ No newline at end of file +}