Added new Plugin and Permissions stuff :D

This commit is contained in:
Shoghi Cervantes 2014-03-23 00:22:14 +01:00
parent 28c5443b0d
commit af14c87572
13 changed files with 1255 additions and 257 deletions

View File

@ -22,19 +22,13 @@
namespace PocketMine;
use PocketMine\Network\Protocol\Info;
use PocketMine\PMF\Plugin as PMFPlugin;
use PocketMine\Utils\Config;
use PocketMine\Utils\TextFormat;
use PocketMine\Utils\Utils;
use PocketMine\Plugin\PluginManager;
class PluginAPI extends \stdClass{
private $server;
private $plugins = array();
private $randomNonce;
public function __construct(){
$this->server = ServerAPI::request();
$this->randomNonce = Utils::getRandomBytes(16, false);
$this->server->api->console->register("plugins", "", array($this, "commandHandler"));
$this->server->api->console->register("version", "", array($this, "commandHandler"));
$this->server->api->ban->cmdWhitelist("version");
@ -45,13 +39,14 @@ class PluginAPI extends \stdClass{
switch($cmd){
case "plugins":
$output = "Plugins: ";
foreach($this->getList() as $plugin){
$output .= $plugin["name"] . ": " . $plugin["version"] . ", ";
foreach(PluginManager::getPlugins() as $plugin){
$d = $plugin->getDescription();
$output .= $d->getName() . ": " . $d->getVersion() . ", ";
}
$output = $output === "Plugins: " ? "No plugins installed.\n" : substr($output, 0, -2) . "\n";
break;
case "version":
$output = "PocketMine-MP " . VERSION . "" . CODENAME . "」 API #" . API_VERSION . " for Minecraft: PE " . MINECRAFT_VERSION . " protocol #" . Info::CURRENT_PROTOCOL;
$output = "PocketMine-MP " . \PocketMine\VERSION . "" . \PocketMine\CODENAME . "」 API #" . \PocketMine\API_VERSION . " for Minecraft: PE " . \PocketMine\MINECRAFT_VERSION . " protocol #" . Info::CURRENT_PROTOCOL;
if(\PocketMine\GIT_COMMIT !== str_repeat("00", 20)){
$output .= " (git " . \PocketMine\GIT_COMMIT . ")";
}
@ -63,210 +58,9 @@ class PluginAPI extends \stdClass{
}
public function __destruct(){
foreach($this->plugins as $p){
$p[0]->__destruct();
}
unset($plugins);
}
public function getList(){
$list = array();
foreach($this->plugins as $p){
$list[] = $p[1];
}
return $list;
}
public function getAll(){
return $this->plugins;
}
public function load($file){
if(is_link($file) or is_dir($file) or !file_exists($file)){
console("[ERROR] " . basename($file) . " is not a file");
return false;
}
if(strtolower(substr($file, -3)) === "pmf"){
$pmf = new PMFPlugin($file);
$info = $pmf->getPluginInfo();
} else{
$content = file_get_contents($file);
$info = strstr($content, "*/", true);
$content = str_repeat(PHP_EOL, substr_count($info, "\n")) . substr(strstr($content, "*/"), 2);
if(preg_match_all('#([a-zA-Z0-9\-_]*)=([^\r\n]*)#u', $info, $matches) == 0){ //false or 0 matches
console("[ERROR] Failed parsing of " . basename($file));
return false;
}
$info = array();
foreach($matches[1] as $k => $i){
$v = $matches[2][$k];
switch(strtolower($v)){
case "on":
case "true":
case "yes":
$v = true;
break;
case "off":
case "false":
case "no":
$v = false;
break;
}
$info[$i] = $v;
}
$info["code"] = $content;
$info["class"] = trim(strtolower($info["class"]));
}
if(!isset($info["name"]) or !isset($info["version"]) or !isset($info["class"]) or !isset($info["author"])){
console("[ERROR] Failed parsing of " . basename($file));
return false;
}
console("[INFO] Loading plugin \"" . TextFormat::GREEN . $info["name"] . TextFormat::RESET . "\" " . TextFormat::AQUA . $info["version"] . TextFormat::RESET . " by " . TextFormat::AQUA . $info["author"] . TextFormat::RESET);
if($info["class"] !== "none" and class_exists($info["class"])){
console("[ERROR] Failed loading plugin: class already exists");
return false;
}
if(((!isset($pmf) and (include $file) === false) or (isset($pmf) and eval($info["code"]) === false)) and $info["class"] !== "none" and !class_exists($info["class"])){
console("[ERROR] Failed loading {$info['name']}: evaluation error");
return false;
}
$className = $info["class"];
$apiversion = array_map("intval", explode(",", (string) $info["apiversion"]));
if(!in_array(API_VERSION, $apiversion)){
console("[WARNING] Plugin \"" . $info["name"] . "\" may not be compatible with the API (" . $info["apiversion"] . " != " . API_VERSION . ")! It can crash or corrupt the server!");
}
$identifier = $this->getIdentifier($info["name"], $info["author"]);
if($info["class"] !== "none"){
$object = new $className($this->server->api, false);
if(!($object instanceof Plugin)){
console("[ERROR] Plugin \"" . $info["name"] . "\" doesn't use the Plugin Interface");
if(method_exists($object, "__destruct")){
$object->__destruct();
}
$object = null;
unset($object);
} else{
$this->plugins[$identifier] = array($object, $info);
}
} else{
$this->plugins[$identifier] = array(new DummyPlugin($this->server->api, false), $info);
}
return true;
}
public function getIdentifier($name, $author){
return sha1(trim(strtolower($name)), true) ^ sha1(trim(strtolower($author)), true) ^ sha1($this->randomNonce, true);
}
public function get($identifier){
if($identifier instanceof Plugin){
foreach($this->plugins as $p){
if($p[0] === $identifier){
return $p;
}
}
return false;
}
if(isset($this->plugins[$identifier])){
return $this->plugins[$identifier];
}
return false;
}
public function pluginsPath(){
$path = join(DIRECTORY_SEPARATOR, array(\PocketMine\DATA . "plugins", ""));
@mkdir($path);
return $path;
}
public function configPath(Plugin $plugin){
$p = $this->get($plugin);
$identifier = $this->getIdentifier($p[1]["name"], $p[1]["author"]);
if($p === false){
return false;
}
$path = $this->pluginsPath() . $p[1]["name"] . DIRECTORY_SEPARATOR;
$this->plugins[$identifier][1]["path"] = $path;
@mkdir($path);
return $path;
}
public function createConfig(Plugin $plugin, $default = array()){
$p = $this->get($plugin);
if($p === false){
return false;
}
$path = $this->configPath($plugin);
$cnf = new Config($path . "config.yml", Config::YAML, $default);
$cnf->save();
return $path;
}
public function readYAML($file){
return yaml_parse(preg_replace("#^([ ]*)([a-zA-Z_]{1}[^\:]*)\:#m", "$1\"$2\":", file_get_contents($file)));
}
public function writeYAML($file, $data){
return file_put_contents($file, yaml_emit($data, YAML_UTF8_ENCODING));
}
public function init(){
$this->server->event("server.start", array($this, "initAll"));
$this->loadAll();
}
private function loadAll(){
$dir = dir($this->pluginsPath());
while(false !== ($file = $dir->read())){
if($file{0} !== "."){
$ext = strtolower(substr($file, -3));
if($ext === "php" or $ext === "pmf"){
$this->load($dir->path . $file);
}
}
}
}
public function initAll(){
console("[INFO] Starting plugins...");
foreach($this->plugins as $p){
$p[0]->init(); //ARGHHH!!! Plugin loading randomly fails!!
}
}
}
interface Plugin{
public function __construct(ServerAPI $api, $server = false);
public function init();
public function __destruct();
}
class DummyPlugin implements Plugin{
public function __construct(ServerAPI $api, $server = false){
}
public function init(){
}
public function __destruct(){
}
}
}

View File

@ -31,6 +31,7 @@ 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;
@ -301,12 +302,6 @@ class Server{
public function addHandler($event, callable $callable, $priority = 5){
if(!is_callable($callable)){
return false;
} elseif(isset(Deprecation::$events[$event])){
$sub = "";
if(Deprecation::$events[$event] !== false){
$sub = " Substitute \"" . Deprecation::$events[$event] . "\" found.";
}
console("[ERROR] Event \"$event\" has been deprecated.$sub [Adding handle to " . (is_array($callable) ? get_class($callable[0]) . "::" . $callable[1] : $callable) . "]");
}
$priority = (int) $priority;
$hnid = $this->handCnt++;
@ -346,12 +341,6 @@ class Server{
break;
}
}
} elseif(isset(Deprecation::$events[$event])){
$sub = "";
if(Deprecation::$events[$event] !== false){
$sub = " Substitute \"" . Deprecation::$events[$event] . "\" found.";
}
console("[ERROR] Event \"$event\" has been deprecated.$sub [Handler]");
}
if($result !== false){
@ -460,11 +449,11 @@ class Server{
$p["rcon.password"] = "******";
}
$dump .= "server.properties: " . var_export($p, true) . "\r\n\r\n\r\n";
if($this->api->plugin instanceof PluginAPI){
$plist = $this->api->plugin->getList();
if(class_exists("PocketMine\\Plugin\\PluginManager", false)){
$dump .= "Loaded plugins:\r\n";
foreach($plist as $p){
$dump .= $p["name"] . " " . $p["version"] . " by " . $p["author"] . "\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";
}
@ -618,12 +607,6 @@ class Server{
$ev($data, $event);
}
}
} elseif(isset(Deprecation::$events[$event])){
$sub = "";
if(Deprecation::$events[$event] !== false){
$sub = " Substitute \"" . Deprecation::$events[$event] . "\" found.";
}
console("[ERROR] Event \"$event\" has been deprecated.$sub [Trigger]");
}
}

View File

@ -29,6 +29,8 @@ use PocketMine\Network\Protocol\Info;
use PocketMine\Network\Query\QueryHandler;
use PocketMine\Network\RCON\RCON;
use PocketMine\Network\UPnP\UPnP;
use PocketMine\Plugin\PluginManager;
use PocketMine\PMF\Plugin;
use PocketMine\Recipes\Crafting;
use PocketMine\Tile\Tile;
use PocketMine\Utils\Config;
@ -220,7 +222,7 @@ class ServerAPI{
}
}
$this->apiList[] = $this->plugin = new PluginAPI();
console("[INFO] Loaded ".count(PluginManager::loadPlugins(\PocketMine\DATA . "plugins/")). " plugin(s).");
}
@ -270,8 +272,9 @@ class ServerAPI{
public function sendUsage(){
console("[DEBUG] Sending usage data...", true, true, 2);
$plist = "";
foreach($this->plugin->getList() as $p){
$plist .= str_replace(array(";", ":"), "", $p["name"]) . ":" . str_replace(array(";", ":"), "", $p["version"]) . ";";
foreach(PluginManager::getPlugins() as $p){
$d = $p->getDescription();
$plist .= str_replace(array(";", ":"), "", $d->getName()) . ":" . str_replace(array(";", ":"), "", $d->getVersion()) . ";";
}
$this->asyncOperation(ASYNC_CURL_POST, array(

View File

@ -59,11 +59,12 @@ class QueryHandler{
public function regenerateInfo(){
$str = "";
$plist = "PocketMine-MP " . PocketMine\VERSION;
$pl = $this->server->api->plugin->getList();
$pl = PocketMine\Plugin\PluginManager::getPlugins();
if(count($pl) > 0){
$plist .= ":";
foreach($pl as $p){
$plist .= " " . str_replace(array(";", ":", " "), array("", "", "_"), $p["name"]) . " " . str_replace(array(";", ":", " "), array("", "", "_"), $p["version"]) . ";";
$d = $p->getDescription();
$plist .= " " . str_replace(array(";", ":", " "), array("", "", "_"), $d->getName()) . " " . str_replace(array(";", ":", " "), array("", "", "_"), $d->getVersion()) . ";";
}
$plist = substr($plist, 0, -1);
}

View File

@ -0,0 +1,60 @@
<?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\Permission;
use PocketMine;
interface Permissible extends ServerOperator{
/**
* Checks if this instance has a permission overridden
*
* @param string|Permission $name
*
* @return boolean
*/
public function isPermissionSet($name);
/**
* Returns the permission value if overridden, or the default value if not
*
* @param string|Permission $name
*
* @return mixed
*/
public function hasPermission($name);
//TODO: Attachment
/**
* @return void
*/
public function recalculatePermissions();
/**
* TODO: Check this
* @return Permission[]
*/
public function getEffectivePermissions();
}

View File

@ -0,0 +1,130 @@
<?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\Permission;
use PocketMine;
/**
* Represents a permission
*/
class Permission{
const DEFAULT_OP = "op";
const DEFAULT_NOT_OP = "notop";
const DEFAULT_TRUE = "true";
const DEFAULT_FALSE = "false";
public static $DEFAULT_PERMISSION = self::DEFAULT_OP;
private $name;
private $description;
private $children = array();
private $defaultValue;
/**
* Creates a new Permission object to be attached to Permissible objects
*
* @param string $name
* @param string $description
* @param string $defaultValue
* @param array $children
*/
public function __construct($name, $description = null, $defaultValue = null, array $children = array()){
$this->name = $name;
$this->description = $description !== null ? $description : "";
$this->defaultValue = $defaultValue !== null ? $defaultValue : self::$DEFAULT_PERMISSION;
$this->children = $children;
$this->recalculatePermissibles();
}
/**
* @return string
*/
public function getName(){
return $this->name;
}
/**
* @return array
*/
public function getChildren(){
return $this->children;
}
/**
* @return string
*/
public function getDefault(){
return $this->defaultValue;
}
/**
* @param string $value
*/
public function setDefault($value){
if($value !== $this->defaultValue){
$this->defaultValue = $value;
$this->recalculatePermissibles();
}
}
/**
* @return string
*/
public function getDescription(){
return $this->description;
}
/**
* @param string $value
*/
public function setDescription($value){
$this->description = $value;
}
public function getPermissibles(){
//TODO: get from plugin manager
//plugin handler -> getPermissionSubscriptions($this->name);
return array();
}
public function recalculatePermissibles(){
//TODO: recalculate
$perms = $this->getPermissibles();
//plugin handler -> recalculatePermissionDefaults($this);
foreach($perms as $p){
$p->recalculatePermissions();
}
}
public function addParent($name){
if($name instanceof Permission){
}else{
}
}
}

View File

@ -2,11 +2,11 @@
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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
@ -15,23 +15,28 @@
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*
*/
//TODO: REMOVE
namespace PocketMine\Permission;
namespace PocketMine;
use PocketMine;
class Deprecation{
public static $events = array(
"server.tick" => "ServerAPI::schedule()",
"server.time" => "time.change",
"world.block.change" => "block.change",
"block.drop" => "item.drop",
"api.op.check" => "op.check",
"api.player.offline.get" => "player.offline.get",
"api.player.offline.save" => "player.offline.save",
);
interface ServerOperator{
/**
* Checks if the current object has operator permissions
*
* @return bool
*/
public function isOp();
/**
* Sets the operator permission for the current object
*
* @param bool $value
*
* @return void
*/
public function setOp($value);
}

View File

@ -0,0 +1,76 @@
<?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\Plugin;
use PocketMine;
/**
* It is recommended to use PluginBase for the actual plugin
*
*/
interface Plugin{
/**
* Called when the plugin is loaded, before calling onEnable()
*/
public function onLoad();
public function onEnable();
public function isEnabled();
public function onDisable();
public function isDisabled();
public function getDataFolder();
/**
* @return PluginDescription
*/
public function getDescription();
/**
* Gets an embedded resource in the plugin file.
*/
public function getResource($filename);
public function saveResource($filename, $replace = false);
/**
* Returns all the resources incrusted in the plugin
*/
public function getResources();
public function getConfig();
public function saveConfig();
public function saveDefaultConfig();
public function reloadConfig();
public function getServer();
public function getName();
}

View File

@ -0,0 +1,202 @@
<?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\Plugin;
use PocketMine;
use PocketMine\Utils\Config;
abstract class PluginBase{
/** @var PocketMine\Server */
private $server;
private $isEnabled = false;
private $initialized = false;
/** @var PluginDescription */
private $description;
private $dataFolder;
private $config;
/** @var string */
private $configFile;
private $file;
/**
* Called when the plugin is loaded, before calling onLoad()
*/
public function onLoad(){
}
public function onEnable(){
}
public final function isEnabled(){
return $this->isEnabled === true;
}
public final function setEnabled($boolean = true){
if($this->isEnabled !== $boolean){
$this->isEnabled = $boolean;
if($this->isEnabled === true){
$this->onEnable();
}else{
$this->onDisable();
}
}
}
public function onDisable(){
}
public final function isDisabled(){
return $this->isEnabled === false;
}
public final function getDataFolder(){
return $this->dataFolder;
}
public final function getDescription(){
return $this->description;
}
protected final function initialize(PocketMine\Server $server, PluginDescription $description, $dataFolder, $file){
if($this->initialized === false){
$this->initialized = true;
$this->server = $server;
$this->description = $description;
$this->dataFolder = $dataFolder;
$this->file = $file;
$this->configFile = $this->dataFolder . "config.yml";
}
}
public final function isInitialized(){
return $this->initialized;
}
public function onCommand(CommandSender $sender, Command $command, $label, $args){
return false;
}
/* TODO
public function getCommand($name){
$this->get
}*/
/**
* Gets an embedded resource on the plugin file.
*
* @param string $filename
*
* @return bool|string Resource data, or false
*/
public function getResource($filename){
$filename = str_replace("\\", "/", $filename);
if(isset($this->phar) and $this->phar instanceof \Phar){
//TODO
}else{
if(file_exists($this->dataFolder . "resources/" . $filename)){
return file_get_contents($this->dataFolder . "resources/" . $filename);
}
return false;
}
}
public function saveResource($filename, $replace = false){
if(trim($filename) === ""){
return false;
}
if(($resource = $this->getResource($filename)) === false){
return false;
}
$out = $this->dataFolder . $filename;
if(!file_exists($this->dataFolder)){
@mkdir($this->dataFolder, 0755, true);
}
if(file_exists($out) and $replace !== true){
return false;
}
return @file_put_contents($out, $resource) !== false;
}
/**
* Returns all the resources incrusted on the plugin
*
* @return string[]
*/
public function getResources(){
if(!$this->isPhar()){
$resources = array();
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->dataFolder . "resources/")) as $resource){
$resources[] = $resource;
}
return $resources;
}
}
public function getConfig(){
if(!isset($this->config)){
$this->reloadConfig();
}
return $this->config;
}
public function saveConfig(){
if($this->getConfig()->save() === false){
console("[SEVERE] Could not save config to ". $this->configFile);
return false;
}
return true;
}
public function saveDefaultConfig(){
if(!file_exists($this->configFile)){
$this->saveResource("config.yml", false);
}
}
public function reloadConfig(){
$this->config = new Config($this->configFile);
if(($configStream = $this->getResource("config.yml")) !== false){
$this->config->setDefaults(yaml_parse(config::fixYAMLIndexes($configStream)));
}
}
public final function getServer(){
return $this->dataFolder;
}
public final function getName()
{
return $this->description->getName();
}
protected function getFile(){
return $this->file;
}
}

View File

@ -0,0 +1,207 @@
<?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\Plugin;
use PocketMine;
use PocketMine\Permission\Permission;
class PluginDescription{
private $name;
private $main;
private $api;
private $depend = array();
private $softDepend = array();
private $loadBefore = array();
private $version;
private $commands = array();
private $description = null;
private $authors = array();
private $website = null;
private $order = PluginLoadOrder::POSTWORLD;
/**
* @var Permission[]
*/
private $permissions = array();
/**
* @param string $yamlString
*/
public function __construct($yamlString){
$this->loadMap(\yaml_parse($yamlString));
}
private function loadMap(array $plugin){
$this->name = preg_replace("[^A-Za-z0-9 _.-]", "", $plugin["name"]);
if($this->name === ""){
trigger_error("Invalid PluginDescription name", E_USER_WARNING);
return;
}
$this->name = str_replace(" ", "_", $this->name);
$this->version = $plugin["version"];
$this->main = $plugin["main"];
$this->api = !is_array($plugin["api"]) ? array($plugin["api"]) : $plugin["api"];
if(stripos($this->main, "PocketMine\\") === 0){
trigger_error("Invalid PluginDescription main, cannot start within the PocketMine namespace", E_USER_ERROR);
return;
}
//TODO: commands
if(isset($plugin["depend"])){
$this->depend = (array) $plugin["depend"];
}
if(isset($plugin["softdepend"])){
$this->softDepend = (array) $plugin["softdepend"];
}
if(isset($plugin["loadbefore"])){
$this->loadBefore = (array) $plugin["loadbefore"];
}
if(isset($plugin["website"])){
$this->website = $plugin["website"];
}
if(isset($plugin["description"])){
$this->description = $plugin["description"];
}
if(isset($plugin["load"])){
$order = strtoupper($plugin["load"]);
if(!defined("PocketMine\\Plugin\\PluginLoadOrder::" . $order)){
trigger_error("Invalid PluginDescription load", E_USER_ERROR);
return;
}else{
$this->order = constant("PocketMine\\Plugin\\PluginLoadOrder::" . $order);
}
}
if(isset($plugin["authors"])){
$this->authors = $plugin["authors"];
}elseif(isset($plugin["author"])){
$this->authors = array($plugin["author"]);
}else{
$this->authors = array();
}
//TODO: Do permissions
}
/**
* @return array
*/
public function getCompatibleApis(){
return $this->api;
}
/**
* @return array
*/
public function getAuthors(){
return $this->authors;
}
/**
* @return array
*/
public function getCommands(){
return $this->commands;
}
/**
* @return array
*/
public function getDepend()
{
return $this->depend;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* @return array
*/
public function getLoadBefore()
{
return $this->loadBefore;
}
/**
* @return string
*/
public function getMain()
{
return $this->main;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return int
*/
public function getOrder()
{
return $this->order;
}
/**
* @return Permission[]
*/
public function getPermisions()
{
return $this->permissions;
}
/**
* @return array
*/
public function getSoftDepend()
{
return $this->softDepend;
}
/**
* @return string
*/
public function getVersion()
{
return $this->version;
}
/**
* @return string
*/
public function getWebsite()
{
return $this->website;
}
}

View File

@ -0,0 +1,41 @@
<?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\Plugin;
use PocketMine;
abstract class PluginLoadOrder{
/*
* Load before loading other PocketMine API's.
*/
const SYSTEM = 0;
/*
* The plugin will be loaded after the first world has been loaded/created.
*/
const PREWORLD = 1;
/*
* The plugin will be loaded after the first world has been loaded/created.
*/
const POSTWORLD = 1;
}

View File

@ -0,0 +1,57 @@
<?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\Plugin;
/**
* Handles different types of plugins
*/
interface PluginLoader{
/**
* Loads the plugin contained in $file
*
* @param string $file
*
* @return Plugin
*/
public function loadPlugin($file);
/**
* Gets the PluginDescription from the file
*
* @param string $file
*
* @return PluginDescription
*/
public function getPluginDescription($file);
/**
* Returns the filename patterns that this loader accepts
*
* @return array
*/
public function getPluginFilters();
public function enablePlugin(Plugin $plugin);
public function disablePlugin(Plugin $plugin);
}

View File

@ -0,0 +1,439 @@
<?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\Plugin;
use PocketMine;
use PocketMine\Permission\Permission;
use PocketMine\Permission\Permissible;
/**
* Manages all the plugins, Permissions and Permissibles
*/
abstract class PluginManager{
/**
* @var Plugin[]
*/
protected static $plugins = array();
/**
* @var Permission[]
*/
protected static $permissions = array();
/**
* @var Permission[]
*/
protected static $defaultPerms = array();
/**
* @var Permission[]
*/
protected static $defaultPermsOp = array();
/**
* @var Permissible[]
*/
protected static $permSubs = array();
/**
* @var Permissible[]
*/
protected static $defSubs = array();
/**
* @var Permissible[]
*/
protected static $defSubsOp = array();
/**
* @var PluginLoader[]
*/
protected static $fileAssociations = array();
/**
* @param string $name
*
* @return null|Plugin
*/
public static function getPlugin($name){
if(isset(static::$plugins[$name])){
return static::$plugins[$name];
}
return null;
}
/**
* @param string|PluginLoader $loader
*
* @return boolean
*/
public static function registerInterface($loader){
if(is_object($loader) and !($loader instanceof PluginLoader)){
return false;
}elseif(is_string($loader)){
if(is_subclass_of($loader, "PocketMine\\Plugin\\PluginLoader")){
$loader = new $loader;
}else{
return false;
}
}
static::$fileAssociations[spl_object_hash($loader)] = array($loader, $loader->getPluginFilters());
return true;
}
/**
* @return Plugin[]
*/
public static function getPlugins(){
return static::$plugins;
}
/**
* @param string $path
*
* @return Plugin
*/
public static function loadPlugin($path){
foreach(static::$fileAssociations as $loader){
if(preg_match($loader[1], basename($file)) > 0){
$description = $loader[0]->getPluginDescription($path);
if($description instanceof PluginDescription){
return $loader[0]->loadPlugin($path);
}
}
}
return null;
}
/**
* @param $directory
*
* @return Plugin[]
*/
public static function loadPlugins($directory){
if(is_dir($directory)){
$plugins = array();
$loadedPlugins = array();
$dependencies = array();
$softDependencies = array();
foreach(new \IteratorIterator(new \DirectoryIterator($directory)) as $file){
foreach(static::$fileAssociations as $loader){
if(preg_match($loader[1], basename($file)) > 0){
$description = $loader[0]->getPluginDescription($file);
if($description instanceof PluginDescription){
$name = $description->getName();
if(stripos($name, "pocketmine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){
console("[ERROR] Could not load plugin '".$name."': restricted name");
continue;
}elseif(strpos($name, " ") !== false){
console("[WARNING] Plugin '".$name."' uses spaces in its name, this is discouraged");
}
if(isset($plugins[$name])){
console("[ERROR] Could not load duplicate plugin '".$name."': plugin exists");
continue;
}
$compatible = false;
//Check multiple dependencies
foreach($description->getCompatibleApis() as $version){
//Format: majorVersion.minorVersion.patch
$version = array_map("intval", explode(".", $version));
$apiVersion = array_map("intval", explode(".", PocketMine\API_VERSION));
//Completely different API version
if($version[0] !== $apiVersion[0]){
continue;
}
//If the plugin requires new API features, being backwards compatible
if($version[1] > $apiVersion[1]){
continue;
}
$compatible = true;
break;
}
if($compatible === false){
console("[ERROR] Could not load plugin '".$name."': API version not compatible");
continue;
}
$plugins[$name] = $file;
$softDependencies[$name] = (array) $description->getSoftDepend();
$dependencies[$name] = (array) $description->getDepend();
foreach($description->getLoadBefore() as $before){
if(isset($softDependencies[$before])){
$softDependencies[$before][] = $name;
}else{
$softDependencies[$before] = array($name);
}
}
break;
}
}
}
}
while(count($plugins) > 0){
$missingDependency = true;
foreach($plugins as $name => $file){
if(isset($dependencies[$name])){
foreach($dependencies[$name] as $key => $dependency){
if(isset($loadedPlugins[$dependency])){
unset($dependencies[$name][$key]);
}elseif(!isset($plugins[$dependency])){
console("[SEVERE] Could not load plugin '".$name."': Unknown dependency");
break;
}
}
if(count($dependencies[$name]) === 0){
unset($dependencies[$name]);
}
}
if(isset($softDependencies[$name])){
foreach($softDependencies[$name] as $key => $dependency){
if(isset($loadedPlugins[$dependency])){
unset($softDependencies[$name][$key]);
}
}
if(count($softDependencies[$name]) === 0){
unset($softDependencies[$name]);
}
}
if(!isset($dependencies[$name]) and !isset($softDependencies[$name])){
unset($plugins[$name]);
$missingDependency = false;
if($plugin = static::loadPlugin($file) and $plugin instanceof Plugin){
$loadedPlugins[$name] = $plugin;
}else{
console("[SEVERE] Could not load plugin '".$name."'");
}
}
}
if($missingDependency === true){
foreach($plugins as $name => $file){
if(!isset($dependencies[$name])){
unset($softDependencies[$name]);
unset($plugins[$name]);
$missingDependency = false;
if($plugin = static::loadPlugin($file) and $plugin instanceof Plugin){
$loadedPlugins[$name] = $plugin;
}else{
console("[SEVERE] Could not load plugin '".$name."'");
}
}
}
//No plugins loaded :(
if($missingDependency === true){
foreach($plugins as $name => $file){
console("[SEVERE] Could not load plugin '".$name."': circular dependency detected");
}
$plugins = array();
}
}
}
return $loadedPlugins;
}else{
return array();
}
}
/**
* @param string $name
*
* @return null|Permission
*/
public static function getPermission($name){
if(isset(static::$permissions[$name])){
return static::$permissions[$name];
}
return null;
}
/**
* @param Permission $permission
*
* @return bool
*/
public static function addPermission(Permission $permission){
if(!isset(static::$permissions[$permission->getName()])){
static::$permissions[$permission->getName()] = $permission;
static::calculatePermissionDefault($permission);
return true;
}
return false;
}
/**
* @param string|Permission $permission
*/
public function removePermission($permission){
if($permission instanceof Permission){
unset(static::$permissions[$permission->getName()]);
}else{
unset(static::$permissions[$permission]);
}
}
/**
* @param boolean $op
*
* @return Permission[]
*/
public static function getDefaultPermissions($op){
if($op === true){
return static::$defaultPermsOp;
}else{
return static::$defaultPerms;
}
}
/**
* @param Permission $permission
*/
public static function recalculatePermissionDefaults(Permission $permission){
if(isset(static::$permissions[$permission->getName()])){
unset(static::$defaultPermsOp[$permission->getName()]);
unset(static::$defaultPerms[$permission->getName()]);
static::calculatePermissionDefault($permission);
}
}
/**
* @param Permission $permission
*/
private static function calculatePermissionDefault(Permission $permission){
if($permission->getDefault() === Permission::DEFAULT_OP or $permission->getDefault() === Permission::DEFAULT_TRUE){
static::$defaultPermsOp[$permission->getName()] = $permission;
static::dirtyPermissibles(true);
}
if($permission->getDefault() === Permission::DEFAULT_NOT_OP or $permission->getDefault() === Permission::DEFAULT_TRUE){
static::$defaultPerms[$permission->getName()] = $permission;
static::dirtyPermissibles(false);
}
}
/**
* @param boolean $op
*/
private static function dirtyPermissibles($op){
foreach(static::getDefaultPermSubscriptions($op) as $p){
$p->recalculatePermissions();
}
}
/**
* @param string $permission
* @param Permissible $permissible
*/
public static function subscribeToPermission($permission, Permissible $permissible){
if(!isset(static::$permSubs[$permission])){
//TODO: Use WeakRef
static::$permSubs[$permission] = array();
}
static::$permSubs[$permission][spl_object_hash($permissible)] = $permissible;
}
/**
* @param string $permission
* @param Permissible $permissible
*/
public static function unsubscribeFromPermission($permission, Permissible $permissible){
if(isset(static::$permSubs[$permission])){
unset(static::$permSubs[$permission][spl_object_hash($permissible)]);
}
}
/**
* @param string $permission
*
* @return Permissible[]
*/
public static function getPermissionSubscriptions($permission){
if(isset(static::$permSubs[$permission])){
return static::$permSubs[$permission];
}
return array();
}
/**
* @param boolean $op
* @param Permissible $permissible
*/
public static function subscribeToDefaultPerms($op, Permissible $permissible){
if($op === true){
static::$defSubsOp[spl_object_hash($permissible)] = $permissible;
}else{
static::$defSubs[spl_object_hash($permissible)] = $permissible;
}
}
/**
* @param boolean $op
* @param Permissible $permissible
*/
public static function unsubscribeFromDefaultPerms($op, Permissible $permissible){
if($op === true){
unset(static::$defSubsOp[spl_object_hash($permissible)]);
}else{
unset(static::$defSubs[spl_object_hash($permissible)]);
}
}
/**
* @param boolean $op
*
* @return Permissible[]
*/
public static function getDefaultPermSubscriptions($op){
if($op === true){
return static::$defSubsOp;
}else{
return static::$defSubs;
}
}
/**
* @return Permission[]
*/
public static function getPermissions(){
return static::$permissions;
}
}