diff --git a/README.md b/README.md index 5644ae9..32a9c25 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,39 @@ # KillRate -* Summary: Keep track of how much killing is going-on -* Dependency Plugins: N/A -* PocketMine-MP version: 1.4 - API 1.10.0 +* Summary: Keep track of the number of kills +* PocketMine-MP version: 1.4 (API:1.10.0) * DependencyPlugins: - * OptionalPlugins: PocketMoney,MassiveEconomy,EconomyAPI,GoldStd * Categories: Informational * Plugin Access: Commands, Databases, Entities, Tile Entities -* WebSite: [github](https://github.com/alejandroliu/pocketmine-plugins/tree/master/KillRate) +* WebSite: https://github.com/alejandroliu/pocketmine-plugins/tree/master/KillRate ## Overview -Keep track on how much killing is going-on on a server. + + + +**DO NOT POST QUESTION/BUG-REPORTS/REQUESTS IN THE REVIEWS** + +It is difficult to carry a conversation in the reviews. If you +have a question/bug-report/request please use the +[Thread](http://forums.pocketmine.net/threads/killrate.8060/) for +that. You are more likely to get a response and help that way. + +_NOTE:_ + +This documentation was last updated for version **1.2.3**. + +Please go to +[github](https://github.com/alejandroliu/pocketmine-plugins/tree/master/KillRate) +for the most up-to-date documentation. + +You can also download this plugin from this [page](https://github.com/alejandroliu/pocketmine-plugins/releases/tag/KillRate-1.2.3). + + + +This plugin keeps track on how much killing is going-on on a server. It may optionally use an economy plugin like for example, PocketMoney, to reward killing. @@ -24,7 +45,20 @@ Basic Usage: * killrate stats [player] - Show the KillRate stats for [player] * killrate top [online] - Show top players. -You can also place signs with the following text in the first line: +You can also place signs to show game statistics. + +Thanks to @Daniel123 and @CaptainKenji17 for suggestions and feedback. + +## Documentation + +This plugin supports PocketMoney and GoldStd and has experimental +support for MassiveEconomy and EconomyAPI. + +### Signs + +You can place signs showing current game statistics. The following +sign types are available by default, by entering the keyword +([KEYWORD]) in **LINE1** of the sign: * [STATS] - Current player statistics * [RANKINGS] - Top 3 players + scores @@ -34,17 +68,33 @@ You can also place signs with the following text in the first line: * [TOPNAMES] - Top 3 on-line player names * [TOPPOINTS] - Top 3 on-line player scores -These signs will then display current statistics. These signs can be -further customized by adding the following: +Signs showing top players can be further customized by adding +additional entries in the sign text: -* LINE2 - Title, first line of the sign. -* LINE3 - What statistic to count (i.e. deaths, points, player), etc. -* LINE4 - format line, selects a format from the config.yml formats section. +* LINE2 - Title, this will be the first line of the sign. If, + however, you set it to **"^^^"** (Three consecutive **^** signs), + the title will be omitted (and the sign will show a top 4). +* LINE3 - What statistic to count. It defaults to _points_, but it + can be changed to anything (for example, _deaths_, _player_, etc). + Essentially the value here is the word on the left when you enter + the command _killrate stats_. +* LINE4 - format line, select a format out of the **config.yml** + file's **formats** section. -## Documentation +In the **formats** section you have: -This plugin supports PocketMoney and GoldStd and has experimental -support for MassiveEconomy and EconomyAPI. +``` + selector: format +``` + +The **selector** is a word that matches the text in **LINE4** of the +sign. The format can contain any text and the following variable +substitutions: + +* {player} - player's name +* {n} - rank number +* {count} - score +* {sname} - only the first 8 characters of the player's name ### Permission Nodes @@ -58,78 +108,27 @@ support for MassiveEconomy and EconomyAPI. * killrate.signs.use : Allow to use KillRate signs -## Configuration - -These can be configured from `config.yml`: - -```YAML -settings: - points: true - rewards: true - creative: false - dynamic-updates: 80 - kill-streak: false or value - reset-on-death: false or value - pop-up: false -values: - zombie: [10,100] - Player: [100, 100] - '*': [0, -10] -backend: SQLiteMgr -MySQL: - host: localhost - user: nobody - password: secret - database: KillRateDb - port: 3306 -signs: - '[STATS]': stats - '[RANKINGS]': rankings - '[ONLINE TOPS]': online-ranks - '[RANKNAMES]': rankings-names - '[RANKPOINTS]': rankings-points - '[TOPNAMES]': online-top-names - '[TOPPOINTS]': online-top-points -formats: - default: '{sname} {count}' - names: '{n}.{player}' - scores: '{count}' -``` - -If `creative` is set to true, kills done when the player is in -`creative` will be counted. The default is false, *NOT* to count -them. - -If `points` is true, points are awarded and tracked. You need to -enable `points` for the rankings to work. - -If `rewards` is true, money is awarded. You need an economy plugin -for this to work. - -`dynamic-updates` show in tick intervals how often signs are updated. +### Configuration -`pop-up` will use the _pop up_ message to show the player's score. +Configuration is through the `config.yml` file. +The following sections are defined: -`kill-streak`: Set to `false` or to a number. Will show the kill -streak of a player. +#### config.yml -`reset-on-death`: Set to `false` or to a number. When the player dies -that number of times, scores will reset. (It is GAME OVER). +* settings: Configuration settings + * points: award points. if true points are awarded and tracked. + * rewards: award money. if true, money is awarded. Requires an economy plugin + * creative: track creative kills. if true, kills done by players in creative are scored + * dynamic-updates: Update signs. Set to 0 or false to disable, otherwise sign update frequence in ticks + * reset-on-death: Reset counters on death. set to **false** or to a number. When the player dies that number of times, scores will reset. (GAME OVER MAN!) + * kill-streak: Enable kill-streak tracking. "set to **false** or to a number. Will show the kill streak of a player once the number of kills before dying reaches number + * achievements: Enable PocketMine achievements +* values: configure awards. (1st.money, 2nd.points) Configures how many points or how much money is awarded per kill type. The first number is points, the second is money. You can use negative values. +* formats: Sign formats. Used to show sign data +* backend: Use SQLiteMgr or MySqlMgr +* MySql: MySQL settings. Only used if backend is MySqlMgr to configure MySql settings +* signs: placed signs text. These are used to configure sign texts. Place signs with the words on the left, and the sign type (on the right) will be created -`values` are used to configure how many points or how much money is -awarded per kill type. The first number is points, the second is -money. You can use negative values. - -`signs` are used to configure sign texts. These texts will be used to -identify which signs should show player stats. - -`formats` are used to show what data are shown in the different -signs. The following variables are available in these formats: - -* {player} - player's name -* {n} - rank number -* {count} - score -* {sname} - only the first 8 characters of a name ## Translations @@ -141,18 +140,65 @@ languages currently available are: You can provide your own message file by creating a file called `messages.ini` in the plugin config directory. Check -[github](https://github.com/alejandroliu/pocketmine-plugins/tree/master/KillRate/resources/messages/) +[github](https://github.com/alejandroliu/pocketmine-plugins/tree/master/KillRate) for sample files. The contents of these "ini" files are key-value pairs: "Base text"="Translated Text" +## API + +The following functions are available to get information from this +plugin: + +* getRankings($limit=10,$online=false,$stat = "points") + * $limit - the number of rows to return + * $online - false, all players, true, only on-line players are + returned + * $stat - the statistic you want to display +* updateDb($player,$stat,$incr = 1) + * $player - the player you want to score + * $stat - type of statistic to update + * $incr - how many units to increase +* getScore($player,$stat = "points") + * $player - player to look-up + * $stat - statistic to return + +To use the api: + +```php +[PHP] +$server->getPluginManager()->getPlugin("KillRate")->function() +[/PHP] +``` + +## FAQ + +* Q: Can you score when you push people to lava (or other indirect kills)? +* A: Only direct kills are scored. All indirect kills (pushing people + to lava, causing explosions, etc) can not be scored. + # Changes +* 1.2.3: + * MySqlMgr: Fixed typo + * Fixed bug with setting rewards/points to false (Reported by @reidq7) +* 1.2.2 + * small tweaks on the comments of the config file... + * Added achievements +* 1.2.1: + * CptKenji's features: + * Double money and Best streak tracking. + * Fixed MySql support. It should work now. +* 1.2.0: Bumped the version number to reflect config changes. + * Added the "^^^" hack. + * Removed pop-up scores. + * Improved documentation * 1.1.1: * Minor tweaks * Signs are more configurable + * **PLEASE DELETE OLD CONFIG.YML FILE** * 1.1.0: General improvements * Added experimental MySQL support * Messages file and translations: spanish diff --git a/plugin.yml b/plugin.yml index 1cc5fc4..347ad14 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,5 +1,5 @@ name: KillRate -version: 1.1.1 +version: 1.2.3 main: aliuly\killrate\Main api: 1.10.0 load: POSTWORLD @@ -8,6 +8,7 @@ softdepend: [PocketMoney,MassiveEconomy,EconomyAPI,GoldStd] description: Keep track of the number of kills author: aliuly +website: https://github.com/alejandroliu/pocketmine-plugins/tree/master/KillRate commands: killrate: diff --git a/resources/messages/messages.ini b/resources/messages/messages.ini index 0c19c72..3e1b74d 100644 --- a/resources/messages/messages.ini +++ b/resources/messages/messages.ini @@ -1,6 +1,8 @@ ; messages.ini "# MISSING MONEY API PLUGIN"="" "%1%-mode"="" +"%1% beat previous streak record of %2% at %3% kills"="" +"%1% ended his kill-streak at %2% kills"="" "%1% has a %2% kill streak"="" "%1% points awarded!"="" "%1% points deducted!"="" @@ -11,8 +13,9 @@ ". Player Points"="" ". Please install one of the following:"="" "Adventure"="" +"Configuration has been changed"="" "Creative"="" -"Feature DISABLED"="" +"It is recommended to delete old config.yml"="" "KillRate sub-commands"="" "Kills: "="" "Money: "="" @@ -24,8 +27,6 @@ "Placed [KillRate] sign"="" "Please report bugs"="" "Points: "="" -"Pop-ups only available on PMv1.5+"="" -"Score: %1%"="" "Show player scores"="" "Show top players"="" "Spectator"="" @@ -41,7 +42,6 @@ "Usage: /killrate %1% %2%"="" "Using %1% as backend"="" "Using %1% backend is untested"="" -"Using deprecated pop-up feature"="" "Using money API from %1%"="" "You are fined $%1%"="" "You are fined $1"="" @@ -49,11 +49,16 @@ "You do not have permission to do that."="" "You earn $%1%"="" "You earn $1"="" +"You earn an additional $%1% for being in kill-streak!"="" "You were killed by %1%!"="" "one point awarded!"="" "one point deducted!"="" "#%1% was killed by %2%!"="" +"#Feature DISABLED"="" +"#Pop-ups only available on PMv1.5+"="" +"#Score: %1%"="" "#Top On-Line"="" +"#Using deprecated pop-up feature"="" "#You can only use this command in-game"="" "#You have a %1% kill streak."="" "#{count}"="" diff --git a/resources/messages/spa.ini b/resources/messages/spa.ini index 0ced6e6..1745150 100644 --- a/resources/messages/spa.ini +++ b/resources/messages/spa.ini @@ -1,6 +1,8 @@ ; spa.ini "# MISSING MONEY API PLUGIN"="# FALTA PLUGIN DE ECONOMIA" "%1%-mode"="modo-%1%" +"%1% beat previous streak record of %2% at %3% kills"="%1% rompió su record de rachas anterior de %2% con %3% victorias." +"%1% ended his kill-streak at %2% kills"="%1% terminó su racha de victorias con %2%" "%1% has a %2% kill streak"="%1% tiene una racha de %2% victorias" "%1% points awarded!"="%1% puntos ganados!" "%1% points deducted!"="%1% puntos perdidos!" @@ -11,8 +13,9 @@ ". Player Points"=". Jugador Puntos" ". Please install one of the following:"=". Por favor instale uno de estos:" "Adventure"="Aventura" +"Configuration has been changed"="Configuración ha cambiado" "Creative"="Creativo" -"Feature DISABLED"="Módulo DESACTIVADO" +"It is recommended to delete old config.yml"="Se recomienda borrar su config.yml anterior" "KillRate sub-commands"="Sub-comandos de KillRate" "Kills: "="Muertos: " "Money: "="Dinero: " @@ -22,10 +25,8 @@ "On-line Names"="Nombres en-línea" "On-line Scores"="Puntajes en-línea" "Placed [KillRate] sign"="Construyo un cartel de [KillRate]" -"Please report bugs"="Por favor reporte ERRORER" +"Please report bugs"="Por favor reporte ERRORES" "Points: "="Puntos: " -"Pop-ups only available on PMv1.5+"="Pop-up solo disponible en PMv1.5+" -"Score: %1%"="Puntaje: %1%" "Show player scores"="Mostrar puntajes de jugador" "Show top players"="Mostrar los mejores jugadores" "Spectator"="Espectador" @@ -41,7 +42,6 @@ "Usage: /killrate %1% %2%"="Uso: /killrate %1% %2%" "Using %1% as backend"="Usando %1% para almacenamiento" "Using %1% backend is untested"="Uso de %1% es experimental" -"Using deprecated pop-up feature"="Usando módulo de pop-up obsoleto" "Using money API from %1%"="Usando API de Economía: %1%" "You are fined $%1%"="Eres multado %1% EUR" "You are fined $1"="Eres multado un EUR" @@ -49,10 +49,15 @@ "You do not have permission to do that."="No tienes permiso de hacer eso" "You earn $%1%"="Haz ganado %1% EUR" "You earn $1"="Haz ganado Un EUR" +"You earn an additional $%1% for being in kill-streak!"="Ganaste unos %1%EUR addicionales por tener un racha!" "You were killed by %1%!"="Fue eliminado por %1%!" "one point awarded!"="Un punto ganado!" "one point deducted!"="Un punto perdido!" "#%1% was killed by %2%!"="%1% fue eliminado por %2%!" +"#Feature DISABLED"="Módulo DESACTIVADO" +"#Pop-ups only available on PMv1.5+"="Pop-up solo disponible en PMv1.5+" +"#Score: %1%"="Puntaje: %1%" "#Top On-Line"="Mejores En-Línea" +"#Using deprecated pop-up feature"="Usando módulo de pop-up obsoleto" "#You can only use this command in-game"="Solo puedes usar esto dendro del juego" "#You have a %1% kill streak."="Tienes una racha de %1% victorias" diff --git a/src/aliuly/killrate/Main.php b/src/aliuly/killrate/Main.php index 59499dc..9aa9395 100644 --- a/src/aliuly/killrate/Main.php +++ b/src/aliuly/killrate/Main.php @@ -1,4 +1,7 @@ dbm = null; if (!is_dir($this->getDataFolder())) mkdir($this->getDataFolder()); mc::plugin_init($this,$this->getFile()); $this->getServer()->getPluginManager()->registerEvents($this, $this); $defaults = [ "version" => $this->getDescription()->getVersion(), + "# settings" => "Configuration settings", "settings" => [ + "# points" => "award points.", // if true points are awarded and tracked. "points" => true, + "# rewards" => "award money.", // if true, money is awarded. Requires an economy plugin "rewards" => true, + "# creative" => "track creative kills.", // if true, kills done by players in creative are scored "creative" => false, + "# dynamic-updates" => "Update signs.", // Set to 0 or false to disable, otherwise sign update frequence in ticks "dynamic-updates" => 80, + "# reset-on-death" => "Reset counters on death.", // set to **false** or to a number. When the player dies that number of times, scores will reset. (GAME OVER MAN!) "reset-on-death" => false, + "# kill-streak" => "Enable kill-streak tracking.", // "set to **false** or to a number. Will show the kill streak of a player once the number of kills before dying reaches number "kill-streak" => false, - "pop-up" => false, + "# achievements" => "Enable PocketMine achievements", + "achievements" => true, ], + "# values" => "configure awards. (1st.money, 2nd.points)", // Configures how many points or how much money is awarded per kill type. The first number is points, the second is money. You can use negative values. "values" => [ "*" => [ 1, 10 ], // Default "Player" => [ 100, 100 ], ], + "# formats" => "Sign formats.", // Used to show sign data "formats" => [ "default" => "{sname} {count}", "names" => "{n}.{player}", "scores" => "{count}", ], + "# backend" => "Use SQLiteMgr or MySqlMgr", "backend" => "SQLiteMgr", + "# MySql" => "MySQL settings.", // Only used if backend is MySqlMgr to configure MySql settings "MySql" => [ - "comment" => "Only used if backend = MySqlMgr", "host" => "localhost", "user" => "nobody", "password" => "secret", "database" => "KillRateDb", "port" => 3306, ], + "# signs" => "placed signs text.", // These are used to configure sign texts. Place signs with the words on the left, and the sign type (on the right) will be created "signs" => [ "[STATS]" => "stats", "[ONLINE TOPS]" => "online-tops", @@ -89,6 +107,11 @@ public function onEnable(){ ]; $this->cfg = (new Config($this->getDataFolder()."config.yml", Config::YAML,$defaults))->getAll(); + if (version_compare($this->cfg["version"],"1.2.0") < 0) { + $this->getLogger()->warning(TextFormat::RED.mc::_("Configuration has been changed")); + $this->getLogger()->warning(mc::_("It is recommended to delete old config.yml")); + } + $backend = __NAMESPACE__."\\".$this->cfg["backend"]; $this->dbm = new $backend($this); if ($this->cfg["backend"] != "SQLiteMgr") { @@ -98,27 +121,13 @@ public function onEnable(){ $this->getLogger()->info(mc::_("Using %1% as backend", $this->cfg["backend"])); } - $pm = $this->getServer()->getPluginManager(); - if(!($this->money = $pm->getPlugin("PocketMoney")) - && !($this->money = $pm->getPlugin("GoldStd")) - && !($this->money = $pm->getPlugin("EconomyAPI")) - && !($this->money = $pm->getPlugin("MassiveEconomy"))){ - $this->getLogger()->error(TextFormat::RED. - mc::_("# MISSING MONEY API PLUGIN")); - $this->getLogger()->error(TextFormat::BLUE. - mc::_(". Please install one of the following:")); - $this->getLogger()->error(TextFormat::WHITE. - mc::_("* GoldStd")); - $this->getLogger()->error(TextFormat::WHITE. - mc::_("* PocketMoney")); - $this->getLogger()->error(TextFormat::WHITE. - mc::_("* EconomyAPI or")); - $this->getLogger()->error(TextFormat::WHITE. - mc::_("* MassiveEconomy")); - } else { - $this->getLogger()->info(TextFormat::BLUE. - mc::_("Using money API from %1%", - TextFormat::WHITE.$this->money->getName()." v".$this->money->getDescription()->getVersion())); + if (isset($this->cfg["settings"]["rewards"])) { + $this->money = MoneyAPI::moneyPlugin($this); + if ($this->money) { + MoneyAPI::foundMoney($this,$this->money); + } else { + MoneyAPI::noMoney($this); + } } if ($this->cfg["settings"]["dynamic-updates"] && $this->cfg["settings"]["dynamic-updates"] > 0) { @@ -135,19 +144,13 @@ public function onEnable(){ } $this->stats = []; - if ($this->cfg["settings"]["pop-up"]) { - $this->getLogger()->warning(TextFormat::YELLOW.mc::_("Using deprecated pop-up feature")); - if ($this->api >= 12) { - $this->getServer()->getScheduler()->scheduleRepeatingTask(new ShowMessageTask($this), 15); - } else { - $this->getLogger()->warning(TextFormat::RED. - mc::_("Pop-ups only available on PMv1.5+")); - $this->getLogger()->warning(TextFormat::RED.mc::_("Feature DISABLED")); - } + if ($this->cfg["settings"]["achievements"]) { + Achievement::add("killer","First Blood!",[]); + Achievement::add("serialKiller","Killer Streak!",["killer"]); } } public function onDisable() { - $this->dbm->close(); + if ($this->dbm !== null) $this->dbm->close(); $this->dbm = null; } @@ -208,21 +211,6 @@ private function cmdHelp(CommandSender $sender,$args) { } return true; } - public function getRankings($limit=10,$online=false,$col = "points") { - if ($online) { - // Online players only... - $plist = []; - foreach ($this->getServer()->getOnlinePlayers() as $p) { - $plist[] = $p->getName(); - } - if (count($plist) < 2) return null; - } else { - $plist = null; - } - //print_r([$limit,$plist]); - return $this->dbm->getTops($limit,$plist,$col); - } - private function cmdTops(CommandSender $c,$args) { if (count($args) == 0) { $res = $this->getRankings(5); @@ -264,47 +252,6 @@ private function cmdStats(CommandSender $c,$args) { return true; } - ////////////////////////////////////////////////////////////////////// - // - // Economy/Money handlers - // - ////////////////////////////////////////////////////////////////////// - public function grantMoney($p,$money) { - if(!$this->money) return false; - switch($this->money->getName()){ - case "GoldStd": - $this->money->grantMoney($p, $money); - break; - case "PocketMoney": - $this->money->grantMoney($p, $money); - break; - case "EconomyAPI": - $this->money->setMoney($p,$this->money->mymoney($p)+$money); - break; - case "MassiveEconomy": - $this->money->payPlayer($p,$money); - break; - default: - return false; - } - return true; - } - public function getMoney($player) { - if(!$this->money) return false; - switch($this->money->getName()){ - case "GoldStd": - return $this->money->getMoney($player); - break; - case "PocketMoney": - case "MassiveEconomy": - return $this->money->getMoney($player); - case "EconomyAPI": - return $this->money->mymoney($player); - default: - return false; - break; - } - } ////////////////////////////////////////////////////////////////////// // // Event handlers @@ -335,16 +282,6 @@ public function announce($pp,$points,$money) { } } - public function updateDb($perp,$vic,$incr = 1) { - $score = $this->dbm->getScore($perp,$vic); - if ($score) { - $this->dbm->updateScore($perp,$vic,$score["count"]+$incr); - return $score["count"]+$incr; - } - $this->dbm->insertScore($perp,$vic,$incr); - return $incr; - - } public function getPrizes($vic) { if (isset($this->cfg["values"][$vic])) { return $this->cfg["values"][$vic]; @@ -357,16 +294,16 @@ public function getPrizes($vic) { public function updateScores($perp,$vic) { $this->updateDb($perp,$vic); $awards = [ false,false]; - if (isset($this->cfg["settings"]["points"])) { + if ($this->cfg["settings"]["points"]) { // Add points... list($points,$money) = $this->getPrizes($vic); $this->updateDb($perp,"points",$points); $awards[0] = $points; } - if (isset($this->cfg["settings"]["rewards"])) { + if ($this->cfg["settings"]["rewards"]) { // Add money... list($points,$money) = $this->getPrizes($vic); - $this->grantMoney($perp,$money); + MoneyAPI::grantMoney($this->money,$perp,$money); $awards[1] = $money; } return $awards; @@ -395,6 +332,23 @@ public function deadDealer($pv) { } } if ($this->cfg["settings"]["kill-streak"]) { + $n = $pv->getName(); + $newstreak = $this->dbm->getScore($n,"streak"); + // Keep track of the best streak ever... + if ($newstreak) { + $newstreak = $newstreak["count"]; + $oldstreak = $this->dbm->getScore($n,"best-streak"); + if ($oldstreak) { + $oldstreak = $oldstreak["count"]; + if ($newstreak > $oldstreak) { + $this->dbm->updateScore($n,"best-streak",$newstreak); + $this->getServer()->broadcastMessage(mc::_("%1% beat previous streak record of %2% at %3% kills", $n, $oldstreak, $newstreak)); + } + } else { + $this->dbm->insertScore($n,"best-streak",$newstreak); + $this->getServer()->broadcastMessage(mc::_("%1% ended his kill-streak at %2% kills", $n, $newstreak)); + } + } $this->dbm->delScore($pv->getName(),"streak"); } } @@ -421,6 +375,7 @@ public function deadDealer($pv) { if (!($pp instanceof Player)) return; // Not killed by player... // No scoring for creative players... if ($pp->isCreative() && !isset($this->cfg["settings"]["creative"])) return; + if ($this->cfg["settings"]["achievements"]) $pp->awardAchievement("killer"); $perp = $pp->getName(); $vic = $pv->getName(); if ($pv instanceof Player) { @@ -431,7 +386,14 @@ public function deadDealer($pv) { if ($this->cfg["settings"]["kill-streak"]) { $streak = $this->updateDb($perp,"streak"); if ($streak > $this->cfg["settings"]["kill-streak"]) { + if ($this->cfg["settings"]["achievements"]) $pp->awardAchievement("serialKiller"); $this->getServer()->broadcastMessage(TextFormat::YELLOW.mc::_("%1% has a %2% kill streak",$pp->getName(),$streak)); + if ($this->cfg["settings"]["rewards"]) { + list($points,$money) = $this->getPrizes($vic); + $pp->sendMessage(TextFormat::GREEN. + mc::_("You earn an additional $%1% for being in kill-streak!",$money)); + MoneyAPI::grantMoney($this->money,$perp,$money); + } } } } @@ -535,7 +497,8 @@ public function activateSign($pl,$tile) { } $text[$l++] = $j.$score; } - $text[$l++] = mc::_("Money: ").$this->getMoney($name); + $text[$l++] = mc::_("Money: "). + MoneyAPI::getMoney($this->money,$name); break; case "online-tops": $text = $this->topSign(true,"default",mc::_("Top Online"),$sign); @@ -561,11 +524,6 @@ public function activateSign($pl,$tile) { } $this->updateSign($pl,$tile,$text); } - public function getScore($pl,$type = "points") { - $score = $this->dbm->getScore($pl->getName(),$type); - if ($score) return $score["count"]; - return 0; - } protected function topSign($mode,$fmt,$title,$sign) { $col = "points"; @@ -576,25 +534,63 @@ protected function topSign($mode,$fmt,$title,$sign) { } else { $fmt = $this->cfg["formats"][$fmt]; } - $text = ["","","",""]; - $text[0] = $title; - $res = $this->getRankings(3,$mode,$col); + if ($title == "^^^") { + $cnt = 4; + $start = 0; + } else { + $text[0] = $title; + $cnt = 3; + $start = 1; + } + $res = $this->getRankings($cnt,$mode,$col); if ($res == null) { $text[2] = mc::_("NO STATS FOUND!"); } else { - $i = 1; + $i = 1; $j = $start; foreach ($res as $r) { $tr = [ "{player}" => $r["player"], "{count}" => $r["count"], "{sname}" => substr($r["player"],0,8), - "{n}" => $i, + "{n}" => $i++, ]; - $text[$i] = strtr($fmt,$tr); - ++$i; + $text[$j++] = strtr($fmt,$tr); } } return $text; } + ////////////////////////////////////////////////////////////////////// + // API functions + ////////////////////////////////////////////////////////////////////// + public function getRankings($limit=10,$online=false,$col = "points") { + if ($online) { + // Online players only... + $plist = []; + foreach ($this->getServer()->getOnlinePlayers() as $p) { + $plist[] = $p->getName(); + } + if (count($plist) < 2) return null; + } else { + $plist = null; + } + //print_r([$limit,$plist]); + return $this->dbm->getTops($limit,$plist,$col); + } + public function updateDb($perp,$vic,$incr = 1) { + $score = $this->dbm->getScore($perp,$vic); + if ($score) { + $this->dbm->updateScore($perp,$vic,$score["count"]+$incr); + return $score["count"]+$incr; + } + $this->dbm->insertScore($perp,$vic,$incr); + return $incr; + + } + public function getScore($pl,$type = "points") { + $score = $this->dbm->getScore($pl->getName(),$type); + if ($score) return $score["count"]; + return 0; + } + } diff --git a/src/aliuly/killrate/MySqlMgr.php b/src/aliuly/killrate/MySqlMgr.php index be10d8e..046de71 100644 --- a/src/aliuly/killrate/MySqlMgr.php +++ b/src/aliuly/killrate/MySqlMgr.php @@ -6,12 +6,12 @@ class MySqlMgr implements DatabaseManager { private $database; - static function prepare($player) { - return "'".\mysqli::real_escape_string(strtolower($player))."'"; + protected function prepare($player) { + return "'".$this->database->real_escape_string(strtolower($player))."'"; } public function close() { $this->database->close(); - unset($this->databse); + unset($this->database); } public function __construct(PluginBase $owner){ $cf = $owner->getCfg("MySql"); @@ -34,12 +34,12 @@ public function __construct(PluginBase $owner){ public function getTops($limit,$players,$scores) { $sql = "SELECT * FROM Scores"; - $sql .= " WHERE type = ".self::prepare($scores); + $sql .= " WHERE type = ".$this->prepare($scores); if ($players != null) { $sql .= " AND player IN ("; $q = ""; foreach ($players as $p) { - $sql .= $q.self::prepare($p); + $sql .= $q.$this->prepare($p); $q = ","; } $sql .=")"; @@ -58,7 +58,7 @@ public function getTops($limit,$players,$scores) { } public function getScores($player) { - $sql = "SELECT * FROM Scores WHERE player = ".self::prepare($player); + $sql = "SELECT * FROM Scores WHERE player = ".$this->prepare($player); $res = $this->database->query($sql); if ($res === false) return null; $tab = []; @@ -69,8 +69,8 @@ public function getScores($player) { return $tab; } public function getScore($player,$type) { - $sql = "SELECT * FROM Scores WHERE player = ".self::prepare($player). - " AND type = ".self::prepare($type); + $sql = "SELECT * FROM Scores WHERE player = ".$this->prepare($player). + " AND type = ".$this->prepare($type); $res = $this->database->query($sql); $ret = $res->fetch_assoc(); $res->free(); @@ -78,22 +78,22 @@ public function getScore($player,$type) { } public function insertScore($player,$type,$cnt) { $sql = "INSERT INTO Scores (player,type,count) VALUES (". - self::prepare($player).", ".self::prepare($type).", ".intval($cnt). + $this->prepare($player).", ".$this->prepare($type).", ".intval($cnt). ")"; return $this->database->query($sql); } public function updateScore($player,$type,$cnt) { $sql ="UPDATE Scores SET count=".intval($cnt). - " WHERE (player = ".self::prepare($player)." AND type = ". - self::prepare($type).")"; + " WHERE (player = ".$this->prepare($player)." AND type = ". + $this->prepare($type).")"; return $this->database->query($sql); } public function delScore($player,$type = null) { - $sql ="DELETE FROM Scores WHERE player=".self::prepare($player); + $sql ="DELETE FROM Scores WHERE player=".$this->prepare($player); if ($type !== null) { - $sql .= " AND type = ".self::prepare($type); + $sql .= " AND type = ".$this->prepare($type); } return $this->database->query($sql); } diff --git a/src/aliuly/killrate/ShowMessageTask.php b/src/aliuly/killrate/ShowMessageTask.php deleted file mode 100644 index 1703da4..0000000 --- a/src/aliuly/killrate/ShowMessageTask.php +++ /dev/null @@ -1,29 +0,0 @@ -owner; - } - - public function onRun($currentTick){ - $plugin = $this->getPlugin(); - if ($plugin->isDisabled()) return; - - foreach ($plugin->getServer()->getOnlinePlayers() as $pl) { - $pl->sendPopup(TextFormat::ITALIC . TextFormat::GRAY . - mc::_("Score: %1%", $plugin->getScore($pl))); - } - } - -} diff --git a/src/aliuly/killrate/common/MPMU.php b/src/aliuly/killrate/common/MPMU.php index b12ab2e..965e579 100644 --- a/src/aliuly/killrate/common/MPMU.php +++ b/src/aliuly/killrate/common/MPMU.php @@ -5,20 +5,53 @@ use pocketmine\utils\MainLogger; use pocketmine\command\CommandSender; use pocketmine\Player; +use pocketmine\command\PluginCommand; +use aliuly\killrate\common\mc; + +/** + * My PocketMine Utils class + */ abstract class MPMU { - // My PocketMine Utils + /** @var str[] $items Nice names for items */ static protected $items = []; - const VERSION = "0.0.1"; + /** @const str VERSION plugin version string */ + const VERSION = "1.1.0"; + /** + * libcommon library version. If a version is provided it will check + * the version using apiCheck. + * + * @param str version Version to check + * + * @return str|bool + */ static public function version($version = "") { if ($version == "") return self::VERSION; return self::apiCheck(self::VERSION,$version); } + /** + * Used to check the PocketMine API version + * + * @param str version Version to check + * + * @return str|bool + */ static public function apiVersion($version = "") { if ($version == "") return \pocketmine\API_VERSION; return self::apiCheck(\pocketmine\API_VERSION,$version); } + /** + * Checks API compatibility from $api against $version. $version is a + * string containing the version. It can contain the following operators: + * + * >=, <=, <> or !=, =, !|~, <, > + * + * @param str api Installed API version + * @param str version API version to compare against + * + * @return bool + */ static public function apiCheck($api,$version) { switch (substr($version,0,2)) { case ">=": @@ -43,21 +76,12 @@ static public function apiCheck($api,$version) { if (intval($api) != intval($version)) return 0; return version_compare($api,$version) >= 0; } - static public function itemName(Item $item) { - $n = $item->getName(); - if ($n != "Unknown") return $n; - if (count(self::$items) == 0) { - $constants = array_keys((new \ReflectionClass("pocketmine\\item\\Item"))->getConstants()); - foreach ($constants as $constant) { - $id = constant("pocketmine\\item\\Item::$constant"); - $constant = str_replace("_", " ", $constant); - self::$items[$id] = $constant; - } - } - if (isset(self::$items[$item->getId()])) - return self::$items[$item->getId()]; - return $n; - } + /** + * Returns a localized string for the gamemode + * + * @param int mode + * @return str + */ static public function gamemodeStr($mode) { if (class_exists(__NAMESPACE__."\\mc",false)) { switch ($mode) { @@ -76,13 +100,27 @@ static public function gamemodeStr($mode) { } return "$mode-mode"; } - + /** + * Check's player or sender's permissions and shows a message if appropriate + * + * @param CommandSender $sender + * @param str $permission + * @param bool $msg If false, no message is shown + * @return bool + */ static public function access(CommandSender $sender, $permission,$msg=true) { if($sender->hasPermission($permission)) return true; if ($msg) $sender->sendMessage(mc::_("You do not have permission to do that.")); return false; } + /** + * Check's if $sender is a player in game + * + * @param CommandSender $sender + * @param bool $msg If false, no message is shown + * @return bool + */ static public function inGame(CommandSender $sender,$msg = true) { if (!($sender instanceof Player)) { if ($msg) $sender->sendMessage(mc::_("You can only do this in-game")); @@ -90,18 +128,119 @@ static public function inGame(CommandSender $sender,$msg = true) { } return true; } + /** + * Takes a player and creates a string suitable for indexing + * + * @param Player|str $player - Player to index + * @return str + */ static public function iName($player) { if ($player instanceof Player) { $player = strtolower($player->getName()); } return $player; } - - static public function teleport($player, $pos) { - if (!self::apiVersion("1.12.0")) { - $mw = $player->getServer()->getPluginManager()->getPlugin("ManyWorlds"); - if ($mw !== null) return $mw->mwtp($player,$pos); + /** + * Lile file_get_contents but for a Plugin resource + * + * @param Plugin $plugin + * @param str $filename + * @return str|null + */ + static public function getResourceContents($plugin,$filename) { + $fp = $plugin->getResource($filename); + if($fp === null){ + return null; + } + $contents = stream_get_contents($fp); + fclose($fp); + return $contents; + } + /** + * Call a plugin's function + * + * @param Server $server - pocketmine server instance + * @param str $plug - plugin to call + * @param str $method - method to call + * @param mixed $default - If the plugin does not exist or it is not enable, this value uis returned + * @return mixed + */ + static public function callPlugin($server,$plug,$method,$args,$default = null) { + if (($plugin = $server->getPluginManager()->getPlugin($plug)) !== null + && $plugin->isEnabled()) { + $fn = [ $plugin, $method ]; + return $fn(...$args); + } + return $default; + } + /** + * Register a command + * + * @param Plugin $plugin - plugin that "owns" the command + * @param CommandExecutor $executor - object that will be called onCommand + * @param str $cmd - Command name + * @param array $yaml - Additional settings for this command. + */ + static public function addCommand($plugin, $executor, $cmd, $yaml) { + $newCmd = new PluginCommand($cmd,$plugin); + if (isset($yaml["description"])) + $newCmd->setDescription($yaml["description"]); + if (isset($yaml["usage"])) + $newCmd->setUsage($yaml["usage"]); + if(isset($yaml["aliases"]) and is_array($yaml["aliases"])) { + $aliasList = []; + foreach($yaml["aliases"] as $alias) { + if(strpos($alias,":")!== false) { + $this->owner->getLogger()->info("Unable to load alias $alias"); + continue; + } + $aliasList[] = $alias; + } + $newCmd->setAliases($aliasList); } - $player->teleport($pos); + if(isset($yaml["permission"])) + $newCmd->setPermission($yaml["permission"]); + if(isset($yaml["permission-message"])) + $newCmd->setPermissionMessage($yaml["permission-message"]); + $newCmd->setExecutor($executor); + $cmdMap = $plugin->getServer()->getCommandMap(); + $cmdMap->register($plugin->getDescription()->getName(),$newCmd); } + /** + * Unregisters a command + * @param Server|Plugin $obj - Access path to server instance + * @param str $cmd - Command name to remove + */ + static public function rmCommand($srv, $cmd) { + $cmdMap = $srv->getCommandMap(); + $oldCmd = $cmdMap->getCommand($cmd); + if ($oldCmd === null) return false; + $oldCmd->setLabel($cmd."_disabled"); + $oldCmd->unregister($cmdMap); + return true; + } + /** + * Send a PopUp, but takes care of checking if there are some + * plugins that might cause issues. + * + * Currently only supports SimpleAuth and BasicHUD. + * + * @param Player $player + * @param str $msg + */ + static public function sendPopup($player,$msg) { + $pm = $player->getServer()->getPluginManager(); + if (($sa = $pm->getPlugin("SimpleAuth")) !== null) { + // SimpleAuth also has a HUD when not logged in... + if ($sa->isEnabled() && !$sa->isPlayerAuthenticated($player)) return; + } + if (($hud = $pm->getPlugin("BasicHUD")) !== null) { + // Send pop-ups through BasicHUD + $hud->sendPopup($player,$msg); + return; + } + $player->sendPopup($msg); + } + + } diff --git a/src/aliuly/killrate/common/MoneyAPI.php b/src/aliuly/killrate/common/MoneyAPI.php new file mode 100644 index 0000000..4277294 --- /dev/null +++ b/src/aliuly/killrate/common/MoneyAPI.php @@ -0,0 +1,146 @@ +getLogger()->log($level,TextFormat::RED. + mc::_("# MISSING MONEY API PLUGIN")); + $this->getLogger()->error(TextFormat::BLUE. + mc::_(". Please install one of the following:")); + $this->getLogger()->error(TextFormat::WHITE. + mc::_("* GoldStd")); + $this->getLogger()->error(TextFormat::WHITE. + mc::_("* PocketMoney")); + $this->getLogger()->error(TextFormat::WHITE. + mc::_("* EconomyAPI or")); + $this->getLogger()->error(TextFormat::WHITE. + mc::_("* MassiveEconomy")); + } else { + $plugin->getLogger()->log($level,TextFormat::RED. + "# MISSING MONEY API PLUGIN"); + $this->getLogger()->error(TextFormat::BLUE. + ". Please install one of the following:"); + $this->getLogger()->error(TextFormat::WHITE. + "* GoldStd"); + $this->getLogger()->error(TextFormat::WHITE. + "* PocketMoney"); + $this->getLogger()->error(TextFormat::WHITE. + "* EconomyAPI or"); + $this->getLogger()->error(TextFormat::WHITE. + "* MassiveEconomy"); + } + } + /** + * Show a notice when the money API is found + * + * @param PluginBase $plugin - current plugin + * @param PluginBase $api - found plugin + * @param LogLevel $level - optional log level + */ + static public function foundMoney(PluginBase $plugin,$api,$level = LogLevel::INFO) { + if (class_exists(__NAMESPACE__."\\mc",false)) { + $plugin->getLogger()->log($level,TextFormat::BLUE. + mc::_("Using money API from %1%", + $api->getFullName())); + } else { + $plugin->getLogger()->log($level,TextFormat::BLUE. + "Using money API from ".$api->getFullName()); + } + } + /** + * Find a supported *money* plugin + * + * @param var obj - Server or Plugin object + * @return null|Plugin + */ + static public function moneyPlugin($obj) { + if ($obj instanceof Server) { + $server = $obj; + } else { + $server = $obj->getServer(); + } + $pm = $server->getPluginManager(); + if(!($money = $pm->getPlugin("PocketMoney")) + && !($money = $pm->getPlugin("GoldStd")) + && !($money = $pm->getPlugin("EconomyAPI")) + && !($money = $pm->getPlugin("MassiveEconomy"))){ + return null; + } + return $money; + } + /** + * Gives money to a player. + * + * @param Plugin api Economy plugin (from moneyPlugin) + * @param str|IPlayer p Player to pay + * @param int money Amount of money to play (can be negative) + * + * @return bool + */ + static public function grantMoney($api,$p,$money) { + if(!$api) return false; + switch($api->getName()){ + case "GoldStd": // takes IPlayer|str + $api->grantMoney($p, $money); + break; + case "PocketMoney": // takes str + if ($p instanceof IPlayer) $p = $p->getName(); + $api->grantMoney($p, $money); + break; + case "EconomyAPI": // Takes str + if ($p instanceof IPlayer) $p = $p->getName(); + $api->setMoney($p,$api->mymoney($p)+$money); + break; + case "MassiveEconomy": // Takes str + if ($p instanceof IPlayer) $p = $p->getName(); + $api->payPlayer($p->getName(),$money); + break; + default: + return false; + } + return true; + } + /** + * Gets player balance + * + * @param Plugin $api Economy plugin (from moneyPlugin) + * @param str|IPlayer $player Player to lookup + * + * @return int + */ + static public function getMoney($api,$player) { + if(!$api) return false; + switch($api->getName()){ + case "GoldStd": + return $api->getMoney($player); + break; + case "PocketMoney": + case "MassiveEconomy": + if ($player instanceof IPlayer) $player = $player->getName(); + return $api->getMoney($player); + case "EconomyAPI": + if ($player instanceof IPlayer) $player = $player->getName(); + return $api->mymoney($player); + default: + return false; + break; + } + } +} diff --git a/src/aliuly/killrate/common/PluginCallbackTask.php b/src/aliuly/killrate/common/PluginCallbackTask.php index 6ebcba9..2155f9f 100644 --- a/src/aliuly/killrate/common/PluginCallbackTask.php +++ b/src/aliuly/killrate/common/PluginCallbackTask.php @@ -1,31 +1,20 @@ args = $args; $this->args[] = $this; } - /** * @return callable */ diff --git a/src/aliuly/killrate/common/mc.php b/src/aliuly/killrate/common/mc.php index f73141e..966cfc7 100644 --- a/src/aliuly/killrate/common/mc.php +++ b/src/aliuly/killrate/common/mc.php @@ -1,18 +1,38 @@ getFile()); + * * mc::_("string to translate\n") + * * mc::_("string to translate %1% %2%\n",$arg1,$arg2) + * * mc::n(mc::\_("singular form"),mc::\_("Plural form"),$count) + */ abstract class mc { - /* - * Use xgettext --no-wrap [-j] [-o file] to extract messages - * -j is to join existing message files - * -o output file + /** @var str[] $txt Message translations */ + public static $txt = []; + /** Main translation function + * + * This translates strings. The naming of "_" is to make it compatible + * with gettext utilities. The string can contain "%1%", "%2%, etc... + * These are inserted from the following arguments. Use "%%" to insert + * a single "%". * - * Usage: - * mc::load("messages.po|messages.ini"); - * mc::_("string to translate\n") - * mc::n(mc::_("Plural for one"),mc::_("Plural for not one"),$count) + * @param str[] $args - messages + * @return str translated string */ - public static $txt = []; public static function _(...$args) { $fmt = array_shift($args); if (isset(self::$txt[$fmt])) $fmt = self::$txt[$fmt]; @@ -27,9 +47,23 @@ public static function _(...$args) { } return $fmt; } + /** + * Plural and singular forms. + * + * @param str $a - Singular form + * @param str $b - Plural form + * @param int $c - the number to test to select between $a or $b + * @return str - Either plural or singular forms depending on the value of $c + */ public static function n($a,$b,$c) { return $c == 1 ? $a : $b; } + /** + * Load a message file for a PocketMine plugin. Only uses .ini files. + * + * @param Plugin $plugin - owning plugin + * @param str $path - output of $plugin->getFile() + */ public static function plugin_init($plugin,$path) { if (file_exists($plugin->getDataFolder()."messages.ini")) { self::load($plugin->getDataFolder()."messages.ini"); @@ -41,7 +75,11 @@ public static function plugin_init($plugin,$path) { if (!file_exists($msgs)) return; mc::load($msgs); } - + /** + * Load the specified message catalogue. + * Can read .ini or .po files. + * @param str $f - Filename to load + */ public static function load($f) { $potxt = "\n".file_get_contents($f)."\n"; if (preg_match('/\nmsgid\s/',$potxt)) {