├── .gitignore
├── resources
└── config.yml
├── plugin.yml
├── .travis.yml
├── phpunit.xml
├── src
└── Buycraft
│ └── PocketMine
│ ├── Util
│ ├── RunAsyncTask.php
│ ├── FinalizeReportTask.php
│ ├── AnalyticsSend.php
│ ├── InventoryUtils.php
│ ├── PackageInventory.php
│ ├── CategoryInventory.php
│ └── ReportUtil.php
│ ├── Execution
│ ├── DeleteCommandsAsyncTask.php
│ ├── CategoryRefreshTask.php
│ ├── ImmediateExecutionRunner.php
│ ├── PlayerCommandExecutor.php
│ ├── CommandExecutor.php
│ ├── DeleteCommandsTask.php
│ ├── QueuedCommand.php
│ └── DuePlayerCheck.php
│ ├── Commands
│ ├── BuyCommand.php
│ ├── SecretVerificationTask.php
│ ├── BuycraftCommandAlias.php
│ └── BuycraftCommand.php
│ ├── PluginApi.php
│ ├── BuycraftListener.php
│ └── BuycraftPlugin.php
├── README.md
├── LICENSE.md
└── CONTRIBUTING.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | *.phar
--------------------------------------------------------------------------------
/resources/config.yml:
--------------------------------------------------------------------------------
1 | # BuycraftPM Configuration
2 | secret: ''
--------------------------------------------------------------------------------
/plugin.yml:
--------------------------------------------------------------------------------
1 | name: Tebex-PMMP
2 | main: Buycraft\PocketMine\BuycraftPlugin
3 | version: 2.0.1
4 | author: Tebex Limited
5 | api: 3.0.0
6 | api-version: 3.0.0
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 | php:
3 | - 7.1
4 |
5 | matrix:
6 | fast_finish: true
7 |
8 | script:
9 | - phpunit
10 | - pwd
11 | - ./build-plugin.sh
12 |
13 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 | ./tests/
14 |
15 |
16 |
17 |
18 | app/
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Util/RunAsyncTask.php:
--------------------------------------------------------------------------------
1 | asyncTask = $asyncTask;
22 | }
23 |
24 | /**
25 | * Actions to execute when run
26 | *
27 | * @param $currentTick
28 | *
29 | * @return void
30 | */
31 | public function onRun(int$currentTick)
32 | {
33 | Server::getInstance()->getAsyncPool()->submitTask($this->asyncTask);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Execution/DeleteCommandsAsyncTask.php:
--------------------------------------------------------------------------------
1 | pluginApi = $pluginApi;
22 | $this->commands = $commands;
23 | }
24 |
25 | /**
26 | * Actions to execute when run
27 | *
28 | * @param $currentTick
29 | *
30 | * @return void
31 | */
32 | public function onRun()
33 | {
34 | $this->pluginApi->deleteCommands((array)$this->commands);
35 | }
36 | }
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Commands/BuyCommand.php:
--------------------------------------------------------------------------------
1 | plugin = $plugin;
19 | }
20 |
21 | public function execute(CommandSender $sender, string $commandLabel, array $args): bool
22 | {
23 | if ($sender instanceof Player) {
24 | $this->plugin->getInventoryUtils()->showCategoryGui($sender);
25 | } else {
26 | $this->plugin->getLogger()->error("Only in-game players can execute the /buy command");
27 | }
28 | return true;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Util/FinalizeReportTask.php:
--------------------------------------------------------------------------------
1 | lines = $lines;
19 | $this->fn = BuycraftPlugin::getInstance()->getDataFolder() . 'report-' . date('Y-m-d-H-i-s') . '.txt';
20 | }
21 |
22 | /**
23 | * Actions to execute when run
24 | *
25 | * @return void
26 | */
27 | public function onRun()
28 | {
29 | $ss = ReportUtil::generateServiceStatus();
30 | $result = implode("\n", array_merge((array)$this->lines, $ss));
31 | file_put_contents($this->fn, $result);
32 | }
33 |
34 | public function onCompletion(Server $server)
35 | {
36 | BuycraftPlugin::getInstance()->getLogger()->info("Report saved to " . $this->fn);
37 | }
38 | }
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Execution/CategoryRefreshTask.php:
--------------------------------------------------------------------------------
1 | plugin = $plugin;
18 | }
19 |
20 | public function onRun(int $currentTick)
21 | {
22 | $this->plugin->getLogger()->info("Refreshing category list...");
23 |
24 | $pluginApi = $this->plugin->getPluginApi();
25 | try {
26 | $request = $pluginApi->basicGet("/listing", true, 10);
27 | $this->plugin->setCategories($request['categories']);
28 |
29 | $this->plugin->getLogger()->info("Category refresh complete.");
30 | } catch (\Exception $e) {
31 | //$this->plugin->getLogger()->logException($e);
32 | $this->plugin->getLogger()->error(TextFormat::RED . "Unable to fetch category listing.");
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BuycraftPM
2 |
3 | BuycraftPM is the official port of the Buycraft plugin to PocketMine-MP. BuycraftPM closely follows BuycraftX in both
4 | functionality and behavior as much as possible.
5 |
6 | ## Contributing
7 |
8 | We welcome contributions from the community. Please refer to the CONTRIBUTING.md file for more details. By submitting code to us, you agree to the
9 | terms set out in the CONTRIBUTING.md file
10 |
11 |
12 | ## Compatibility
13 |
14 | We are committed to making sure that BuycraftPM works on as many PocketMine-MP forks as reasonably possible. The Buycraft
15 | team tests and ensures that full functionality for BuycraftPM is available on **PocketMine-MP**, **ClearSky** and **Genisys**.
16 |
17 | Other forks may work, but are not tested by Buycraft and you may be unable to obtain support for issues that arise.
18 |
19 | ## Building the plugin
20 |
21 | To build the plugin, run `./build-plugin.sh` on any *nix host (OS X and Linux are tested by us).
22 |
23 | ## Support
24 | If you are a Buycraft customer and you need any assistance with this plugin, please contact our support team through your Buycraft account.
25 |
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Util/AnalyticsSend.php:
--------------------------------------------------------------------------------
1 | json = $json;
28 | $this->secret = $secret;
29 | }
30 |
31 | public static function sendAnalytics(BuycraftPlugin $plugin)
32 | {
33 |
34 | //noop
35 | }
36 |
37 | /**
38 | * Actions to execute when run
39 | *
40 | * @return void
41 | */
42 | public function onRun()
43 | {
44 | //noop
45 | }
46 |
47 | public function onCompletion(Server $server)
48 | {
49 | //noop
50 | }
51 | }
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Buycraft
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Execution/ImmediateExecutionRunner.php:
--------------------------------------------------------------------------------
1 | pluginApi = $pluginApi;
22 | }
23 |
24 | /**
25 | * Actions to execute when run
26 | *
27 | * @return void
28 | */
29 | public function onRun()
30 | {
31 | try {
32 | $response = $this->pluginApi->basicGet("/queue/offline-commands");
33 | $this->setResult($response->commands);
34 | } catch (\Exception $e) {
35 | $this->setResult($e);
36 | return;
37 | }
38 | }
39 |
40 | public function onCompletion(Server $server)
41 | {
42 | if ($this->getResult() instanceof \Exception) {
43 | //BuycraftPlugin::getInstance()->getLogger()->logException($this->getResult());
44 | BuycraftPlugin::getInstance()->getLogger()->error(TextFormat::RED . "Unable to fetch offline commands.");
45 | return;
46 | }
47 | foreach ($this->getResult() as $command) {
48 | BuycraftPlugin::getInstance()
49 | ->getCommandExecutionTask()
50 | ->queue($command, $command->player->name, false, $command->player->uuid ? $command->player->uuid : "");
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Execution/PlayerCommandExecutor.php:
--------------------------------------------------------------------------------
1 | pluginApi = $pluginApi;
25 | $this->due = $due;
26 | }
27 |
28 | /**
29 | * Actions to execute when run
30 | *
31 | * @return void
32 | */
33 | public function onRun()
34 | {
35 | try {
36 | $this->setResult($this->pluginApi->basicGet('/queue/online-commands/' . $this->due->id)->commands);
37 | } catch (\Exception $e) {
38 | $this->setResult($e);
39 | return;
40 | }
41 | }
42 |
43 | public function onCompletion(Server $server)
44 | {
45 | if ($this->getResult() instanceof \Exception) {
46 | //BuycraftPlugin::getInstance()->getLogger()->logException($this->getResult());
47 | BuycraftPlugin::getInstance()->getLogger()->error(TextFormat::RED . "Unable to fetch online commands for player.");
48 | return;
49 | }
50 | foreach ($this->getResult() as $command) {
51 | BuycraftPlugin::getInstance()
52 | ->getCommandExecutionTask()
53 | ->queue($command, $this->due->name, true, $this->due->uuid ? $this->due->uuid : "");
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Commands/SecretVerificationTask.php:
--------------------------------------------------------------------------------
1 | secret = $secret;
25 | $this->dataFolder = $dataFolder;
26 | }
27 |
28 | /**
29 | * Actions to execute when run
30 | *
31 | * @return void
32 | */
33 | public function onRun()
34 | {
35 | try {
36 | $api = new PluginApi($this->secret, $this->dataFolder);
37 | $this->setResult($api->basicGet("/information"));
38 | } catch (\Exception $e) {
39 | $this->setResult($e);
40 | }
41 | }
42 |
43 | public function onCompletion(Server $server)
44 | {
45 | $result = $this->getResult();
46 | if ($result instanceof \Exception) {
47 | //BuycraftPlugin::getInstance()->getLogger()->logException($result);
48 | BuycraftPlugin::getInstance()->getLogger()->error(TextFormat::RED . "This secret key appears to be invalid. Try again.");
49 | } else {
50 |
51 | BuycraftPlugin::getInstance()->changeApi(new PluginApi($this->secret, $this->dataFolder), $result);
52 | BuycraftPlugin::getInstance()->getConfig()->set('secret', $this->secret);
53 | BuycraftPlugin::getInstance()->getLogger()->info(TextFormat::GREEN . "Secret set!");
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Execution/CommandExecutor.php:
--------------------------------------------------------------------------------
1 | commands as $id => $command) {
32 | if (count($successfully_executed) >= self::MAXIMUM_COMMANDS_TO_RUN) {
33 | break;
34 | }
35 |
36 | if ($command->canExecute()) {
37 | // TODO: Capture command exceptions for our use.
38 | if (Server::getInstance()->dispatchCommand(new ConsoleCommandSender(), $command->getFinalCommand())) {
39 | $successfully_executed[] = $command;
40 | }
41 | }
42 | }
43 |
44 | // Now queue all the successfully run commands to be removed from the command queue.
45 | foreach ($successfully_executed as $executed) {
46 | BuycraftPlugin::getInstance()->getDeleteCommandsTask()->queue($executed->getCommandId());
47 | unset($this->commands[$executed->getCommandId()]);
48 | }
49 | }
50 |
51 | public function queue($command, $username, $online, $xuid = '')
52 | {
53 | $this->commands[$command->id] = new QueuedCommand($command, $username, $online, $xuid);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Commands/BuycraftCommandAlias.php:
--------------------------------------------------------------------------------
1 | plugin = $plugin;
28 | }
29 |
30 | /**
31 | * @param CommandSender $sender
32 | * @param string $commandLabel
33 | * @param string[] $args
34 | *
35 | * @return mixed
36 | */
37 | public function execute(CommandSender $sender, string $commandLabel, array $args) :bool
38 | {
39 | Server::getInstance()->dispatchCommand($sender, "tebex " . implode(" ", $args));
40 | return true;
41 | }
42 |
43 | private function sendHelp(CommandSender $sender)
44 | {
45 | $sender->sendMessage(TextFormat::GREEN . "Usage for the Tebex-PMMP plugin:");
46 | $sender->sendMessage(TextFormat::GREEN . "/tebex:secret" . TextFormat::GRAY . ": Set your server's secret.");
47 | $sender->sendMessage(TextFormat::GREEN . "/tebex:forcecheck" . TextFormat::GRAY . ": Check for current purchases.");
48 | $sender->sendMessage(TextFormat::GREEN . "/tebex:info" . TextFormat::GRAY . ": Retrieves public information about your web store.");
49 | $sender->sendMessage(TextFormat::GREEN . "/tebex:report" . TextFormat::GRAY . ": Generates a report you can send to Buycraft support.");
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to BuycraftPM
2 |
3 | Contributions to the BuycraftPM codebase must be made by using your own fork of our repository and then submitting pull requests.
4 |
5 | Contributions can take the form of new components/features, changes to existing features, tests, documentation, bug fixes or optimizations.
6 |
7 | The Buycraft team will review all contributions, and their decision is final. During the review process they may ask questions of your contributions, or request alterations or fixes. The Buycraft team reserve the right to close any pull request or issue for any reason.
8 |
9 | ## Terms of Contributing
10 |
11 | By making a contribution, you agree to the terms below, which includes granting Tebex Ltd a royalty-free, perpetual and irrevocable license to use and relicense your contribution under any terms deemed fit to Tebex. You may only contribute software and materials originally created by you or your organisation and you must have the right to make such contributions.
12 |
13 | Subject to the terms and conditions of this Agreement, you grant to Tebex and all third party recipients of software, products, services, and information distributed by Tebex a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute the contributed code and such derivative works.
14 |
15 | By submitting code for including in the BuycraftPM codebase, you represent that each code submission is of your own original creation and they you hold the copyright for such works, or are authorized to submit by the copyright holder.
16 |
17 | You agree to waive all other claims of any nature, including express contract, implied-in-fact contract, or quasi-contract, arising out of any submission of code to Tebex.
18 |
19 | The terms of contributing may be changed by us at any time, and such changes will be published in this file. Before each submission, you should review this file, and if you no longer agree to the terms, stop submitting code to us.
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Execution/DeleteCommandsTask.php:
--------------------------------------------------------------------------------
1 | pluginApi = $pluginApi;
24 | }
25 |
26 | /**
27 | * Actions to execute when run
28 | *
29 | * @param $currentTick
30 | *
31 | * @return void
32 | */
33 | public function onRun(int$currentTick)
34 | {
35 | $available = count($this->commandIds);
36 | if ($available > self::MAXIMUM_COMMANDS_TO_POST) {
37 | // Only consider the first MAXIMUM_COMMANDS_TO_POST commands.
38 | $toPost = array_slice($this->commandIds, 0, self::MAXIMUM_COMMANDS_TO_POST);
39 | $this->commandIds = array_slice($this->commandIds, self::MAXIMUM_COMMANDS_TO_POST);
40 | } else {
41 | // Copy the array
42 | $toPost = $this->commandIds;
43 | $this->commandIds = array();
44 | }
45 |
46 | if (isset($toPost) && count($toPost) > 0) {
47 | BuycraftPlugin::getInstance()->getServer()->getAsyncPool()->submitTask(new DeleteCommandsAsyncTask($this->pluginApi, $toPost));
48 | }
49 | }
50 |
51 | /**
52 | * Immediately purges all queued commands.
53 | */
54 | public function sendAllCommands()
55 | {
56 | if (count($this->commandIds) > self::MAXIMUM_COMMANDS_TO_POST) {
57 | $chunked = array_chunk($this->commandIds, self::MAXIMUM_COMMANDS_TO_POST);
58 | foreach ($chunked as $chunk) {
59 | BuycraftPlugin::getInstance()->getPluginApi()->deleteCommands($chunk);
60 | }
61 | } else {
62 | BuycraftPlugin::getInstance()->getPluginApi()->deleteCommands($this->commandIds);
63 | }
64 | }
65 |
66 | /**
67 | * Queues a command to be marked complete.
68 | * @param $id integer
69 | */
70 | public function queue($id)
71 | {
72 | if (!in_array($id, $this->commandIds)) {
73 | $this->commandIds[] = $id;
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Execution/QueuedCommand.php:
--------------------------------------------------------------------------------
1 | command = $command;
25 | $this->username = $username;
26 | $this->xuid = $xuid;
27 | $this->queuedTime = time();
28 | $this->needOnline = $needOnline;
29 | }
30 |
31 | public function getCommandId()
32 | {
33 | return $this->command->id;
34 | }
35 |
36 |
37 |
38 | public function canExecute()
39 | {
40 | $plugin = BuycraftPlugin::getInstance();
41 | $player = $plugin->getPlayer(Server::getInstance(), $this->username, $this->xuid);
42 |
43 | if ($this->needOnline) {
44 | if (!$player) {
45 | return false;
46 | }
47 | }
48 |
49 | // Check delay.
50 | if (property_exists($this->command->conditions, "delay")) {
51 | $after = $this->queuedTime + (int)$this->command->conditions->delay;
52 | if (time() < $after) {
53 | return false;
54 | }
55 | }
56 |
57 | // Check inventory slots.
58 | if (property_exists($this->command->conditions, "slots")) {
59 | // Needing inventory slots implies that the player is online, too.
60 | if ($player == NULL) {
61 | return false;
62 | }
63 |
64 | $count = 0;
65 | for ($i = 0; $i < $player->getInventory()->getSize(); $i++) {
66 | if ($player->getInventory()->getItem($i)->getId() === 0) {
67 | $count++;
68 | }
69 | }
70 |
71 | if ($count < (int)$this->command->conditions->slots) {
72 | return false;
73 | }
74 | }
75 |
76 | return true;
77 | }
78 |
79 | public function getFinalCommand()
80 | {
81 | $command = str_replace(
82 | [
83 | '{name}',
84 | '{player}',
85 | '{username}',
86 | '{uuid}',
87 | '{xuid}',
88 | '{id}'
89 | ],
90 | [
91 | $this->username,
92 | $this->username,
93 | $this->username,
94 | $this->xuid,
95 | $this->xuid,
96 | $this->xuid,
97 | ],
98 | $this->command->command
99 | );
100 |
101 | return $command;
102 | }
103 | }
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Util/InventoryUtils.php:
--------------------------------------------------------------------------------
1 | plugin = $main;
19 | }
20 |
21 | public function showCategoryGui(Player $p)
22 | {
23 | $inv = new CategoryInventory();
24 |
25 | $i = 0;
26 |
27 | foreach ($this->plugin->getCategories() as $category) {
28 | if ($i > 25) {
29 | break;
30 | }
31 | $item = Item::fromString($category['gui_item'] ?? "CHEST");
32 |
33 | $nbt = $item->getNamedTag() ?? new CompoundTag("", []);
34 | $nbt->setTag(new IntTag("categoryId", $category['id']));
35 | $item->setNamedTag($nbt);
36 |
37 | $item->setCustomName("§r§f" . $category['name']);
38 |
39 | $inv->addItem($item);
40 |
41 | $i++;
42 | }
43 |
44 | $item = Item::get(Item::WOOL, 5);
45 | $nbt = $item->getNamedTag() ?? new CompoundTag("", []);
46 | $nbt->setTag(new IntTag("buycraft-continue", 1));
47 | $item->setNamedTag($nbt);
48 | $item->setCustomName("§r§aDrag an item here");
49 | $inv->setItem(26, $item);
50 |
51 | $p->addWindow($inv);
52 | }
53 |
54 | public function showPackageGui(Player $p, $categoryId)
55 | {
56 | $category = false;
57 |
58 | foreach ($this->plugin->getCategories() as $loopedCategory) {
59 | if ($loopedCategory['id'] === $categoryId) {
60 | $category = $loopedCategory;
61 | }
62 | }
63 |
64 | if (!$category) {
65 | $p->sendMessage("There was a problem loading the packages for this category");
66 | return false;
67 | }
68 |
69 | $inv = new PackageInventory();
70 | $currency = $this->plugin->getServerInformation()->account->currency->symbol;
71 |
72 | $i = 0;
73 | foreach ($category['packages'] as $package) {
74 | if ($i > 25) {
75 | break;
76 | }
77 |
78 | $item = Item::fromString($package['gui_item'] ?? "PAPER");
79 |
80 | $nbt = $item->getNamedTag() ?? new CompoundTag("", []);
81 | $nbt->setTag(new IntTag("packageId", $package['id']));
82 | $item->setNamedTag($nbt);
83 |
84 | $item->setCustomName("§r§f" . $package['name']);
85 |
86 | $item->setLore([
87 | "§r§7Price: " . $currency . $package['price']
88 | ]);
89 |
90 | $inv->addItem($item);
91 | $i++;
92 | }
93 |
94 | $item = Item::get(Item::WOOL, 5);
95 | $nbt = $item->getNamedTag() ?? new CompoundTag("", []);
96 | $nbt->setTag(new IntTag("buycraft-continue", 1));
97 | $item->setNamedTag($nbt);
98 | $item->setCustomName("§r§aDrag an item here");
99 | $inv->setItem(26, $item);
100 |
101 | $p->addWindow($inv);
102 | }
103 |
104 | public function getPackageLink(Player $player, $packageId)
105 | {
106 | $request = $this->plugin->getPluginApi()->post("/checkout", [
107 | "username" => $player->getName(),
108 | "package_id" => $packageId
109 | ]);
110 |
111 | return $request['url'];
112 | }
113 |
114 | }
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Util/PackageInventory.php:
--------------------------------------------------------------------------------
1 | holders[$id = $player->getId()])) {
60 | $this->holders[$id] = $this->holder = $player->floor()->add(0, static::INVENTORY_HEIGHT, 0);
61 | $this->sendBlocks($player, self::SEND_BLOCKS_FAKE);
62 | $this->sendFakeTile($player);
63 | parent::onOpen($player);
64 | }
65 | }
66 |
67 | public function onClose(Player $player): void
68 | {
69 | if (isset($this->holders[$id = $player->getId()])) {
70 | parent::onClose($player);
71 | $this->sendBlocks($player, self::SEND_BLOCKS_REAL);
72 | unset($this->holders[$id]);
73 | }
74 | }
75 |
76 | protected function sendFakeTile(Player $player): void
77 | {
78 | $holder = $this->holders[$player->getId()];
79 | $pk = new BlockEntityDataPacket();
80 | $pk->x = $holder->x;
81 | $pk->y = $holder->y;
82 | $pk->z = $holder->z;
83 | $tag = new CompoundTag();
84 | $tag->setString("id", static::FAKE_TILE_ID);
85 | $customName = "Select a package";
86 | if ($customName !== null) {
87 | $tag->setString("CustomName", $customName);
88 | }
89 | $pk->namedtag = (self::$nbtWriter ?? (self::$nbtWriter = new NetworkLittleEndianNBTStream()))->write($tag);
90 | $player->dataPacket($pk);
91 | }
92 |
93 | protected function sendBlocks(Player $player, int $type): void
94 | {
95 | switch ($type) {
96 | case self::SEND_BLOCKS_FAKE:
97 | $player->getLevel()->sendBlocks([$player], $this->getFakeBlocks($this->holders[$player->getId()]));
98 | return;
99 | case self::SEND_BLOCKS_REAL:
100 | $player->getLevel()->sendBlocks([$player], $this->getRealBlocks($player, $this->holders[$player->getId()]));
101 | return;
102 | }
103 | throw new \Error("Unhandled type $type provided.");
104 | }
105 |
106 | protected function getFakeBlocks(Vector3 $holder): array
107 | {
108 | return [
109 | Block::get(static::FAKE_BLOCK_ID, static::FAKE_BLOCK_DATA)->setComponents($holder->x, $holder->y, $holder->z)
110 | ];
111 | }
112 |
113 | protected function getRealBlocks(Player $player, Vector3 $holder): array
114 | {
115 | return [
116 | $player->getLevel()->getBlockAt($holder->x, $holder->y, $holder->z)
117 | ];
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Util/CategoryInventory.php:
--------------------------------------------------------------------------------
1 | holders[$id = $player->getId()])) {
60 | $this->holders[$id] = $this->holder = $player->floor()->add(0, static::INVENTORY_HEIGHT, 0);
61 | $this->sendBlocks($player, self::SEND_BLOCKS_FAKE);
62 | $this->sendFakeTile($player);
63 | parent::onOpen($player);
64 | }
65 | }
66 |
67 | public function onClose(Player $player): void
68 | {
69 | if (isset($this->holders[$id = $player->getId()])) {
70 | parent::onClose($player);
71 | $this->sendBlocks($player, self::SEND_BLOCKS_REAL);
72 | unset($this->holders[$id]);
73 | }
74 | }
75 |
76 | protected function sendFakeTile(Player $player): void
77 | {
78 | $holder = $this->holders[$player->getId()];
79 | $pk = new BlockEntityDataPacket();
80 | $pk->x = $holder->x;
81 | $pk->y = $holder->y;
82 | $pk->z = $holder->z;
83 | $tag = new CompoundTag();
84 | $tag->setString("id", static::FAKE_TILE_ID);
85 | $customName = "Select a category";
86 | if ($customName !== null) {
87 | $tag->setString("CustomName", $customName);
88 | }
89 | $pk->namedtag = (self::$nbtWriter ?? (self::$nbtWriter = new NetworkLittleEndianNBTStream()))->write($tag);
90 | $player->dataPacket($pk);
91 | }
92 |
93 | protected function sendBlocks(Player $player, int $type): void
94 | {
95 | switch ($type) {
96 | case self::SEND_BLOCKS_FAKE:
97 | $player->getLevel()->sendBlocks([$player], $this->getFakeBlocks($this->holders[$player->getId()]));
98 | return;
99 | case self::SEND_BLOCKS_REAL:
100 | $player->getLevel()->sendBlocks([$player], $this->getRealBlocks($player, $this->holders[$player->getId()]));
101 | return;
102 | }
103 | throw new \Error("Unhandled type $type provided.");
104 | }
105 |
106 | protected function getFakeBlocks(Vector3 $holder): array
107 | {
108 | return [
109 | Block::get(static::FAKE_BLOCK_ID, static::FAKE_BLOCK_DATA)->setComponents($holder->x, $holder->y, $holder->z)
110 | ];
111 | }
112 |
113 | protected function getRealBlocks(Player $player, Vector3 $holder): array
114 | {
115 | return [
116 | $player->getLevel()->getBlockAt($holder->x, $holder->y, $holder->z)
117 | ];
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Util/ReportUtil.php:
--------------------------------------------------------------------------------
1 | getPluginApi()->getSecret();
22 |
23 | $report_lines = [];
24 | $report_lines[] = "### Server Information ###";
25 | $report_lines[] = "Report generated on " . date('r');
26 | $report_lines[] = "";
27 | $report_lines[] = "Operating system: " . PHP_OS . " / " . Utils::getOS();
28 | $report_lines[] = "PHP version: " . PHP_VERSION;
29 | $report_lines[] = "Server version: " . Server::getInstance()->getPocketMineVersion() . " (API: " .
30 | Server::getInstance()->getApiVersion() . ")";
31 |
32 | $report_lines[] = "";
33 | $report_lines[] = "### Platform Information ###";
34 | $report_lines[] = "Plugin version: " . BuycraftPlugin::getInstance()->getDescription()->getVersion();
35 | $report_lines[] = "";
36 | $api_exists = BuycraftPlugin::getInstance()->getPluginApi() !== null;
37 | $report_lines[] = "Connected to Buycraft? " . ($api_exists ? 'yes' : 'no');
38 | $information = BuycraftPlugin::getInstance()->getServerInformation();
39 | if ($information !== NULL) {
40 | $report_lines[] = "Web store ID: " . $information->account->id;
41 | $report_lines[] = "Web store URL: " . $information->account->domain;
42 | $report_lines[] = "Web store name: " . $information->account->name;
43 | $report_lines[] = "Web store currency: " . $information->account->currency->iso_4217;
44 | $report_lines[] = "Web store in online mode? " . ($information->account->online_mode ? 'yes' : 'no');
45 |
46 | $report_lines[] = "Server name: " . $information->server->name;
47 | $report_lines[] = "Server ID: " . $information->server->id;
48 | }
49 |
50 | $report_lines[] = "";
51 | $report_lines[] = "### Service Status ###";
52 | return $report_lines;
53 | }
54 |
55 | /**
56 | * Generates the service status lines (this has to be done in an async task for obvious reasons).
57 | * @return array
58 | */
59 | public static function generateServiceStatus() {
60 | $checks = [
61 | // Notice that we're not using just plugin.buycraft.net. That's because it throws an error. We'll compromise
62 | // and use the PocketMine versions page.
63 | 'Buycraft plugin API' => [
64 | "url" => PluginApi::BUYCRAFT_PLUGIN_API_URL . '/versions/pocketmine',
65 | "headers" => [
66 | "X-Buycraft-Secret" => ReportUtil::$secret
67 | ]
68 | ],
69 | "Google over HTTPS" => 'https://encrypted.google.com',
70 | "Google over HTTP" => 'http://www.google.com'
71 | ];
72 |
73 | $results = [];
74 |
75 | foreach($checks as $name => $url) {
76 |
77 | if (is_array($url)) {
78 | $ctx = curl_init($url['url']);
79 |
80 | $headers = [];
81 | foreach ($url['headers'] as $k => $v){
82 | $headers[] = "{$k}: " . $v . ",";
83 | }
84 | curl_setopt($ctx, CURLOPT_HTTPHEADER, [implode(", ", $headers), "User-Agent: BuycraftPM"]);
85 | $url = $url['url'];
86 | } else {
87 | $ctx = curl_init($url);
88 | }
89 |
90 | curl_setopt($ctx, CURLOPT_FAILONERROR, true);
91 | curl_setopt($ctx, CURLOPT_SSL_VERIFYPEER, false);
92 | curl_setopt($ctx, CURLOPT_TIMEOUT, 5);
93 | curl_setopt($ctx, CURLOPT_RETURNTRANSFER, true);
94 | $result = curl_exec($ctx);
95 | if ($result === FALSE) {
96 | $results[] = "Can't access " . $name . " (" . $url . "): " . curl_error($ctx);
97 | } else {
98 | $results[] = "Can access " . $name . " (" . $url . ")";
99 | }
100 | curl_close($ctx);
101 | }
102 |
103 | return $results;
104 | }
105 | }
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Execution/DuePlayerCheck.php:
--------------------------------------------------------------------------------
1 | pluginApi = $pluginApi;
29 | $this->allowReschedule = $allowReschedule;
30 | }
31 |
32 | /**
33 | * Actions to execute when run
34 | *
35 | * @return void
36 | */
37 | public function onRun()
38 | {
39 | $page = 1;
40 | $allDue = array();
41 |
42 | do {
43 | // Sleep for a while between fetches.
44 | if ($page > 1) {
45 | usleep(mt_rand(5, 15) * 100000);
46 | }
47 |
48 | try {
49 | $result = $this->pluginApi->basicGet("/queue?limit=" . self::PLAYERS_PER_PAGE . "&page=" . $page);
50 | } catch (\Exception $e) {
51 | $this->setResult($e);
52 | return;
53 | }
54 |
55 | if (count($result->players) == 0) {
56 | break;
57 | }
58 |
59 | foreach ($result->players as $player) {
60 | $allDue[strtolower($player->name)] = $player;
61 | }
62 |
63 | $page++;
64 | } while ($result->meta->more);
65 |
66 | $this->setResult(array(
67 | 'all_due' => $allDue,
68 | 'next_delay' => $result->meta->next_check ?? self::FALLBACK_DELAY,
69 | 'execute_offline' => $result->meta->execute_offline
70 | ));
71 | }
72 |
73 | public function onCompletion(Server $server)
74 | {
75 | $plugin = BuycraftPlugin::getInstance();
76 | $result = $this->getResult();
77 |
78 | // Test if the result is an exception, which indicates something went wrong
79 | if (!($result instanceof \Exception)) {
80 | $plugin->getLogger()->info("Found " . count($result['all_due']) . " due player(s).");
81 | $plugin->setAllDue($result['all_due']);
82 |
83 | // See if we can execute some commands right now
84 | if ($result['execute_offline']) {
85 | $plugin->getLogger()->info("Executing commands that can be run now...");
86 | $server->getAsyncPool()->submitTask(new ImmediateExecutionRunner($this->pluginApi));
87 | }
88 |
89 | // Check for player command execution we can do.
90 | $canProcessNow = array_slice(array_filter($result['all_due'], function ($due) use ($server, $plugin) {
91 | return $plugin->getPlayer($server, $due->name, $due->uuid ? $due->uuid : "");
92 | }), 0, self::MAXIMUM_ONLINE_PLAYERS_TO_PROCESS);
93 |
94 | if (count($canProcessNow) > 0) {
95 | $plugin->getLogger()->info("Running commands for " . count($canProcessNow) . " online player(s)...");
96 |
97 | $at = 1;
98 | foreach ($canProcessNow as $due) {
99 | $this->scheduleDelayedAsyncTask(new PlayerCommandExecutor($this->pluginApi, $due), 10 * $at++);
100 | }
101 | }
102 | } else {
103 | $plugin->getLogger()->error("Check failed with message: " . $result->getMessage());
104 | }
105 |
106 | // Reschedule this task if desired.
107 | if ($this->allowReschedule) {
108 | // PocketMine-MP doesn't allow us to directly delay the eventual execution of an asynchronous task, so
109 | // a workaround must be used.
110 | $nextDelay = is_array($result) ? $result['next_delay'] : self::FALLBACK_DELAY;
111 | $this->scheduleDelayedAsyncTask(new DuePlayerCheck($this->pluginApi, true), $nextDelay * 20);
112 | }
113 | }
114 |
115 | private function scheduleDelayedAsyncTask($task, $delay)
116 | {
117 | BuycraftPlugin::getInstance()->getScheduler()->scheduleDelayedTask(new RunAsyncTask(BuycraftPlugin::getInstance(), $task), $delay);
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/PluginApi.php:
--------------------------------------------------------------------------------
1 | secret = $secret;
21 | $this->dataFolder = $dataFolder;
22 | }
23 |
24 | /**
25 | * Returns the decoded JSON response of a simple GET Buycraft API call.
26 | * @param $endpoint string
27 | * @return mixed
28 | * @throws \Exception
29 | */
30 | public function basicGet($endpoint, $assoc = false, $timeout = 5)
31 | {
32 | // Do a basic GET request
33 | $ctx = $this->initializeCurl(self::BUYCRAFT_PLUGIN_API_URL . $endpoint, $timeout);
34 | $body = curl_exec($ctx);
35 |
36 | // Did the request fail? If so, return an error.
37 | if ($body === FALSE) {
38 | $err = curl_error($ctx);
39 | curl_close($ctx);
40 |
41 | throw new \Exception("cURL request has failed: " . $err);
42 | }
43 |
44 | curl_close($ctx);
45 |
46 | // Try to deserialize the response as JSON.
47 | $result = json_decode($body, $assoc);
48 |
49 | if ($result === NULL) {
50 | throw new \Exception("Result can't be decoded as JSON.");
51 | }
52 |
53 | if ($assoc) {
54 | if (array_key_exists('error_code', $result)) {
55 | throw new \Exception("Error " . $result['error_code'] . ": " . $result['error_message']);
56 | }
57 | } else {
58 | if (property_exists($result, 'error_code')) {
59 | throw new \Exception("Error " . $result->error_code . ": " . $result->error_message);
60 | }
61 | }
62 |
63 | return $result;
64 | }
65 |
66 | public function post($endpoint, $data)
67 | {
68 | $data = json_encode($data);
69 |
70 | $ctx = curl_init(self::BUYCRAFT_PLUGIN_API_URL . $endpoint);
71 | curl_setopt($ctx, CURLOPT_HTTPHEADER, [
72 | "X-Buycraft-Secret: " . $this->secret,
73 | "User-Agent: BuycraftPM",
74 | "Content-Type: application/json",
75 | "Content-Length: " . strlen($data)
76 | ]);
77 |
78 | curl_setopt($ctx, CURLOPT_SSL_VERIFYPEER, false);
79 | curl_setopt($ctx, CURLOPT_TIMEOUT, 5);
80 | curl_setopt($ctx, CURLOPT_CUSTOMREQUEST, "POST");
81 | curl_setopt($ctx, CURLOPT_POSTFIELDS, $data);
82 | curl_setopt($ctx, CURLOPT_RETURNTRANSFER, true);
83 |
84 |
85 | $body = curl_exec($ctx);
86 |
87 | if ($body === FALSE) {
88 | $err = curl_error($ctx);
89 | curl_close($ctx);
90 |
91 | throw new \Exception("cURL request has failed: " . $err);
92 | }
93 |
94 | curl_close($ctx);
95 |
96 | $result = json_decode($body, true);
97 |
98 | if ($result === NULL) {
99 | throw new \Exception("Result can't be decoded as JSON.");
100 | }
101 |
102 | if (array_key_exists('error_code', $result)) {
103 | throw new \Exception("Error " . $result['error_code'] . ": " . $result['error_message']);
104 | }
105 |
106 | return $result;
107 | }
108 |
109 | /**
110 | * Returns a cURL session ready to be configured further. This sets the required cURL options for the Buycraft API.
111 | * @param $url string
112 | * @return resource
113 | */
114 | private function initializeCurl($url, $timeout = 5)
115 | {
116 | $ctx = curl_init($url);
117 | curl_setopt($ctx, CURLOPT_HTTPHEADER, ["X-Buycraft-Secret: " . $this->secret, "User-Agent: BuycraftPM"]);
118 | curl_setopt($ctx, CURLOPT_RETURNTRANSFER, true);
119 | curl_setopt($ctx, CURLOPT_SSL_VERIFYPEER, false);
120 | curl_setopt($ctx, CURLOPT_TIMEOUT, $timeout);
121 | return $ctx;
122 | }
123 |
124 | /**
125 | * Delete the requested commands.
126 | * @param $ids array|integer
127 | * @throws \Exception
128 | */
129 | public function deleteCommands($ids)
130 | {
131 | if (count($ids) == 0) {
132 | throw new \Exception("Passed ids parameter is not a non-empty array.");
133 | }
134 |
135 | $query = "ids[]=" . implode('&ids[]=', $ids);
136 | $ctx = $this->initializeCurl(self::BUYCRAFT_PLUGIN_API_URL . "/queue");
137 | curl_setopt($ctx, CURLOPT_FAILONERROR, true);
138 | curl_setopt($ctx, CURLOPT_POST, 1);
139 | curl_setopt($ctx, CURLOPT_CUSTOMREQUEST, "DELETE");
140 | curl_setopt($ctx, CURLOPT_POSTFIELDS, $query);
141 | $result = curl_exec($ctx);
142 | $err = curl_error($ctx);
143 | curl_close($ctx);
144 |
145 | if ($result === FALSE) {
146 | throw new \Exception("Unable to delete commands: " . $err);
147 | }
148 | }
149 |
150 | public function getSecret()
151 | {
152 | return $this->secret;
153 | }
154 | }
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/BuycraftListener.php:
--------------------------------------------------------------------------------
1 | plugin = $main;
29 | }
30 |
31 | public function onPlayerJoin(PlayerJoinEvent $event)
32 | {
33 | $player = $event->getPlayer();
34 | if ($this->plugin->isDue($player)) {
35 | $duePlayer = $this->plugin->getDue($player);
36 | $this->plugin->removeDue($player);
37 |
38 | $this->plugin->getLogger()->info("Executing login commands for " . $player->getName() . "[XUID: {$player->getXuid()}]...");
39 | Server::getInstance()->getAsyncPool()->submitTask(new PlayerCommandExecutor($this->plugin->getPluginApi(),
40 | $duePlayer));
41 | }
42 | }
43 |
44 |
45 | public function onInventoryTransaction(InventoryTransactionEvent $event): void
46 | {
47 | $tr = $event->getTransaction();
48 | $actions = $tr->getActions();
49 |
50 |
51 | foreach ($actions as $action) {
52 | if ($action instanceof SlotChangeAction) {
53 | if ($action->getInventory() instanceof CategoryInventory ||
54 | $action->getInventory() instanceof PackageInventory) {
55 | $event->setCancelled(true);
56 |
57 | $target = $action->getTargetItem();
58 | if ($target->getNamedTag()->hasTag("buycraft-continue", IntTag::class)) {
59 | if ($action->getInventory() instanceof CategoryInventory) {
60 | $event->setCancelled();
61 | $this->handleCategoryInventoryClick($event, $action);
62 | } elseif
63 | ($action->getInventory() instanceof PackageInventory) {
64 | $event->setCancelled();
65 | $this->handlePackageInventoryClick($event, $action);
66 | }
67 | }
68 |
69 | }
70 | }
71 | }
72 | }
73 |
74 |
75 | private function handleCategoryInventoryClick(InventoryTransactionEvent $event, SlotChangeAction $action)
76 | {
77 | $item = $action->getSourceItem();
78 |
79 | if (!$item) {
80 | return false;
81 | }
82 |
83 | $nbt = $item->getNamedTag();
84 |
85 | if (!$nbt->hasTag("categoryId", IntTag::class)) {
86 | return false;
87 | }
88 |
89 | $p = $event->getTransaction()->getSource();
90 |
91 | $p->removeWindow($action->getInventory());
92 |
93 | $inventoryUtils = $this->plugin->getInventoryUtils();
94 |
95 | $this->plugin->getScheduler()->scheduleDelayedTask(new class($inventoryUtils, $p, $nbt) extends Task
96 | {
97 |
98 | private $inventoryUtils;
99 | private $p;
100 | private $nbt;
101 |
102 | public function __construct($inventoryUtils, $p, $nbt)
103 | {
104 | $this->inventoryUtils = $inventoryUtils;
105 | $this->p = $p;
106 | $this->nbt = $nbt;
107 | }
108 |
109 | function onRun(int $currentTick)
110 | {
111 | $this->inventoryUtils->showPackageGui($this->p, $this->nbt->getInt("categoryId"));
112 | }
113 |
114 | }, 10);
115 |
116 | return true;
117 | }
118 |
119 | private
120 | function handlePackageInventoryClick(InventoryTransactionEvent $event, SlotChangeAction $action)
121 | {
122 | $item = $action->getSourceItem();
123 |
124 | if (!$item) {
125 | return false;
126 | }
127 |
128 |
129 | $nbt = $item->getNamedTag();
130 |
131 | if (!$nbt->hasTag("packageId", IntTag::class)) {
132 | return false;
133 | }
134 |
135 | $p = $event->getTransaction()->getSource();
136 | $packageId = $nbt->getInt("packageId");
137 |
138 | $p->removeWindow($action->getInventory());
139 |
140 | $url = $this->plugin->getInventoryUtils()->getPackageLink($p, $packageId);
141 |
142 | $pk = new TextPacket();
143 | $pk->type = TextPacket::TYPE_RAW;
144 | $pk->message = "§a" . $url;
145 |
146 | $p->sendDataPacket($pk, false, false);
147 |
148 |
149 | return true;
150 | }
151 | }
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/Commands/BuycraftCommand.php:
--------------------------------------------------------------------------------
1 | plugin = $plugin;
27 | }
28 |
29 | /**
30 | * @param CommandSender $sender
31 | * @param string $commandLabel
32 | * @param string[] $args
33 | *
34 | * @return mixed
35 | */
36 | public function execute(CommandSender $sender, string $commandLabel, array $args) :bool
37 | {
38 | if (!$sender->hasPermission('buycraft.admin')) {
39 | $sender->sendMessage(TextFormat::RED . "You don't have permission to use Buycraft administrative commands.");
40 | return true;
41 | }
42 |
43 | if (count($args) == 0) {
44 | $this->sendHelp($sender);
45 | return true;
46 | }
47 |
48 | switch ($args[0]) {
49 | case "secret":
50 | if (!($sender instanceof ConsoleCommandSender)) {
51 | $sender->sendMessage(TextFormat::RED . "This command must be run from the console.");
52 | return true;
53 | }
54 |
55 | if (count($args) != 2) {
56 | $sender->sendMessage(TextFormat::RED . "This command requires a secret key.");
57 | return true;
58 | }
59 |
60 | $secret = $args[1];
61 |
62 | $this->plugin->getServer()->getAsyncPool()->submitTask(new SecretVerificationTask($secret, $this->plugin->getDataFolder()));
63 | break;
64 | case "forcecheck":
65 | if (count($args) != 1) {
66 | $sender->sendMessage(TextFormat::RED . "This command doesn't take any arguments.");
67 | return true;
68 | }
69 |
70 | if ($this->plugin->getPluginApi() == null) {
71 | $sender->sendMessage(TextFormat::RED . "You didn't set your secret (or it is invalid). Please set it and try again.");
72 | return true;
73 | }
74 |
75 | $this->plugin->getServer()->getAsyncPool()->submitTask(new DuePlayerCheck($this->plugin->getPluginApi(), false));
76 | $sender->sendMessage(TextFormat::GREEN . "Force check successfully queued.");
77 | break;
78 | case "info":
79 | if (count($args) != 1) {
80 | $sender->sendMessage(TextFormat::RED . "This command doesn't take any arguments.");
81 | return true;
82 | }
83 |
84 | if ($this->plugin->getServerInformation() == null) {
85 | $sender->sendMessage(TextFormat::RED . "No server information found (did you forget to set your secret?)");
86 | return true;
87 | }
88 |
89 | $sender->sendMessage(TextFormat::GREEN . "Server " . $this->plugin->getServerInformation()->server->name . " on account " .
90 | $this->plugin->getServerInformation()->account->name);
91 | if (isset($this->plugin->getServerInformation()->game_type)) {
92 | $sender->sendMessage(TextFormat::GREEN . "Web store Type: "
93 | . $this->plugin->getServerInformation()->game_type);
94 | }
95 | $sender->sendMessage(TextFormat::GREEN . "Web store URL: " . $this->plugin->getServerInformation()->account->domain);
96 | $sender->sendMessage(TextFormat::GREEN . "Server currency is " . $this->plugin->getServerInformation()->account->currency->iso_4217);
97 | break;
98 | case "report":
99 | if (!($sender instanceof ConsoleCommandSender)) {
100 | $sender->sendMessage(TextFormat::RED . "This command must be run from the console.");
101 | return true;
102 | }
103 |
104 | $sender->sendMessage(TextFormat::YELLOW . "Generating report, please wait...");
105 | $lines = ReportUtil::generateBaseReport();
106 | $this->plugin->getServer()->getAsyncPool()->submitTask(new FinalizeReportTask($lines));
107 | break;
108 | }
109 |
110 | return true;
111 | }
112 |
113 | private function sendHelp(CommandSender $sender)
114 | {
115 | $sender->sendMessage(TextFormat::GREEN . "Usage for the Tebex-PMMP plugin:");
116 | $sender->sendMessage(TextFormat::GREEN . "/tebex:secret" . TextFormat::GRAY . ": Set your server's secret.");
117 | $sender->sendMessage(TextFormat::GREEN . "/tebex:forcecheck" . TextFormat::GRAY . ": Check for current purchases.");
118 | $sender->sendMessage(TextFormat::GREEN . "/tebex:info" . TextFormat::GRAY . ": Retrieves public information about your web store.");
119 | $sender->sendMessage(TextFormat::GREEN . "/tebex:report" . TextFormat::GRAY . ": Generates a report you can send to Buycraft support.");
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/Buycraft/PocketMine/BuycraftPlugin.php:
--------------------------------------------------------------------------------
1 | getLogger()->error("Tebex-PMMP requires the curl extension to be installed with SSL support. Halting...");
47 | return;
48 | }
49 |
50 | $version = curl_version();
51 | $ssl_supported = ($version['features'] & CURL_VERSION_SSL);
52 | if (!$ssl_supported)
53 | {
54 | $this->getLogger()->error("Tebex-PMMP requires the curl extension to be installed with SSL support. Halting...");
55 | return;
56 | }
57 |
58 | self::$instance = $this;
59 |
60 | $this->saveDefaultConfig();
61 |
62 | $secret = $this->getConfig()->get('secret');
63 | if ($secret) {
64 | $api = new PluginApi($secret, $this->getDataFolder());
65 | $this->inventoryUtils = new InventoryUtils($this);
66 | try {
67 | $this->verifyInformation($api);
68 | $this->pluginApi = $api;
69 | $this->startInitialTasks();
70 | } catch (\Exception $e) {
71 | $this->getLogger()->warning("Unable to verify information");
72 | //$this->getLogger()->logException($e);
73 | }
74 | } else {
75 |
76 | //Can we migrate?
77 | if(file_exists($this->getDataFolder() . "../BuycraftPM/config.yml")){
78 | $oldconfig = new Config($this->getDataFolder() . "../BuycraftPM/config.yml",Config::YAML);
79 | if ($oldconfig->get("secret")) {
80 | $this->getLogger()->info("Migrating secret from old BuycraftPM plugin...");
81 | $this->getServer()->getAsyncPool()->submitTask(
82 | new SecretVerificationTask($oldconfig->get("secret"), $this->getDataFolder())
83 | );
84 | }
85 | } else {
86 |
87 | $this->getLogger()
88 | ->info("Looks like this is your first time using Tebex. Set up your server by using 'tebex secret '.");
89 | }
90 | }
91 |
92 | $this->getServer()->getPluginManager()->registerEvents(new BuycraftListener($this), $this);
93 | $this->getServer()->getCommandMap()->register("buycraft", new BuycraftCommandAlias($this, "buycraft"));
94 | $this->getServer()->getCommandMap()->register("tebex", new BuycraftCommand($this, "tebex"));
95 | $this->getServer()->getCommandMap()->register("buy", new BuyCommand($this));
96 | }
97 |
98 | private function verifyInformation(PluginApi $api)
99 | {
100 | try {
101 | $this->serverInformation = $api->basicGet("/information");
102 | } catch (\Exception $e) {
103 | $this->getLogger()->warning("Unable to verify information");
104 | //$this->getLogger()->logException($e);
105 | }
106 | }
107 |
108 | private function startInitialTasks()
109 | {
110 | $this->commandExecutionTask = new CommandExecutor();
111 | $this->getScheduler()->scheduleRepeatingTask($this->commandExecutionTask, 1);
112 | $this->deleteCommandsTask = new DeleteCommandsTask($this->pluginApi);
113 | $this->getScheduler()->scheduleRepeatingTask($this->deleteCommandsTask, 20);
114 | $this->categoryRefreshTask = new CategoryRefreshTask($this);
115 | $this->getScheduler()->scheduleRepeatingTask($this->categoryRefreshTask, 20 * 60 * 3);
116 | $this->getServer()->getAsyncPool()->submitTask(new DuePlayerCheck($this->pluginApi, true));
117 | }
118 |
119 | public function onDisable()
120 | {
121 | $this->saveConfig();
122 | }
123 |
124 | /**
125 | * @return PluginApi
126 | */
127 | public function getPluginApi()
128 | {
129 | return $this->pluginApi;
130 | }
131 |
132 | /**
133 | * @return CommandExecutor
134 | */
135 | public function getCommandExecutionTask()
136 | {
137 | return $this->commandExecutionTask;
138 | }
139 |
140 | /**
141 | * @return DeleteCommandsTask
142 | */
143 | public function getDeleteCommandsTask()
144 | {
145 | return $this->deleteCommandsTask;
146 | }
147 |
148 | /**
149 | * @return bool
150 | */
151 | public function isDue(Player $player): bool
152 | {
153 | return isset($this->allDue[$player->getLowerCaseName()]);
154 | }
155 |
156 | /**
157 | * @return object
158 | */
159 | public function getDue(Player $player)
160 | {
161 | return $this->allDue[$player->getLowerCaseName()];
162 | }
163 |
164 | public function removeDue(Player $player): void
165 | {
166 | unset($this->allDue[$player->getLowerCaseName()]);
167 | }
168 |
169 | /**
170 | * @param array $allDue
171 | */
172 | public function setAllDue(array $allDue)
173 | {
174 | $this->allDue = $allDue;
175 | }
176 |
177 | public function getPlayer(Server $server, $username, $xuid = '')
178 | {
179 | if ($xuid != '') {
180 | $this->getLogger()->info("Checking for existing of player with XUID {$xuid}");
181 | foreach ($server->getOnlinePlayers() as $player) {
182 | if ($player->getXuid() === $xuid) {
183 | return $player;
184 | }
185 | }
186 |
187 | return false;
188 | }
189 |
190 | $this->getLogger()->info("Checking for existing of player with Username {$username}");
191 |
192 | $player = $server->getPlayerExact($username);
193 |
194 | return $player ? $player : false;
195 | }
196 |
197 | /**
198 | * Attempts to change the current API object. Will not always work, but due to the "design" of threaded PHP, this
199 | * is the only way we can accomplish this.
200 | * @param $newApi PluginApi
201 | * @param $information mixed
202 | */
203 | public function changeApi(PluginApi $newApi, $information)
204 | {
205 | $this->pluginApi = $newApi;
206 | $this->getScheduler()->cancelAllTasks();
207 | $this->startInitialTasks();
208 |
209 | // change information if required (for secret command)
210 | if ($information !== NULL) {
211 | $this->serverInformation = $information;
212 | }
213 | }
214 |
215 | /**
216 | * @return mixed
217 | */
218 | public function getServerInformation()
219 | {
220 | return $this->serverInformation;
221 | }
222 |
223 | public function setCategories(array $categories)
224 | {
225 | $this->categories = $categories;
226 | }
227 |
228 | public function getCategories()
229 | {
230 | return $this->categories;
231 | }
232 |
233 | public function getInventoryUtils()
234 | {
235 | return $this->inventoryUtils;
236 | }
237 | }
--------------------------------------------------------------------------------