PageRenderTime 25ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/LiveSigns/src/aliuly/livesigns/Main.php

https://gitlab.com/Skull3x/pocketmine-plugins
PHP | 359 lines | 322 code | 17 blank | 20 comment | 57 complexity | 708c68285bcc261fa9730e1c0ee0ea9e MD5 | raw file
  1. <?php
  2. /**
  3. ** CONFIG:main
  4. **/
  5. namespace aliuly\livesigns;
  6. use pocketmine\plugin\PluginBase;
  7. use pocketmine\command\CommandExecutor;
  8. use pocketmine\command\CommandSender;
  9. use pocketmine\command\Command;
  10. use pocketmine\event\Listener;
  11. use pocketmine\utils\Config;
  12. use pocketmine\utils\TextFormat;
  13. use aliuly\livesigns\common\PluginCallbackTask;
  14. use aliuly\livesigns\common\BasicPlugin;
  15. use aliuly\livesigns\common\BasicHelp;
  16. use aliuly\livesigns\common\mc;
  17. class Main extends BasicPlugin implements CommandExecutor {
  18. protected $texts; // trigger texts
  19. protected $fetcher; // async task retriever
  20. protected $fetch_redo; // Re-do a fetch
  21. protected $signsCfg; // user sign configuration
  22. protected $signsTxt; // preprocessed sign text
  23. protected $cmds; // Contains command implementations
  24. protected $fetchcfg; // Fetcher Configuration
  25. protected $floats; // Floating text handler
  26. public $vars; // Used in variable substitutions
  27. public $debug; // Show debug messages
  28. public function onDisable() {
  29. if ($this->fetcher !== null && !$this->fetcher->isFinished()) {
  30. $id = $this->fetcher->getTaskId();
  31. $this->getServer()->getScheduler()->cancelTask($id);
  32. }
  33. parent::onDisable();
  34. }
  35. public function onEnable(){
  36. if (!is_dir($this->getDataFolder())) mkdir($this->getDataFolder());
  37. mc::plugin_init($this,$this->getFile());
  38. $this->saveResource("signs.yml");
  39. $this->saveResource("welcome.txt");
  40. $this->saveResource("floats.yml");
  41. $this->saveResource("tops.php");
  42. $defaults = [
  43. "version" => $this->getDescription()->getVersion(),
  44. "# settings" => "tunable parameters",
  45. "settings" => [
  46. "# tile-updates" => "How often to update signs in game from cache",// (in-ticks)
  47. "tile-updates" => 80,
  48. "# cache-signs" => "Default seconds to cache sign data",
  49. "cache-signs" => 7200,
  50. "# expire-cache" => "How often to expire caches (ticks)",
  51. "expire-cache" => 200,
  52. "# debug" => "shows additional debug data",
  53. "debug" => false,
  54. ],
  55. "fetcher" => [
  56. "# path" => "file path for the file fetcher",
  57. "# twitter" => "Used by the twitter feed fetcher",
  58. "twitter" => [
  59. 'oauth_access_token' => "YOUR_OAUTH_ACCESS_TOKEN",
  60. 'oauth_access_token_secret' => "YOUR_OAUTH_ACCESS_TOKEN_SECRET",
  61. 'consumer_key' => "YOUR_CONSUMER_KEY",
  62. 'consumer_secret' => "YOUR_CONSUMER_SECRET"
  63. ],
  64. ],
  65. "# signs" => "trigger text",
  66. "signs" => [
  67. "tag" => ["[LIVESIGN]","[livesign]"],
  68. ],
  69. ];
  70. $cf = (new Config($this->getDataFolder()."config.yml",
  71. Config::YAML, $defaults))->getAll();
  72. if (!isset($cf["fetcher"]["path"])) {
  73. $cf["fetcher"]["path"] = $this->getDataFolder();
  74. }
  75. $this->debug = $cf["settings"]["debug"];
  76. $this->texts = [];
  77. foreach ($cf["signs"] as $a=>&$b) {
  78. foreach ($b as $c) {
  79. $this->texts[$c] = $a;
  80. }
  81. }
  82. $this->signsCfg = [];
  83. $this->signsTxt = [];
  84. $this->loadSigns();
  85. $this->fetcher = null;
  86. $this->fetchcfg = $cf["fetcher"];
  87. $this->getServer()->getScheduler()->scheduleRepeatingTask(
  88. new PluginCallbackTask($this,[$this,"expireCache"],[$cf["settings"]["cache-signs"]]),$cf["settings"]["expire-cache"]
  89. );
  90. $this->getServer()->getScheduler()->scheduleRepeatingTask(new TileUpdTask($this),$cf["settings"]["tile-updates"]);
  91. $this->floats = new ParticleTxt($this,$cf["settings"]["tile-updates"]);
  92. $this->cmds = [
  93. new LsCmds($this),
  94. "fs"=>new FsCmds($this),
  95. new BasicHelp($this),
  96. ];
  97. // These are constants that should be pre calculated
  98. $this->vars = [
  99. "{LiveSigns}" => $this->getDescription()->getFullName(),
  100. "{MOTD}" => $this->getServer()->getMotd(),
  101. "{NL}" => "\n",
  102. "{BLACK}" => TextFormat::BLACK,
  103. "{DARK_BLUE}" => TextFormat::DARK_BLUE,
  104. "{DARK_GREEN}" => TextFormat::DARK_GREEN,
  105. "{DARK_AQUA}" => TextFormat::DARK_AQUA,
  106. "{DARK_RED}" => TextFormat::DARK_RED,
  107. "{DARK_PURPLE}" => TextFormat::DARK_PURPLE,
  108. "{GOLD}" => TextFormat::GOLD,
  109. "{GRAY}" => TextFormat::GRAY,
  110. "{DARK_GRAY}" => TextFormat::DARK_GRAY,
  111. "{BLUE}" => TextFormat::BLUE,
  112. "{GREEN}" => TextFormat::GREEN,
  113. "{AQUA}" => TextFormat::AQUA,
  114. "{RED}" => TextFormat::RED,
  115. "{LIGHT_PURPLE}" => TextFormat::LIGHT_PURPLE,
  116. "{YELLOW}" => TextFormat::YELLOW,
  117. "{WHITE}" => TextFormat::WHITE,
  118. "{OBFUSCATED}" => TextFormat::OBFUSCATED,
  119. "{BOLD}" => TextFormat::BOLD,
  120. "{STRIKETHROUGH}" => TextFormat::STRIKETHROUGH,
  121. "{UNDERLINE}" => TextFormat::UNDERLINE,
  122. "{ITALIC}" => TextFormat::ITALIC,
  123. "{RESET}" => TextFormat::RESET,
  124. ];
  125. }
  126. public function scheduleRetrieve() {
  127. if ($this->fetcher !== null && !$this->fetcher->isFinished()) {
  128. $this->fetch_redo = true;
  129. return;
  130. }
  131. $this->fetch_redo = false;
  132. $pkgs = [];
  133. foreach ($this->signsCfg as $id => $dat) {
  134. if (isset($this->signsTxt[$id])) {
  135. if (isset($this->signsTxt[$id]["datetime"])) continue; // No need to fetch this one... still current
  136. }
  137. $pkgs[] = [ $id, $dat ];
  138. }
  139. // Nothing to do...
  140. if (count($pkgs) == 0) return;
  141. $task = $this->fetcher = new FetchTask($this,$this->fetchcfg,$pkgs);
  142. $this->getServer()->getScheduler()->scheduleAsyncTask($task);
  143. }
  144. public function retrieveDone($pkgs) {
  145. $now = time();
  146. foreach ($pkgs as $id=>$txt) {
  147. $this->signsTxt[$id] = [ "text"=> $txt, "datetime" => $now ];
  148. }
  149. $this->fetcher = null;
  150. if ($this->fetch_redo) $this->scheduleRetrieve();
  151. }
  152. public function expireCache($dmaxage) {
  153. $now = time();
  154. foreach (array_keys($this->signsTxt) as $id) {
  155. if (!isset($this->signsCfg[$id])) {
  156. // Removed...
  157. unset($this->signsTxt[$id]);
  158. continue;
  159. }
  160. if (!isset($this->signsTxt[$id]["datetime"])) continue;
  161. //*** CHECK ***
  162. if (isset($this->signsCfg[$id]["max-age"])) {
  163. $maxage = $this->signsCfg[$id]["max-age"];
  164. } else {
  165. $fetcher = FetchTask::fetchClass($this->signsCfg[$id]["type"]);
  166. $maxage = $dmaxage;
  167. if ($fetcher !== null && $fetcher::default_age() != -1) {
  168. $maxage = $fetcher::default_age();
  169. }
  170. }
  171. if (($this->signsTxt[$id]["datetime"] + $maxage) < $now) unset($this->signsTxt[$id]["datetime"]);
  172. }
  173. $this->scheduleRetrieve();
  174. }
  175. public function updateVars() {
  176. $this->vars["{tps}"] = $this->getServer()->getTicksPerSecond();
  177. $this->vars["{players}"] = count($this->getServer()->getOnlinePlayers());
  178. $this->vars["{maxplayers}"] = $this->getServer()->getMaxPlayers();
  179. $this->vars["{network-name}"] = $this->getServer()->getNetwork()->getName();
  180. }
  181. private function getText($id) {
  182. if (!isset($this->signsCfg[$id])) {
  183. return [TextFormat::RED.mc::_("Missing id: %1%",$id)];
  184. }
  185. if (!isset($this->signsCfg[$id]["type"])) {
  186. return [TextFormat::RED.mc::_("Incomplete config for %1%",$id)];
  187. }
  188. switch (strtolower($this->signsCfg[$id]["type"])) {
  189. case "php":
  190. // It is PHP script!
  191. $plugin = $this;
  192. $server = $this->getServer();
  193. $logger = $this->getLogger();
  194. $t = implode("\n",$this->signsTxt[$id]["text"]);
  195. if (substr($t,0,2) == "?>") {
  196. ob_start();
  197. eval($t);
  198. return explode("\n",ob_get_clean());
  199. }
  200. return explode("\n",substr($t,2));
  201. case "query":
  202. case "motd":
  203. $vars = $this->vars;
  204. $msg = null;
  205. foreach ($this->signsTxt[$id]["text"] as $ln) {
  206. if ($msg == null) {
  207. $msg = $ln;
  208. continue;
  209. }
  210. list($i,$j) = explode("\t",$ln,2);
  211. $vars["{".$i."}"]= $j;
  212. }
  213. return explode("\n",strtr($msg,$vars));
  214. default:
  215. $text = $this->signsTxt[$id]["text"];
  216. }
  217. if(isset($this->signsCfg[$id]["no-vars"])) return $text;
  218. return explode("\n",strtr(implode("\n",$text),$this->vars));
  219. }
  220. public function getLiveText($id,$opts) {
  221. if (!isset($this->signsTxt[$id])) return null;
  222. if ($opts == null) {
  223. // Default is to do nothing,
  224. return $this->getText($id);
  225. }
  226. $opts = ",$opts,";
  227. $width = 75; $wrapper = "wwrap";
  228. if (preg_match('/,width=(\d+),/',$opts,$mv)) {
  229. $width = $mv[1];
  230. }
  231. foreach (['/,word,/i' => "wwrap",
  232. '/,char,/i' => "wrap"] as $re=>$mode) {
  233. if (preg_match($re,$opts)) $wrapper = $mode;
  234. }
  235. $stx = $this->getText($id);
  236. $stx = explode("\n",TextWrapper::$wrapper(implode("\n",$stx),$width));
  237. return $stx;
  238. }
  239. public function getLiveSign($sign) {
  240. if (!isset($this->texts[$sign[0]])) return null;
  241. $id = trim($sign[1]);
  242. if (!isset($this->signsTxt[$id])) return null;
  243. // We fold lines on words by default, unless
  244. // line4 has - raw or char
  245. switch (strtolower($sign[3])) {
  246. case "raw":
  247. case "none":
  248. $stx = $this->getText($id);
  249. break;
  250. case "char":
  251. case "chr":
  252. $stx = explode("\n",TextWrapper::wrap(implode("\n",$this->getText($id))));
  253. break;
  254. case "word":
  255. default:
  256. $stx = explode("\n",TextWrapper::wwrap(implode("\n",$this->getText($id))));
  257. break;
  258. }
  259. $text = [ "","","","" ];
  260. $i = 0; $s = 1; $j = 0;
  261. if (preg_match('/^\s*(\d+):(\d+)\s*$/',$sign[2],$mv)) {
  262. $i = $mv[1];
  263. $s = $mv[2];
  264. if ($s < 1) $s = 1;
  265. }
  266. while ($i < count($stx) && $j < 4) {
  267. $text[$j++] = $stx[$i];
  268. $i += $s;
  269. }
  270. return $text;
  271. }
  272. public function loadSigns() {
  273. $path = $this->getDataFolder()."signs.yml";
  274. if (!file_exists($path)) {
  275. // No sign data found!
  276. $this->signsCfg = [];
  277. return;
  278. }
  279. $cf = (new Config($path,Config::YAML))->getAll();
  280. $this->signsCfg = $cf;
  281. }
  282. public function saveSigns() {
  283. $path = $this->getDataFolder()."signs.yml";
  284. $yml = new Config($path,Config::YAML,[]);
  285. $yml->setAll($this->signsCfg);
  286. $yml->save();
  287. }
  288. //////////////////////////////////////////////////////////////////////
  289. //
  290. // Command implementations
  291. //
  292. //////////////////////////////////////////////////////////////////////
  293. public function onCommand(CommandSender $sender, Command $cmd, $label, array $args) {
  294. if ($cmd->getName() == "floatsigns") {
  295. return $this->cmds["fs"]->onSCmd($sender,$args);
  296. }
  297. if ($cmd->getName() != "livesigns") return false;
  298. if (count($args) == 0) return false;
  299. return $this->dispatchSCmd($sender,$cmd,$args);
  300. }
  301. public function getStats() {
  302. $txt = [];
  303. if ($this->fetcher === null) {
  304. $txt[] = mc::_("Fetcher not running");
  305. } else {
  306. $txt[] = mc::_("Fetcher available: %1%",$this->fetcher->getTaskId());
  307. if ($this->fetcher->isFinished()) {
  308. $txt[] = mc::_("- Fetcher Finished");
  309. }
  310. }
  311. return $txt;
  312. }
  313. /**
  314. * @api
  315. */
  316. public function getFloats() { return $this->floats; }
  317. public function updateSignCfg($id,$type,$content) {
  318. if ($type == null) {
  319. if (!isset($this->signsCfg[$id])) return;
  320. unset($this->signsCfg[$id]);
  321. } else {
  322. $this->signsCfg[$id] = [ "type" => $type, "content" => $content ];
  323. }
  324. }
  325. public function getSignCfg() {
  326. return $this->signsCfg;
  327. }
  328. public function getSignTxt() {
  329. return $this->signsTxt;
  330. }
  331. public function expireSign($id) {
  332. if ($id !== null) {
  333. if (!isset($this->signsTxt[$id])) return;
  334. if (!isset($this->signsTxt[$id]["datetime"])) return;
  335. unset($this->signsTxt[$id]["datetime"]);
  336. return;
  337. }
  338. foreach (array_keys($this->signsTxt) as $id) {
  339. $this->expireSign($id);
  340. }
  341. }
  342. }