From 993620341a7b6eb35a24aa312cd5adbac69a34f7 Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Thu, 6 Mar 2014 23:33:35 +0100 Subject: [PATCH] Added Villager class and NPC interface --- src/ServerAPI.php | 4 +- src/block/GlowingRedstoneOre.php | 2 - src/block/RedstoneOre.php | 1 - src/entity/NPC.php | 28 +++++ src/entity/Villager.php | 41 +++++++ src/utils/Cache.php | 25 +++++ src/utils/Config.php | 32 ++++-- src/utils/Random.php | 54 ++++++++- src/utils/TextFormat.php | 35 ++++++ src/utils/Utils.php | 184 ++++++++++++++++++++++++++----- src/utils/pthreads.php | 4 +- 11 files changed, 362 insertions(+), 48 deletions(-) create mode 100644 src/entity/NPC.php create mode 100644 src/entity/Villager.php diff --git a/src/ServerAPI.php b/src/ServerAPI.php index 391f7a915..90fd1d675 100644 --- a/src/ServerAPI.php +++ b/src/ServerAPI.php @@ -178,7 +178,7 @@ class ServerAPI{ console("[INFO] Checking for new server version"); console("[INFO] Last check: " . TextFormat::AQUA . date("Y-m-d H:i:s", $this->getProperty("last-update")) . "\x1b[0m"); if($this->server->version->isDev()){ - $info = json_decode(Utils::curl_get("https://api.github.com/repos/PocketMine/PocketMine-MP/commits"), true); + $info = json_decode(Utils::getURL("https://api.github.com/repos/PocketMine/PocketMine-MP/commits"), true); if($info === false or !isset($info[0])){ console("[ERROR] Github API error"); } else{ @@ -195,7 +195,7 @@ class ServerAPI{ } } } else{ - $info = json_decode(Utils::curl_get("https://api.github.com/repos/PocketMine/PocketMine-MP/tags"), true); + $info = json_decode(Utils::getURL("https://api.github.com/repos/PocketMine/PocketMine-MP/tags"), true); if($info === false or !isset($info[0])){ console("[ERROR] Github API error"); } else{ diff --git a/src/block/GlowingRedstoneOre.php b/src/block/GlowingRedstoneOre.php index 683db6685..02000f688 100644 --- a/src/block/GlowingRedstoneOre.php +++ b/src/block/GlowingRedstoneOre.php @@ -37,8 +37,6 @@ class GlowingRedstoneOre extends Solid{ $this->level->setBlock($this, Block::get(REDSTONE_ORE, $this->meta), false, false, true); return BLOCK_UPDATE_WEAK; - } else{ - $this->level->scheduleBlockUpdate(new Position($this, 0, 0, $this->level), Utils::getRandomUpdateTicks(), BLOCK_UPDATE_RANDOM); } return false; diff --git a/src/block/RedstoneOre.php b/src/block/RedstoneOre.php index 77bec6d86..761eb1646 100644 --- a/src/block/RedstoneOre.php +++ b/src/block/RedstoneOre.php @@ -33,7 +33,6 @@ class RedstoneOre extends Solid{ public function onUpdate($type){ if($type === BLOCK_UPDATE_NORMAL or $type === BLOCK_UPDATE_TOUCH){ $this->level->setBlock($this, Block::get(GLOWING_REDSTONE_ORE, $this->meta), false, false, true); - $this->level->scheduleBlockUpdate(new Position($this, 0, 0, $this->level), Utils::getRandomUpdateTicks(), BLOCK_UPDATE_RANDOM); return BLOCK_UPDATE_WEAK; } diff --git a/src/entity/NPC.php b/src/entity/NPC.php new file mode 100644 index 000000000..cfb1c8155 --- /dev/null +++ b/src/entity/NPC.php @@ -0,0 +1,28 @@ + $data){ diff --git a/src/utils/Config.php b/src/utils/Config.php index a92fada82..a4fe40d2b 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -75,16 +75,19 @@ class Config{ ); /** - * @param string $file - * @param int $type - * @param array $default - * @param null|boolean $correct + * @param $file Path of the file to be loaded + * @param int $type Config type to load, -1 by default (detect) + * @param array $default Array with the default values, will be set if not existent + * @param null &$correct Sets correct to true if everything has been loaded correctly */ public function __construct($file, $type = Config::DETECT, $default = array(), &$correct = null){ $this->load($file, $type, $default); $correct = $this->correct; } + /** + * Removes all the changes in memory and loads the file again + */ public function reload(){ unset($this->config); unset($this->correct); @@ -92,16 +95,21 @@ class Config{ $this->load($this->file); } - public function fixYAMLIndexes($str){ + /** + * @param $str + * + * @return mixed + */ + public static function fixYAMLIndexes($str){ return preg_replace("#^([ ]*)([a-zA-Z_]{1}[^\:]*)\:#m", "$1\"$2\":", $str); } /** - * @param string $file - * @param int $type - * @param array $default + * @param $file + * @param int $type + * @param array $default * - * @return boolean + * @return bool */ public function load($file, $type = Config::DETECT, $default = array()){ $this->correct = true; @@ -134,7 +142,7 @@ class Config{ $this->config = @json_decode($content, true); break; case Config::YAML: - $content = $this->fixYAMLIndexes($content); + $content = self::fixYAMLIndexes($content); $this->config = yaml_parse($content); break; case Config::SERIALIZED: @@ -249,8 +257,8 @@ class Config{ } /** - * @param $k - * @param bool $v + * @param $k key to be set + * @param bool $v value to set key */ public function set($k, $v = true){ $this->config[$k] = $v; diff --git a/src/utils/Random.php b/src/utils/Random.php index b0c60c99d..6dc1ac290 100644 --- a/src/utils/Random.php +++ b/src/utils/Random.php @@ -23,36 +23,75 @@ namespace PocketMine\Utils; use PocketMine; -//Unsecure, not used for "Real Randomness" +/** + * Class Random + * + * Unsecure Random Number Generator, used for fast seeded values + * + * @package PocketMine\Utils + */ class Random{ private $z, $w; + /** + * @param int|bool $seed Integer to be used as seed. If false, generates a Random one + */ public function __construct($seed = false){ $this->setSeed($seed); } + /** + * @param int|bool $seed Integer to be used as seed. If false, generates a Random one + */ public function setSeed($seed = false){ $seed = $seed !== false ? (int) $seed : Utils::readInt(Utils::getRandomBytes(4, false)); $this->z = $seed ^ 0xdeadbeef; $this->w = $seed ^ 0xc0de1337; } + /** + * Returns an 31-bit integer (not signed) + * + * @return int + */ public function nextInt(){ return Utils::readInt($this->nextBytes(4)) & 0x7FFFFFFF; } + /** + * Returns a 32-bit integer (signed) + * + * @return int + */ public function nextSignedInt(){ return Utils::readInt($this->nextBytes(4)); } + /** + * Returns a float between 0.0 and 1.0 (inclusive) + * + * @return float + */ public function nextFloat(){ return $this->nextInt() / 0x7FFFFFFF; } + /** + * Returns a float between -1.0 and 1.0 (inclusive) + * + * @return float + */ public function nextSignedFloat(){ return $this->nextSignedInt() / 0x7FFFFFFF; } + /** + * Returns $byteCount random bytes + * + * @param $byteCount + * + * @return string + */ public function nextBytes($byteCount){ $bytes = ""; while(strlen($bytes) < $byteCount){ @@ -64,10 +103,23 @@ class Random{ return substr($bytes, 0, $byteCount); } + /** + * Returns a random boolean + * + * @return bool + */ public function nextBoolean(){ return ($this->nextSignedInt() & 0x01) === 0; } + /** + * Returns a random integer between $start and $end + * + * @param int $start default 0 + * @param int $end default PHP_INT_MAX + * + * @return int + */ public function nextRange($start = 0, $end = PHP_INT_MAX){ return $start + ($this->nextInt() % ($end + 1 - $start)); } diff --git a/src/utils/TextFormat.php b/src/utils/TextFormat.php index e0f315ec1..92327d0ef 100644 --- a/src/utils/TextFormat.php +++ b/src/utils/TextFormat.php @@ -23,6 +23,13 @@ namespace PocketMine\Utils; use PocketMine; +/** + * Class TextFormat + * + * Class used to handle Minecraft chat format, and convert it to other formats like ANSI or HTML + * + * @package PocketMine\Utils + */ class TextFormat{ const BLACK = "§0"; const DARK_BLUE = "§1"; @@ -48,14 +55,35 @@ class TextFormat{ const ITALIC = "§o"; const RESET = "§r"; + /** + * Splits the string by Format tokens + * + * @param string $string + * + * @return array + */ public static function tokenize($string){ return preg_split("/(§[0123456789abcdefklmnor])/", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); } + /** + * Cleans the string from Minecraft codes and ANSI Escape Codes + * + * @param string $string + * + * @return mixed + */ public static function clean($string){ return preg_replace(array("/§[0123456789abcdefklmnor]/", "/\\x1b*/"), "", $string); } + /** + * Returns an HTML-formatted string with colors/markup + * + * @param string|array $string + * + * @return string + */ public static function toHTML($string){ if(!is_array($string)){ $string = self::tokenize($string); @@ -165,6 +193,13 @@ class TextFormat{ return $newString; } + /** + * Returns a string with colorized ANSI Escape codes + * + * @param $string + * + * @return string + */ public static function toANSI($string){ if(!is_array($string)){ $string = self::tokenize($string); diff --git a/src/utils/Utils.php b/src/utils/Utils.php index 6cd6a03e1..5703d24bc 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -27,6 +27,12 @@ namespace PocketMine\Utils; use PocketMine; use PocketMine\Item\Item as Item; +/** + * Class Utils + * Big collection of functions + * + * @package PocketMine\Utils + */ class Utils{ const BIG_ENDIAN = 0x00; const LITTLE_ENDIAN = 0x01; @@ -35,14 +41,32 @@ class Utils{ public static $online = true; public static $ip = false; + /** + * Generates an unique identifier to a callable + * + * @param callable $variable + * + * @return string + */ public static function getCallableIdentifier(callable $variable){ if(is_array($variable)){ - return sha1(strtolower(get_class($variable[0])) . "::" . strtolower($variable[1])); + return sha1(strtolower(spl_object_hash($variable[0])) . "::" . strtolower($variable[1])); } else{ return sha1(strtolower($variable)); } } + /** + * Gets this machine / server instance unique ID + * Returns a hash, the first 32 characters (or 16 if raw) + * will be an identifier that won't change frequently. + * The rest of the hash will change depending on other factors. + * + * @param bool $raw default false, if true, returns the raw identifier, not hexadecimal + * @param string $extra optional, additional data to identify the machine + * + * @return string + */ public static function getUniqueID($raw = false, $extra = ""){ $machine = php_uname("a"); $machine .= file_exists("/proc/cpuinfo") ? file_get_contents("/proc/cpuinfo") : ""; @@ -71,25 +95,33 @@ class Utils{ return hash("md5", $machine, $raw) . hash("sha512", $data, $raw); } + /** + * Gets the External IP using an external service, it is cached + * + * @param bool $force default false, force IP check even when cached + * + * @return string + */ + public static function getIP($force = false){ if(Utils::$online === false){ return false; } elseif(Utils::$ip !== false and $force !== true){ return Utils::$ip; } - $ip = trim(strip_tags(Utils::curl_get("http://checkip.dyndns.org/"))); + $ip = trim(strip_tags(Utils::getURL("http://checkip.dyndns.org/"))); if(preg_match('#Current IP Address\: ([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){ Utils::$ip = $matches[1]; } else{ - $ip = Utils::curl_get("http://www.checkip.org/"); + $ip = Utils::getURL("http://www.checkip.org/"); if(preg_match('#">([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){ Utils::$ip = $matches[1]; } else{ - $ip = Utils::curl_get("http://checkmyip.org/"); + $ip = Utils::getURL("http://checkmyip.org/"); if(preg_match('#Your IP address is ([0-9a-fA-F\:\.]*)#', $ip, $matches) > 0){ Utils::$ip = $matches[1]; } else{ - $ip = trim(Utils::curl_get("http://ifconfig.me/ip")); + $ip = trim(Utils::getURL("http://ifconfig.me/ip")); if($ip != ""){ Utils::$ip = $ip; } else{ @@ -103,6 +135,18 @@ class Utils{ } + /** + * Returns the current Operating System + * Windows => win + * MacOS => mac + * iOS => ios + * Android => android + * Linux => Linux + * BSD => bsd + * Other => other + * + * @return string + */ public static function getOS(){ $uname = php_uname("s"); if(stripos($uname, "Darwin") !== false){ @@ -126,6 +170,13 @@ class Utils{ } } + /** + * Returns a prettified hexdump + * + * @param string $bin + * + * @return string + */ public static function hexdump($bin){ $output = ""; $bin = str_split($bin, 16); @@ -138,6 +189,14 @@ class Utils{ return $output; } + + /** + * Returns a string that can be printed, replaces non-printable characters + * + * @param $str + * + * @return string + */ public static function printable($str){ if(!is_string($str)){ return gettype($str); @@ -146,20 +205,37 @@ class Utils{ return preg_replace('#([^\x20-\x7E])#', '.', $str); } + /** + * Reads a 3-byte big-endian number + * + * @param $str + * + * @return mixed + */ public static function readTriad($str){ list(, $unpacked) = @unpack("N", "\x00" . $str); return $unpacked; } + /** + * Writes a 3-byte big-endian number + * @param $value + * + * @return string + */ public static function writeTriad($value){ return substr(pack("N", $value), 1); } - public static function getRandomUpdateTicks(){ - return -log(lcg_value()) * 1365.4; //Poisson distribution (1/(68.27 * 20)) - } - + /** + * Writes a coded metadata string + * TODO: Replace and move this to entity + * + * @param $data + * + * @return string + */ public static function writeMetadata($data){ $m = ""; foreach($data as $bottom => $d){ @@ -198,10 +274,25 @@ class Utils{ return $m; } + /** + * Writes a Item to binary (short id, byte Count, short Damage) + * + * @param Item $item + * + * @return string + */ public static function writeSlot(Item $item){ return Utils::writeShort($item->getID()) . chr($item->getCount()) . Utils::writeShort($item->getMetadata()); } + /** + * Reads a binary Item, returns an Item object + * + * @param $ob + * + * @return Item + */ + public static function readSlot($ob){ $id = Utils::readShort($ob->get(2)); $cnt = ord($ob->get(1)); @@ -213,6 +304,15 @@ class Utils{ ); } + /** + * Reads a metadata coded string + * TODO: Change + * + * @param $value + * @param bool $types + * + * @return array + */ public static function readMetadata($value, $types = false){ $offset = 0; $m = array(); @@ -297,6 +397,19 @@ class Utils{ return $raw; } + /** + * This function tries to get all the entropy available in PHP, and distills it to get a good RNG. + * + * + * @param int $length default 16, Number of bytes to generate + * @param bool $secure default true, Generate secure distilled bytes, slower + * @param bool $raw default true, returns a binary string if true, or an hexadecimal one + * @param string $startEntropy default null, adds more initial entropy + * @param int &$rounds Will be set to the number of rounds taken + * @param int &$drop Will be set to the amount of dropped bytes + * + * @return string + */ public static function getRandomBytes($length = 16, $secure = true, $raw = true, $startEntropy = "", &$rounds = 0, &$drop = 0){ static $lastRandom = ""; $output = b""; @@ -394,14 +507,7 @@ class Utils{ return $raw === false ? bin2hex($output) : $output; } - public static function round($number){ - return round($number, 0, PHP_ROUND_HALF_DOWN); - } - - public static function distance($pos1, $pos2){ - return sqrt(pow($pos1["x"] - $pos2["x"], 2) + pow($pos1["y"] - $pos2["y"], 2) + pow($pos1["z"] - $pos2["z"], 2)); - } - + /* public static function angle3D($pos1, $pos2){ $X = $pos1["x"] - $pos2["x"]; $Z = $pos1["z"] - $pos2["z"]; @@ -411,9 +517,17 @@ class Utils{ $vAngle = rad2deg(-atan2($Y, $dXZ)); return array("yaw" => $hAngle, "pitch" => $vAngle); - } + }*/ - public static function curl_get($page, $timeout = 10){ + /** + * GETs an URL using cURL + * + * @param $page + * @param int $timeout default 10 + * + * @return bool|mixed + */ + public static function getURL($page, $timeout = 10){ if(Utils::$online === false){ return false; } @@ -434,7 +548,15 @@ class Utils{ return $ret; } - public static function curl_post($page, $args, $timeout = 10){ + /** + * POSTs data to an URL + * @param $page + * @param array|string $args + * @param int $timeout + * + * @return bool|mixed + */ + public static function postURL($page, $args, $timeout = 10){ if(Utils::$online === false){ return false; } @@ -457,18 +579,24 @@ class Utils{ return $ret; } - public static function strToHex($str){ - return bin2hex($str); - } - - public static function hexToStr($hex){ - return hex2bin($hex); - } - + /** + * Reads a byte boolean + * + * @param $b + * + * @return bool + */ public static function readBool($b){ return Utils::readByte($b, false) === 0 ? false : true; } + /** + * Writes a byte boolean + * + * @param $b + * + * @return bool|string + */ public static function writeBool($b){ return Utils::writeByte($b === true ? 1 : 0); } diff --git a/src/utils/pthreads.php b/src/utils/pthreads.php index 242517e71..06adf7015 100644 --- a/src/utils/pthreads.php +++ b/src/utils/pthreads.php @@ -80,7 +80,7 @@ class AsyncMultipleQueue extends Thread{ $url = $this->get(\PocketMine\Utils\Utils::readShort($this->get(2), false)); $timeout = \PocketMine\Utils\Utils::readShort($this->get(2)); - $res = (string) \PocketMine\Utils\Utils::curl_get($url, $timeout); + $res = (string) \PocketMine\Utils\Utils::getURL($url, $timeout); $this->lock(); $this->output .= \PocketMine\Utils\Utils::writeInt($rID) . \PocketMine\Utils\Utils::writeShort(ASYNC_CURL_GET) . \PocketMine\Utils\Utils::writeInt(strlen($res)) . $res; $this->unlock(); @@ -94,7 +94,7 @@ class AsyncMultipleQueue extends Thread{ $key = $this->get(\PocketMine\Utils\Utils::readShort($this->get(2), false)); $d[$key] = $this->get(\PocketMine\Utils\Utils::readInt($this->get(4))); } - $res = (string) \PocketMine\Utils\Utils::curl_post($url, $d, $timeout); + $res = (string) \PocketMine\Utils\Utils::postURL($url, $d, $timeout); $this->lock(); $this->output .= \PocketMine\Utils\Utils::writeInt($rID) . \PocketMine\Utils\Utils::writeShort(ASYNC_CURL_POST) . \PocketMine\Utils\Utils::writeInt(strlen($res)) . $res; $this->unlock();