├── .idea
├── .gitignore
├── Commando.iml
├── misc.xml
├── modules.xml
├── php.xml
└── vcs.xml
├── .poggit.yml
├── LICENSE
├── README.md
├── commando.png
├── composer.json
├── composer.lock
├── docs
└── MIGRATION.md
├── src
└── CortexPE
│ └── Commando
│ ├── BaseCommand.php
│ ├── BaseSubCommand.php
│ ├── IRunnable.php
│ ├── PacketHooker.php
│ ├── args
│ ├── BaseArgument.php
│ ├── BlockPositionArgument.php
│ ├── BooleanArgument.php
│ ├── FloatArgument.php
│ ├── IntegerArgument.php
│ ├── RawStringArgument.php
│ ├── StringEnumArgument.php
│ ├── TargetPlayerArgument.php
│ ├── TextArgument.php
│ └── Vector3Argument.php
│ ├── constraint
│ ├── BaseConstraint.php
│ ├── ConsoleRequiredConstraint.php
│ └── InGameRequiredConstraint.php
│ ├── exception
│ ├── ArgumentOrderException.php
│ ├── CommandoException.php
│ ├── HookAlreadyRegistered.php
│ └── InvalidErrorCode.php
│ ├── store
│ └── SoftEnumStore.php
│ └── traits
│ ├── ArgumentableTrait.php
│ └── IArgumentable.php
└── virion.yml
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 |
--------------------------------------------------------------------------------
/.idea/Commando.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/php.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.poggit.yml:
--------------------------------------------------------------------------------
1 | --- # Poggit-CI Manifest. Open the CI at https://poggit.pmmp.io/ci/Paroxity/Commando
2 | build-by-default: true
3 | branches:
4 | - master
5 | projects:
6 | Commando:
7 | model: virion
8 | type: library
9 | libs:
10 | - src: Muqsit/SimplePacketHandler/SimplePacketHandler
11 | version: ^0.1.4
12 | ...
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Commando
2 |
3 |
4 | A PocketMine-MP Virion for easier implementation of dynamic commands, including support for Minecraft: Bedrock Edition argument listing aimed for both the end users and the plugin developers.
5 |
6 | Refer to the [official documentation](https://github.com/CortexPE/Commando/blob/master/README.md) for instructions on how to use this virion library.
7 |
8 | - Poggit CI [https://poggit.pmmp.io/ci/Paroxity/Commando](https://poggit.pmmp.io/ci/Paroxity/Commando/Commando)
9 | - Packagist [https://packagist.org/packages/paroxity/commando](https://packagist.org/packages/paroxity/commando)
10 |
11 | ## Differences
12 | - Support infinite depth subcommands (used in [PiggyFactions](https://github.com/DaPigGuy/PiggyFactions))
13 | - Improve error handling for command arguments
14 | - And other miscellaneous bug fixes
15 |
16 | We will try to keep this fork up-to-date with the upstream changes.
17 |
18 | -----
19 | **This framework was made with :heart: by CortexPE, modified by Paroxity. Enjoy!~ :3**
20 |
--------------------------------------------------------------------------------
/commando.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Paroxity/Commando/625f33888132cfadc570be33001488d10e84f0d0/commando.png
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "paroxity/commando",
3 | "description": "A Command Framework virion for PocketMine-MP ",
4 | "type": "library",
5 | "license": "LGPL-3.0-only",
6 | "require": {
7 | "pocketmine/pocketmine-mp": "^5.0",
8 | "muqsit/simple-packet-handler": "^0.1.4"
9 | },
10 | "autoload": {
11 | "psr-4": {"CortexPE\\Commando\\": ["src/CortexPE/Commando/"]}
12 | },
13 | "extra": {
14 | "virion": {
15 | "spec": "3.0",
16 | "namespace-root": "CortexPE\\Commando"
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "c4ceaa9d387a5d82fcf1c21d70331fb0",
8 | "packages": [
9 | {
10 | "name": "adhocore/json-comment",
11 | "version": "1.2.1",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/adhocore/php-json-comment.git",
15 | "reference": "651023f9fe52e9efa2198cbaf6e481d1968e2377"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/adhocore/php-json-comment/zipball/651023f9fe52e9efa2198cbaf6e481d1968e2377",
20 | "reference": "651023f9fe52e9efa2198cbaf6e481d1968e2377",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "ext-ctype": "*",
25 | "php": ">=7.0"
26 | },
27 | "require-dev": {
28 | "phpunit/phpunit": "^6.5 || ^7.5 || ^8.5"
29 | },
30 | "type": "library",
31 | "autoload": {
32 | "psr-4": {
33 | "Ahc\\Json\\": "src/"
34 | }
35 | },
36 | "notification-url": "https://packagist.org/downloads/",
37 | "license": [
38 | "MIT"
39 | ],
40 | "authors": [
41 | {
42 | "name": "Jitendra Adhikari",
43 | "email": "jiten.adhikary@gmail.com"
44 | }
45 | ],
46 | "description": "Lightweight JSON comment stripper library for PHP",
47 | "keywords": [
48 | "comment",
49 | "json",
50 | "strip-comment"
51 | ],
52 | "support": {
53 | "issues": "https://github.com/adhocore/php-json-comment/issues",
54 | "source": "https://github.com/adhocore/php-json-comment/tree/1.2.1"
55 | },
56 | "funding": [
57 | {
58 | "url": "https://paypal.me/ji10",
59 | "type": "custom"
60 | },
61 | {
62 | "url": "https://github.com/adhocore",
63 | "type": "github"
64 | }
65 | ],
66 | "time": "2022-10-02T11:22:07+00:00"
67 | },
68 | {
69 | "name": "brick/math",
70 | "version": "0.12.1",
71 | "source": {
72 | "type": "git",
73 | "url": "https://github.com/brick/math.git",
74 | "reference": "f510c0a40911935b77b86859eb5223d58d660df1"
75 | },
76 | "dist": {
77 | "type": "zip",
78 | "url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1",
79 | "reference": "f510c0a40911935b77b86859eb5223d58d660df1",
80 | "shasum": ""
81 | },
82 | "require": {
83 | "php": "^8.1"
84 | },
85 | "require-dev": {
86 | "php-coveralls/php-coveralls": "^2.2",
87 | "phpunit/phpunit": "^10.1",
88 | "vimeo/psalm": "5.16.0"
89 | },
90 | "type": "library",
91 | "autoload": {
92 | "psr-4": {
93 | "Brick\\Math\\": "src/"
94 | }
95 | },
96 | "notification-url": "https://packagist.org/downloads/",
97 | "license": [
98 | "MIT"
99 | ],
100 | "description": "Arbitrary-precision arithmetic library",
101 | "keywords": [
102 | "Arbitrary-precision",
103 | "BigInteger",
104 | "BigRational",
105 | "arithmetic",
106 | "bigdecimal",
107 | "bignum",
108 | "bignumber",
109 | "brick",
110 | "decimal",
111 | "integer",
112 | "math",
113 | "mathematics",
114 | "rational"
115 | ],
116 | "support": {
117 | "issues": "https://github.com/brick/math/issues",
118 | "source": "https://github.com/brick/math/tree/0.12.1"
119 | },
120 | "funding": [
121 | {
122 | "url": "https://github.com/BenMorel",
123 | "type": "github"
124 | }
125 | ],
126 | "time": "2023-11-29T23:19:16+00:00"
127 | },
128 | {
129 | "name": "muqsit/simple-packet-handler",
130 | "version": "0.1.4",
131 | "source": {
132 | "type": "git",
133 | "url": "https://github.com/Muqsit/SimplePacketHandler.git",
134 | "reference": "8121eca3f21cb9912c3ac8406a11f70cf105c905"
135 | },
136 | "dist": {
137 | "type": "zip",
138 | "url": "https://api.github.com/repos/Muqsit/SimplePacketHandler/zipball/8121eca3f21cb9912c3ac8406a11f70cf105c905",
139 | "reference": "8121eca3f21cb9912c3ac8406a11f70cf105c905",
140 | "shasum": ""
141 | },
142 | "require": {
143 | "pocketmine/pocketmine-mp": "^5.0.0"
144 | },
145 | "type": "library",
146 | "extra": {
147 | "virion": {
148 | "spec": "3.0",
149 | "namespace-root": "muqsit\\simplepackethandler"
150 | }
151 | },
152 | "autoload": {
153 | "classmap": [
154 | "src"
155 | ]
156 | },
157 | "notification-url": "https://packagist.org/downloads/",
158 | "license": [
159 | "GPL-3.0"
160 | ],
161 | "authors": [
162 | {
163 | "name": "Muqsit",
164 | "email": "hackhack05@gmail.com"
165 | }
166 | ],
167 | "description": "Handle specific data packets (virion for PMMP API 4.0.0)",
168 | "support": {
169 | "issues": "https://github.com/Muqsit/SimplePacketHandler/issues",
170 | "source": "https://github.com/Muqsit/SimplePacketHandler/tree/0.1.4"
171 | },
172 | "time": "2024-06-14T08:39:49+00:00"
173 | },
174 | {
175 | "name": "pocketmine/bedrock-block-upgrade-schema",
176 | "version": "4.2.0",
177 | "source": {
178 | "type": "git",
179 | "url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
180 | "reference": "8a327197b3b462fa282f40f76b070ffe585a25d2"
181 | },
182 | "dist": {
183 | "type": "zip",
184 | "url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/8a327197b3b462fa282f40f76b070ffe585a25d2",
185 | "reference": "8a327197b3b462fa282f40f76b070ffe585a25d2",
186 | "shasum": ""
187 | },
188 | "type": "library",
189 | "notification-url": "https://packagist.org/downloads/",
190 | "license": [
191 | "CC0-1.0"
192 | ],
193 | "description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves",
194 | "support": {
195 | "issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues",
196 | "source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/4.2.0"
197 | },
198 | "time": "2024-06-13T17:28:26+00:00"
199 | },
200 | {
201 | "name": "pocketmine/bedrock-data",
202 | "version": "2.11.0+bedrock-1.21.0",
203 | "source": {
204 | "type": "git",
205 | "url": "https://github.com/pmmp/BedrockData.git",
206 | "reference": "cae40bde98081b388c4d3ab59d45b8d1cf5d8761"
207 | },
208 | "dist": {
209 | "type": "zip",
210 | "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/cae40bde98081b388c4d3ab59d45b8d1cf5d8761",
211 | "reference": "cae40bde98081b388c4d3ab59d45b8d1cf5d8761",
212 | "shasum": ""
213 | },
214 | "type": "library",
215 | "notification-url": "https://packagist.org/downloads/",
216 | "license": [
217 | "CC0-1.0"
218 | ],
219 | "description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
220 | "support": {
221 | "issues": "https://github.com/pmmp/BedrockData/issues",
222 | "source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.0"
223 | },
224 | "time": "2024-06-13T17:17:55+00:00"
225 | },
226 | {
227 | "name": "pocketmine/bedrock-item-upgrade-schema",
228 | "version": "1.10.0",
229 | "source": {
230 | "type": "git",
231 | "url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
232 | "reference": "b4687afa19f91eacebd46c40d487f4cc515be504"
233 | },
234 | "dist": {
235 | "type": "zip",
236 | "url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/b4687afa19f91eacebd46c40d487f4cc515be504",
237 | "reference": "b4687afa19f91eacebd46c40d487f4cc515be504",
238 | "shasum": ""
239 | },
240 | "type": "library",
241 | "notification-url": "https://packagist.org/downloads/",
242 | "license": [
243 | "CC0-1.0"
244 | ],
245 | "description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves",
246 | "support": {
247 | "issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues",
248 | "source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.10.0"
249 | },
250 | "time": "2024-05-15T15:15:55+00:00"
251 | },
252 | {
253 | "name": "pocketmine/bedrock-protocol",
254 | "version": "31.0.0+bedrock-1.21.0",
255 | "source": {
256 | "type": "git",
257 | "url": "https://github.com/pmmp/BedrockProtocol.git",
258 | "reference": "972373b6b8068963649f0a95163424eb5b645e29"
259 | },
260 | "dist": {
261 | "type": "zip",
262 | "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/972373b6b8068963649f0a95163424eb5b645e29",
263 | "reference": "972373b6b8068963649f0a95163424eb5b645e29",
264 | "shasum": ""
265 | },
266 | "require": {
267 | "ext-json": "*",
268 | "php": "^8.1",
269 | "pocketmine/binaryutils": "^0.2.0",
270 | "pocketmine/color": "^0.2.0 || ^0.3.0",
271 | "pocketmine/math": "^0.3.0 || ^0.4.0 || ^1.0.0",
272 | "pocketmine/nbt": "^1.0.0",
273 | "ramsey/uuid": "^4.1"
274 | },
275 | "require-dev": {
276 | "phpstan/phpstan": "1.11.2",
277 | "phpstan/phpstan-phpunit": "^1.0.0",
278 | "phpstan/phpstan-strict-rules": "^1.0.0",
279 | "phpunit/phpunit": "^9.5 || ^10.0"
280 | },
281 | "type": "library",
282 | "autoload": {
283 | "psr-4": {
284 | "pocketmine\\network\\mcpe\\protocol\\": "src/"
285 | }
286 | },
287 | "notification-url": "https://packagist.org/downloads/",
288 | "license": [
289 | "LGPL-3.0"
290 | ],
291 | "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
292 | "support": {
293 | "issues": "https://github.com/pmmp/BedrockProtocol/issues",
294 | "source": "https://github.com/pmmp/BedrockProtocol/tree/31.0.0+bedrock-1.21.0"
295 | },
296 | "time": "2024-06-13T17:34:14+00:00"
297 | },
298 | {
299 | "name": "pocketmine/binaryutils",
300 | "version": "0.2.6",
301 | "source": {
302 | "type": "git",
303 | "url": "https://github.com/pmmp/BinaryUtils.git",
304 | "reference": "ccfc1899b859d45814ea3592e20ebec4cb731c84"
305 | },
306 | "dist": {
307 | "type": "zip",
308 | "url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/ccfc1899b859d45814ea3592e20ebec4cb731c84",
309 | "reference": "ccfc1899b859d45814ea3592e20ebec4cb731c84",
310 | "shasum": ""
311 | },
312 | "require": {
313 | "php": "^7.4 || ^8.0",
314 | "php-64bit": "*"
315 | },
316 | "require-dev": {
317 | "phpstan/extension-installer": "^1.0",
318 | "phpstan/phpstan": "~1.10.3",
319 | "phpstan/phpstan-phpunit": "^1.0",
320 | "phpstan/phpstan-strict-rules": "^1.0.0",
321 | "phpunit/phpunit": "^9.5 || ^10.0 || ^11.0"
322 | },
323 | "type": "library",
324 | "autoload": {
325 | "psr-4": {
326 | "pocketmine\\utils\\": "src/"
327 | }
328 | },
329 | "notification-url": "https://packagist.org/downloads/",
330 | "license": [
331 | "LGPL-3.0"
332 | ],
333 | "description": "Classes and methods for conveniently handling binary data",
334 | "support": {
335 | "issues": "https://github.com/pmmp/BinaryUtils/issues",
336 | "source": "https://github.com/pmmp/BinaryUtils/tree/0.2.6"
337 | },
338 | "time": "2024-03-04T15:04:17+00:00"
339 | },
340 | {
341 | "name": "pocketmine/callback-validator",
342 | "version": "1.0.3",
343 | "source": {
344 | "type": "git",
345 | "url": "https://github.com/pmmp/CallbackValidator.git",
346 | "reference": "64787469766bcaa7e5885242e85c23c25e8c55a2"
347 | },
348 | "dist": {
349 | "type": "zip",
350 | "url": "https://api.github.com/repos/pmmp/CallbackValidator/zipball/64787469766bcaa7e5885242e85c23c25e8c55a2",
351 | "reference": "64787469766bcaa7e5885242e85c23c25e8c55a2",
352 | "shasum": ""
353 | },
354 | "require": {
355 | "ext-reflection": "*",
356 | "php": "^7.1 || ^8.0"
357 | },
358 | "replace": {
359 | "daverandom/callback-validator": "*"
360 | },
361 | "require-dev": {
362 | "phpstan/extension-installer": "^1.0",
363 | "phpstan/phpstan": "0.12.59",
364 | "phpstan/phpstan-strict-rules": "^0.12.4",
365 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
366 | },
367 | "type": "library",
368 | "autoload": {
369 | "psr-4": {
370 | "DaveRandom\\CallbackValidator\\": "src/"
371 | }
372 | },
373 | "notification-url": "https://packagist.org/downloads/",
374 | "license": [
375 | "MIT"
376 | ],
377 | "authors": [
378 | {
379 | "name": "Chris Wright",
380 | "email": "cw@daverandom.com"
381 | }
382 | ],
383 | "description": "Fork of daverandom/callback-validator - Tools for validating callback signatures",
384 | "support": {
385 | "issues": "https://github.com/pmmp/CallbackValidator/issues",
386 | "source": "https://github.com/pmmp/CallbackValidator/tree/1.0.3"
387 | },
388 | "time": "2020-12-11T01:45:37+00:00"
389 | },
390 | {
391 | "name": "pocketmine/color",
392 | "version": "0.3.1",
393 | "source": {
394 | "type": "git",
395 | "url": "https://github.com/pmmp/Color.git",
396 | "reference": "a0421f1e9e0b0c619300fb92d593283378f6a5e1"
397 | },
398 | "dist": {
399 | "type": "zip",
400 | "url": "https://api.github.com/repos/pmmp/Color/zipball/a0421f1e9e0b0c619300fb92d593283378f6a5e1",
401 | "reference": "a0421f1e9e0b0c619300fb92d593283378f6a5e1",
402 | "shasum": ""
403 | },
404 | "require": {
405 | "php": "^8.0"
406 | },
407 | "require-dev": {
408 | "phpstan/phpstan": "1.10.3",
409 | "phpstan/phpstan-strict-rules": "^1.2.0"
410 | },
411 | "type": "library",
412 | "autoload": {
413 | "psr-4": {
414 | "pocketmine\\color\\": "src/"
415 | }
416 | },
417 | "notification-url": "https://packagist.org/downloads/",
418 | "license": [
419 | "LGPL-3.0"
420 | ],
421 | "description": "Color handling library used by PocketMine-MP and related projects",
422 | "support": {
423 | "issues": "https://github.com/pmmp/Color/issues",
424 | "source": "https://github.com/pmmp/Color/tree/0.3.1"
425 | },
426 | "time": "2023-04-10T11:38:05+00:00"
427 | },
428 | {
429 | "name": "pocketmine/errorhandler",
430 | "version": "0.7.0",
431 | "source": {
432 | "type": "git",
433 | "url": "https://github.com/pmmp/ErrorHandler.git",
434 | "reference": "cae94884368a74ece5294b9ff7fef18732dcd921"
435 | },
436 | "dist": {
437 | "type": "zip",
438 | "url": "https://api.github.com/repos/pmmp/ErrorHandler/zipball/cae94884368a74ece5294b9ff7fef18732dcd921",
439 | "reference": "cae94884368a74ece5294b9ff7fef18732dcd921",
440 | "shasum": ""
441 | },
442 | "require": {
443 | "php": "^8.0"
444 | },
445 | "require-dev": {
446 | "phpstan/phpstan": "~1.10.3",
447 | "phpstan/phpstan-strict-rules": "^1.0",
448 | "phpunit/phpunit": "^9.5 || ^10.0 || ^11.0"
449 | },
450 | "type": "library",
451 | "autoload": {
452 | "psr-4": {
453 | "pocketmine\\errorhandler\\": "src/"
454 | }
455 | },
456 | "notification-url": "https://packagist.org/downloads/",
457 | "license": [
458 | "LGPL-3.0"
459 | ],
460 | "description": "Utilities to handle nasty PHP E_* errors in a usable way",
461 | "support": {
462 | "issues": "https://github.com/pmmp/ErrorHandler/issues",
463 | "source": "https://github.com/pmmp/ErrorHandler/tree/0.7.0"
464 | },
465 | "time": "2024-04-02T18:29:54+00:00"
466 | },
467 | {
468 | "name": "pocketmine/locale-data",
469 | "version": "2.19.6",
470 | "source": {
471 | "type": "git",
472 | "url": "https://github.com/pmmp/Language.git",
473 | "reference": "93e473e20e7f4515ecf45c5ef0f9155b9247a86e"
474 | },
475 | "dist": {
476 | "type": "zip",
477 | "url": "https://api.github.com/repos/pmmp/Language/zipball/93e473e20e7f4515ecf45c5ef0f9155b9247a86e",
478 | "reference": "93e473e20e7f4515ecf45c5ef0f9155b9247a86e",
479 | "shasum": ""
480 | },
481 | "type": "library",
482 | "notification-url": "https://packagist.org/downloads/",
483 | "description": "Language resources used by PocketMine-MP",
484 | "support": {
485 | "issues": "https://github.com/pmmp/Language/issues",
486 | "source": "https://github.com/pmmp/Language/tree/2.19.6"
487 | },
488 | "time": "2023-08-08T16:53:23+00:00"
489 | },
490 | {
491 | "name": "pocketmine/log",
492 | "version": "0.4.0",
493 | "source": {
494 | "type": "git",
495 | "url": "https://github.com/pmmp/Log.git",
496 | "reference": "e6c912c0f9055c81d23108ec2d179b96f404c043"
497 | },
498 | "dist": {
499 | "type": "zip",
500 | "url": "https://api.github.com/repos/pmmp/Log/zipball/e6c912c0f9055c81d23108ec2d179b96f404c043",
501 | "reference": "e6c912c0f9055c81d23108ec2d179b96f404c043",
502 | "shasum": ""
503 | },
504 | "require": {
505 | "php": "^7.4 || ^8.0"
506 | },
507 | "conflict": {
508 | "pocketmine/spl": "<0.4"
509 | },
510 | "require-dev": {
511 | "phpstan/phpstan": "0.12.88",
512 | "phpstan/phpstan-strict-rules": "^0.12.2"
513 | },
514 | "type": "library",
515 | "autoload": {
516 | "classmap": [
517 | "./src"
518 | ]
519 | },
520 | "notification-url": "https://packagist.org/downloads/",
521 | "license": [
522 | "LGPL-3.0"
523 | ],
524 | "description": "Logging components used by PocketMine-MP and related projects",
525 | "support": {
526 | "issues": "https://github.com/pmmp/Log/issues",
527 | "source": "https://github.com/pmmp/Log/tree/0.4.0"
528 | },
529 | "time": "2021-06-18T19:08:09+00:00"
530 | },
531 | {
532 | "name": "pocketmine/math",
533 | "version": "1.0.0",
534 | "source": {
535 | "type": "git",
536 | "url": "https://github.com/pmmp/Math.git",
537 | "reference": "dc132d93595b32e9f210d78b3c8d43c662a5edbf"
538 | },
539 | "dist": {
540 | "type": "zip",
541 | "url": "https://api.github.com/repos/pmmp/Math/zipball/dc132d93595b32e9f210d78b3c8d43c662a5edbf",
542 | "reference": "dc132d93595b32e9f210d78b3c8d43c662a5edbf",
543 | "shasum": ""
544 | },
545 | "require": {
546 | "php": "^8.0",
547 | "php-64bit": "*"
548 | },
549 | "require-dev": {
550 | "phpstan/extension-installer": "^1.0",
551 | "phpstan/phpstan": "~1.10.3",
552 | "phpstan/phpstan-strict-rules": "^1.0",
553 | "phpunit/phpunit": "^8.5 || ^9.5"
554 | },
555 | "type": "library",
556 | "autoload": {
557 | "psr-4": {
558 | "pocketmine\\math\\": "src/"
559 | }
560 | },
561 | "notification-url": "https://packagist.org/downloads/",
562 | "license": [
563 | "LGPL-3.0"
564 | ],
565 | "description": "PHP library containing math related code used in PocketMine-MP",
566 | "support": {
567 | "issues": "https://github.com/pmmp/Math/issues",
568 | "source": "https://github.com/pmmp/Math/tree/1.0.0"
569 | },
570 | "time": "2023-08-03T12:56:33+00:00"
571 | },
572 | {
573 | "name": "pocketmine/nbt",
574 | "version": "1.0.0",
575 | "source": {
576 | "type": "git",
577 | "url": "https://github.com/pmmp/NBT.git",
578 | "reference": "20540271cb59e04672cb163dca73366f207974f1"
579 | },
580 | "dist": {
581 | "type": "zip",
582 | "url": "https://api.github.com/repos/pmmp/NBT/zipball/20540271cb59e04672cb163dca73366f207974f1",
583 | "reference": "20540271cb59e04672cb163dca73366f207974f1",
584 | "shasum": ""
585 | },
586 | "require": {
587 | "php": "^7.4 || ^8.0",
588 | "php-64bit": "*",
589 | "pocketmine/binaryutils": "^0.2.0"
590 | },
591 | "require-dev": {
592 | "phpstan/extension-installer": "^1.0",
593 | "phpstan/phpstan": "1.10.25",
594 | "phpstan/phpstan-strict-rules": "^1.0",
595 | "phpunit/phpunit": "^9.5"
596 | },
597 | "type": "library",
598 | "autoload": {
599 | "psr-4": {
600 | "pocketmine\\nbt\\": "src/"
601 | }
602 | },
603 | "notification-url": "https://packagist.org/downloads/",
604 | "license": [
605 | "LGPL-3.0"
606 | ],
607 | "description": "PHP library for working with Named Binary Tags",
608 | "support": {
609 | "issues": "https://github.com/pmmp/NBT/issues",
610 | "source": "https://github.com/pmmp/NBT/tree/1.0.0"
611 | },
612 | "time": "2023-07-14T13:01:49+00:00"
613 | },
614 | {
615 | "name": "pocketmine/netresearch-jsonmapper",
616 | "version": "v4.4.999",
617 | "source": {
618 | "type": "git",
619 | "url": "https://github.com/pmmp/netresearch-jsonmapper.git",
620 | "reference": "9a6610033d56e358e86a3e4fd5f87063c7318833"
621 | },
622 | "dist": {
623 | "type": "zip",
624 | "url": "https://api.github.com/repos/pmmp/netresearch-jsonmapper/zipball/9a6610033d56e358e86a3e4fd5f87063c7318833",
625 | "reference": "9a6610033d56e358e86a3e4fd5f87063c7318833",
626 | "shasum": ""
627 | },
628 | "require": {
629 | "ext-json": "*",
630 | "ext-pcre": "*",
631 | "ext-reflection": "*",
632 | "ext-spl": "*",
633 | "php": ">=7.1"
634 | },
635 | "replace": {
636 | "netresearch/jsonmapper": "~4.2.0"
637 | },
638 | "require-dev": {
639 | "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0",
640 | "squizlabs/php_codesniffer": "~3.5"
641 | },
642 | "type": "library",
643 | "autoload": {
644 | "psr-0": {
645 | "JsonMapper": "src/"
646 | }
647 | },
648 | "notification-url": "https://packagist.org/downloads/",
649 | "license": [
650 | "OSL-3.0"
651 | ],
652 | "authors": [
653 | {
654 | "name": "Christian Weiske",
655 | "email": "cweiske@cweiske.de",
656 | "homepage": "http://github.com/cweiske/jsonmapper/",
657 | "role": "Developer"
658 | }
659 | ],
660 | "description": "Fork of netresearch/jsonmapper with security fixes needed by pocketmine/pocketmine-mp",
661 | "support": {
662 | "email": "cweiske@cweiske.de",
663 | "issues": "https://github.com/cweiske/jsonmapper/issues",
664 | "source": "https://github.com/pmmp/netresearch-jsonmapper/tree/v4.4.999"
665 | },
666 | "time": "2024-02-23T13:17:01+00:00"
667 | },
668 | {
669 | "name": "pocketmine/pocketmine-mp",
670 | "version": "5.16.0",
671 | "source": {
672 | "type": "git",
673 | "url": "https://github.com/pmmp/PocketMine-MP.git",
674 | "reference": "22a1549998ef0e4668ed48838900ad84258fe04a"
675 | },
676 | "dist": {
677 | "type": "zip",
678 | "url": "https://api.github.com/repos/pmmp/PocketMine-MP/zipball/22a1549998ef0e4668ed48838900ad84258fe04a",
679 | "reference": "22a1549998ef0e4668ed48838900ad84258fe04a",
680 | "shasum": ""
681 | },
682 | "require": {
683 | "adhocore/json-comment": "~1.2.0",
684 | "composer-runtime-api": "^2.0",
685 | "ext-chunkutils2": "^0.3.1",
686 | "ext-crypto": "^0.3.1",
687 | "ext-ctype": "*",
688 | "ext-curl": "*",
689 | "ext-date": "*",
690 | "ext-gmp": "*",
691 | "ext-hash": "*",
692 | "ext-igbinary": "^3.0.1",
693 | "ext-json": "*",
694 | "ext-leveldb": "^0.2.1 || ^0.3.0",
695 | "ext-mbstring": "*",
696 | "ext-morton": "^0.1.0",
697 | "ext-openssl": "*",
698 | "ext-pcre": "*",
699 | "ext-phar": "*",
700 | "ext-pmmpthread": "^6.1.0",
701 | "ext-reflection": "*",
702 | "ext-simplexml": "*",
703 | "ext-sockets": "*",
704 | "ext-spl": "*",
705 | "ext-yaml": ">=2.0.0",
706 | "ext-zip": "*",
707 | "ext-zlib": ">=1.2.11",
708 | "php": "^8.1",
709 | "php-64bit": "*",
710 | "pocketmine/bedrock-block-upgrade-schema": "~4.2.0+bedrock-1.21.0",
711 | "pocketmine/bedrock-data": "~2.11.0+bedrock-1.21.0",
712 | "pocketmine/bedrock-item-upgrade-schema": "~1.10.0+bedrock-1.21.0",
713 | "pocketmine/bedrock-protocol": "~31.0.0+bedrock-1.21.0",
714 | "pocketmine/binaryutils": "^0.2.1",
715 | "pocketmine/callback-validator": "^1.0.2",
716 | "pocketmine/color": "^0.3.0",
717 | "pocketmine/errorhandler": "^0.7.0",
718 | "pocketmine/locale-data": "~2.19.0",
719 | "pocketmine/log": "^0.4.0",
720 | "pocketmine/math": "~1.0.0",
721 | "pocketmine/nbt": "~1.0.0",
722 | "pocketmine/netresearch-jsonmapper": "~v4.4.999",
723 | "pocketmine/raklib": "~1.1.0",
724 | "pocketmine/raklib-ipc": "~1.0.0",
725 | "pocketmine/snooze": "^0.5.0",
726 | "ramsey/uuid": "~4.7.0",
727 | "symfony/filesystem": "~6.4.0"
728 | },
729 | "require-dev": {
730 | "phpstan/phpstan": "1.11.2",
731 | "phpstan/phpstan-phpunit": "^1.1.0",
732 | "phpstan/phpstan-strict-rules": "^1.2.0",
733 | "phpunit/phpunit": "~10.3.0 || ~10.2.0 || ~10.1.0"
734 | },
735 | "type": "project",
736 | "autoload": {
737 | "files": [
738 | "src/CoreConstants.php"
739 | ],
740 | "psr-4": {
741 | "pocketmine\\": "src/"
742 | }
743 | },
744 | "notification-url": "https://packagist.org/downloads/",
745 | "license": [
746 | "LGPL-3.0"
747 | ],
748 | "description": "A server software for Minecraft: Bedrock Edition written in PHP",
749 | "homepage": "https://pmmp.io",
750 | "support": {
751 | "issues": "https://github.com/pmmp/PocketMine-MP/issues",
752 | "source": "https://github.com/pmmp/PocketMine-MP/tree/5.16.0"
753 | },
754 | "funding": [
755 | {
756 | "url": "https://github.com/pmmp/PocketMine-MP#donate",
757 | "type": "custom"
758 | },
759 | {
760 | "url": "https://www.patreon.com/pocketminemp",
761 | "type": "patreon"
762 | }
763 | ],
764 | "time": "2024-06-13T17:55:18+00:00"
765 | },
766 | {
767 | "name": "pocketmine/raklib",
768 | "version": "1.1.1",
769 | "source": {
770 | "type": "git",
771 | "url": "https://github.com/pmmp/RakLib.git",
772 | "reference": "be2783be516bf6e2872ff5c81fb9048596617b97"
773 | },
774 | "dist": {
775 | "type": "zip",
776 | "url": "https://api.github.com/repos/pmmp/RakLib/zipball/be2783be516bf6e2872ff5c81fb9048596617b97",
777 | "reference": "be2783be516bf6e2872ff5c81fb9048596617b97",
778 | "shasum": ""
779 | },
780 | "require": {
781 | "ext-sockets": "*",
782 | "php": "^8.1",
783 | "php-64bit": "*",
784 | "php-ipv6": "*",
785 | "pocketmine/binaryutils": "^0.2.0",
786 | "pocketmine/log": "^0.3.0 || ^0.4.0"
787 | },
788 | "require-dev": {
789 | "phpstan/phpstan": "1.10.1",
790 | "phpstan/phpstan-strict-rules": "^1.0"
791 | },
792 | "type": "library",
793 | "autoload": {
794 | "psr-4": {
795 | "raklib\\": "src/"
796 | }
797 | },
798 | "notification-url": "https://packagist.org/downloads/",
799 | "license": [
800 | "GPL-3.0"
801 | ],
802 | "description": "A RakNet server implementation written in PHP",
803 | "support": {
804 | "issues": "https://github.com/pmmp/RakLib/issues",
805 | "source": "https://github.com/pmmp/RakLib/tree/1.1.1"
806 | },
807 | "time": "2024-03-04T14:02:14+00:00"
808 | },
809 | {
810 | "name": "pocketmine/raklib-ipc",
811 | "version": "1.0.1",
812 | "source": {
813 | "type": "git",
814 | "url": "https://github.com/pmmp/RakLibIpc.git",
815 | "reference": "ce632ef2c6743e71eddb5dc329c49af6555f90bc"
816 | },
817 | "dist": {
818 | "type": "zip",
819 | "url": "https://api.github.com/repos/pmmp/RakLibIpc/zipball/ce632ef2c6743e71eddb5dc329c49af6555f90bc",
820 | "reference": "ce632ef2c6743e71eddb5dc329c49af6555f90bc",
821 | "shasum": ""
822 | },
823 | "require": {
824 | "php": "^8.0",
825 | "php-64bit": "*",
826 | "pocketmine/binaryutils": "^0.2.0",
827 | "pocketmine/raklib": "^0.15.0 || ^1.0.0"
828 | },
829 | "require-dev": {
830 | "phpstan/phpstan": "1.10.1",
831 | "phpstan/phpstan-strict-rules": "^1.0.0"
832 | },
833 | "type": "library",
834 | "autoload": {
835 | "psr-4": {
836 | "raklib\\server\\ipc\\": "src/"
837 | }
838 | },
839 | "notification-url": "https://packagist.org/downloads/",
840 | "license": [
841 | "GPL-3.0"
842 | ],
843 | "description": "Channel-based protocols for inter-thread/inter-process communication with RakLib",
844 | "support": {
845 | "issues": "https://github.com/pmmp/RakLibIpc/issues",
846 | "source": "https://github.com/pmmp/RakLibIpc/tree/1.0.1"
847 | },
848 | "time": "2024-03-01T15:55:05+00:00"
849 | },
850 | {
851 | "name": "pocketmine/snooze",
852 | "version": "0.5.0",
853 | "source": {
854 | "type": "git",
855 | "url": "https://github.com/pmmp/Snooze.git",
856 | "reference": "a86d9ee60ce44755d166d3c7ba4b8b8be8360915"
857 | },
858 | "dist": {
859 | "type": "zip",
860 | "url": "https://api.github.com/repos/pmmp/Snooze/zipball/a86d9ee60ce44755d166d3c7ba4b8b8be8360915",
861 | "reference": "a86d9ee60ce44755d166d3c7ba4b8b8be8360915",
862 | "shasum": ""
863 | },
864 | "require": {
865 | "ext-pmmpthread": "^6.0",
866 | "php-64bit": "^8.1"
867 | },
868 | "require-dev": {
869 | "phpstan/extension-installer": "^1.0",
870 | "phpstan/phpstan": "1.10.3",
871 | "phpstan/phpstan-strict-rules": "^1.0"
872 | },
873 | "type": "library",
874 | "autoload": {
875 | "psr-4": {
876 | "pocketmine\\snooze\\": "src/"
877 | }
878 | },
879 | "notification-url": "https://packagist.org/downloads/",
880 | "license": [
881 | "LGPL-3.0"
882 | ],
883 | "description": "Thread notification management library for code using the pthreads extension",
884 | "support": {
885 | "issues": "https://github.com/pmmp/Snooze/issues",
886 | "source": "https://github.com/pmmp/Snooze/tree/0.5.0"
887 | },
888 | "time": "2023-05-22T23:43:01+00:00"
889 | },
890 | {
891 | "name": "ramsey/collection",
892 | "version": "2.0.0",
893 | "source": {
894 | "type": "git",
895 | "url": "https://github.com/ramsey/collection.git",
896 | "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5"
897 | },
898 | "dist": {
899 | "type": "zip",
900 | "url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
901 | "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
902 | "shasum": ""
903 | },
904 | "require": {
905 | "php": "^8.1"
906 | },
907 | "require-dev": {
908 | "captainhook/plugin-composer": "^5.3",
909 | "ergebnis/composer-normalize": "^2.28.3",
910 | "fakerphp/faker": "^1.21",
911 | "hamcrest/hamcrest-php": "^2.0",
912 | "jangregor/phpstan-prophecy": "^1.0",
913 | "mockery/mockery": "^1.5",
914 | "php-parallel-lint/php-console-highlighter": "^1.0",
915 | "php-parallel-lint/php-parallel-lint": "^1.3",
916 | "phpcsstandards/phpcsutils": "^1.0.0-rc1",
917 | "phpspec/prophecy-phpunit": "^2.0",
918 | "phpstan/extension-installer": "^1.2",
919 | "phpstan/phpstan": "^1.9",
920 | "phpstan/phpstan-mockery": "^1.1",
921 | "phpstan/phpstan-phpunit": "^1.3",
922 | "phpunit/phpunit": "^9.5",
923 | "psalm/plugin-mockery": "^1.1",
924 | "psalm/plugin-phpunit": "^0.18.4",
925 | "ramsey/coding-standard": "^2.0.3",
926 | "ramsey/conventional-commits": "^1.3",
927 | "vimeo/psalm": "^5.4"
928 | },
929 | "type": "library",
930 | "extra": {
931 | "captainhook": {
932 | "force-install": true
933 | },
934 | "ramsey/conventional-commits": {
935 | "configFile": "conventional-commits.json"
936 | }
937 | },
938 | "autoload": {
939 | "psr-4": {
940 | "Ramsey\\Collection\\": "src/"
941 | }
942 | },
943 | "notification-url": "https://packagist.org/downloads/",
944 | "license": [
945 | "MIT"
946 | ],
947 | "authors": [
948 | {
949 | "name": "Ben Ramsey",
950 | "email": "ben@benramsey.com",
951 | "homepage": "https://benramsey.com"
952 | }
953 | ],
954 | "description": "A PHP library for representing and manipulating collections.",
955 | "keywords": [
956 | "array",
957 | "collection",
958 | "hash",
959 | "map",
960 | "queue",
961 | "set"
962 | ],
963 | "support": {
964 | "issues": "https://github.com/ramsey/collection/issues",
965 | "source": "https://github.com/ramsey/collection/tree/2.0.0"
966 | },
967 | "funding": [
968 | {
969 | "url": "https://github.com/ramsey",
970 | "type": "github"
971 | },
972 | {
973 | "url": "https://tidelift.com/funding/github/packagist/ramsey/collection",
974 | "type": "tidelift"
975 | }
976 | ],
977 | "time": "2022-12-31T21:50:55+00:00"
978 | },
979 | {
980 | "name": "ramsey/uuid",
981 | "version": "4.7.6",
982 | "source": {
983 | "type": "git",
984 | "url": "https://github.com/ramsey/uuid.git",
985 | "reference": "91039bc1faa45ba123c4328958e620d382ec7088"
986 | },
987 | "dist": {
988 | "type": "zip",
989 | "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088",
990 | "reference": "91039bc1faa45ba123c4328958e620d382ec7088",
991 | "shasum": ""
992 | },
993 | "require": {
994 | "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12",
995 | "ext-json": "*",
996 | "php": "^8.0",
997 | "ramsey/collection": "^1.2 || ^2.0"
998 | },
999 | "replace": {
1000 | "rhumsaa/uuid": "self.version"
1001 | },
1002 | "require-dev": {
1003 | "captainhook/captainhook": "^5.10",
1004 | "captainhook/plugin-composer": "^5.3",
1005 | "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
1006 | "doctrine/annotations": "^1.8",
1007 | "ergebnis/composer-normalize": "^2.15",
1008 | "mockery/mockery": "^1.3",
1009 | "paragonie/random-lib": "^2",
1010 | "php-mock/php-mock": "^2.2",
1011 | "php-mock/php-mock-mockery": "^1.3",
1012 | "php-parallel-lint/php-parallel-lint": "^1.1",
1013 | "phpbench/phpbench": "^1.0",
1014 | "phpstan/extension-installer": "^1.1",
1015 | "phpstan/phpstan": "^1.8",
1016 | "phpstan/phpstan-mockery": "^1.1",
1017 | "phpstan/phpstan-phpunit": "^1.1",
1018 | "phpunit/phpunit": "^8.5 || ^9",
1019 | "ramsey/composer-repl": "^1.4",
1020 | "slevomat/coding-standard": "^8.4",
1021 | "squizlabs/php_codesniffer": "^3.5",
1022 | "vimeo/psalm": "^4.9"
1023 | },
1024 | "suggest": {
1025 | "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
1026 | "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.",
1027 | "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.",
1028 | "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
1029 | "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
1030 | },
1031 | "type": "library",
1032 | "extra": {
1033 | "captainhook": {
1034 | "force-install": true
1035 | }
1036 | },
1037 | "autoload": {
1038 | "files": [
1039 | "src/functions.php"
1040 | ],
1041 | "psr-4": {
1042 | "Ramsey\\Uuid\\": "src/"
1043 | }
1044 | },
1045 | "notification-url": "https://packagist.org/downloads/",
1046 | "license": [
1047 | "MIT"
1048 | ],
1049 | "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).",
1050 | "keywords": [
1051 | "guid",
1052 | "identifier",
1053 | "uuid"
1054 | ],
1055 | "support": {
1056 | "issues": "https://github.com/ramsey/uuid/issues",
1057 | "source": "https://github.com/ramsey/uuid/tree/4.7.6"
1058 | },
1059 | "funding": [
1060 | {
1061 | "url": "https://github.com/ramsey",
1062 | "type": "github"
1063 | },
1064 | {
1065 | "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
1066 | "type": "tidelift"
1067 | }
1068 | ],
1069 | "time": "2024-04-27T21:32:50+00:00"
1070 | },
1071 | {
1072 | "name": "symfony/filesystem",
1073 | "version": "v6.4.8",
1074 | "source": {
1075 | "type": "git",
1076 | "url": "https://github.com/symfony/filesystem.git",
1077 | "reference": "4d37529150e7081c51b3c5d5718c55a04a9503f3"
1078 | },
1079 | "dist": {
1080 | "type": "zip",
1081 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/4d37529150e7081c51b3c5d5718c55a04a9503f3",
1082 | "reference": "4d37529150e7081c51b3c5d5718c55a04a9503f3",
1083 | "shasum": ""
1084 | },
1085 | "require": {
1086 | "php": ">=8.1",
1087 | "symfony/polyfill-ctype": "~1.8",
1088 | "symfony/polyfill-mbstring": "~1.8"
1089 | },
1090 | "require-dev": {
1091 | "symfony/process": "^5.4|^6.4|^7.0"
1092 | },
1093 | "type": "library",
1094 | "autoload": {
1095 | "psr-4": {
1096 | "Symfony\\Component\\Filesystem\\": ""
1097 | },
1098 | "exclude-from-classmap": [
1099 | "/Tests/"
1100 | ]
1101 | },
1102 | "notification-url": "https://packagist.org/downloads/",
1103 | "license": [
1104 | "MIT"
1105 | ],
1106 | "authors": [
1107 | {
1108 | "name": "Fabien Potencier",
1109 | "email": "fabien@symfony.com"
1110 | },
1111 | {
1112 | "name": "Symfony Community",
1113 | "homepage": "https://symfony.com/contributors"
1114 | }
1115 | ],
1116 | "description": "Provides basic utilities for the filesystem",
1117 | "homepage": "https://symfony.com",
1118 | "support": {
1119 | "source": "https://github.com/symfony/filesystem/tree/v6.4.8"
1120 | },
1121 | "funding": [
1122 | {
1123 | "url": "https://symfony.com/sponsor",
1124 | "type": "custom"
1125 | },
1126 | {
1127 | "url": "https://github.com/fabpot",
1128 | "type": "github"
1129 | },
1130 | {
1131 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1132 | "type": "tidelift"
1133 | }
1134 | ],
1135 | "time": "2024-05-31T14:49:08+00:00"
1136 | },
1137 | {
1138 | "name": "symfony/polyfill-ctype",
1139 | "version": "v1.29.0",
1140 | "source": {
1141 | "type": "git",
1142 | "url": "https://github.com/symfony/polyfill-ctype.git",
1143 | "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
1144 | },
1145 | "dist": {
1146 | "type": "zip",
1147 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
1148 | "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
1149 | "shasum": ""
1150 | },
1151 | "require": {
1152 | "php": ">=7.1"
1153 | },
1154 | "provide": {
1155 | "ext-ctype": "*"
1156 | },
1157 | "suggest": {
1158 | "ext-ctype": "For best performance"
1159 | },
1160 | "type": "library",
1161 | "extra": {
1162 | "thanks": {
1163 | "name": "symfony/polyfill",
1164 | "url": "https://github.com/symfony/polyfill"
1165 | }
1166 | },
1167 | "autoload": {
1168 | "files": [
1169 | "bootstrap.php"
1170 | ],
1171 | "psr-4": {
1172 | "Symfony\\Polyfill\\Ctype\\": ""
1173 | }
1174 | },
1175 | "notification-url": "https://packagist.org/downloads/",
1176 | "license": [
1177 | "MIT"
1178 | ],
1179 | "authors": [
1180 | {
1181 | "name": "Gert de Pagter",
1182 | "email": "BackEndTea@gmail.com"
1183 | },
1184 | {
1185 | "name": "Symfony Community",
1186 | "homepage": "https://symfony.com/contributors"
1187 | }
1188 | ],
1189 | "description": "Symfony polyfill for ctype functions",
1190 | "homepage": "https://symfony.com",
1191 | "keywords": [
1192 | "compatibility",
1193 | "ctype",
1194 | "polyfill",
1195 | "portable"
1196 | ],
1197 | "support": {
1198 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
1199 | },
1200 | "funding": [
1201 | {
1202 | "url": "https://symfony.com/sponsor",
1203 | "type": "custom"
1204 | },
1205 | {
1206 | "url": "https://github.com/fabpot",
1207 | "type": "github"
1208 | },
1209 | {
1210 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1211 | "type": "tidelift"
1212 | }
1213 | ],
1214 | "time": "2024-01-29T20:11:03+00:00"
1215 | },
1216 | {
1217 | "name": "symfony/polyfill-mbstring",
1218 | "version": "v1.29.0",
1219 | "source": {
1220 | "type": "git",
1221 | "url": "https://github.com/symfony/polyfill-mbstring.git",
1222 | "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
1223 | },
1224 | "dist": {
1225 | "type": "zip",
1226 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
1227 | "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
1228 | "shasum": ""
1229 | },
1230 | "require": {
1231 | "php": ">=7.1"
1232 | },
1233 | "provide": {
1234 | "ext-mbstring": "*"
1235 | },
1236 | "suggest": {
1237 | "ext-mbstring": "For best performance"
1238 | },
1239 | "type": "library",
1240 | "extra": {
1241 | "thanks": {
1242 | "name": "symfony/polyfill",
1243 | "url": "https://github.com/symfony/polyfill"
1244 | }
1245 | },
1246 | "autoload": {
1247 | "files": [
1248 | "bootstrap.php"
1249 | ],
1250 | "psr-4": {
1251 | "Symfony\\Polyfill\\Mbstring\\": ""
1252 | }
1253 | },
1254 | "notification-url": "https://packagist.org/downloads/",
1255 | "license": [
1256 | "MIT"
1257 | ],
1258 | "authors": [
1259 | {
1260 | "name": "Nicolas Grekas",
1261 | "email": "p@tchwork.com"
1262 | },
1263 | {
1264 | "name": "Symfony Community",
1265 | "homepage": "https://symfony.com/contributors"
1266 | }
1267 | ],
1268 | "description": "Symfony polyfill for the Mbstring extension",
1269 | "homepage": "https://symfony.com",
1270 | "keywords": [
1271 | "compatibility",
1272 | "mbstring",
1273 | "polyfill",
1274 | "portable",
1275 | "shim"
1276 | ],
1277 | "support": {
1278 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
1279 | },
1280 | "funding": [
1281 | {
1282 | "url": "https://symfony.com/sponsor",
1283 | "type": "custom"
1284 | },
1285 | {
1286 | "url": "https://github.com/fabpot",
1287 | "type": "github"
1288 | },
1289 | {
1290 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1291 | "type": "tidelift"
1292 | }
1293 | ],
1294 | "time": "2024-01-29T20:11:03+00:00"
1295 | }
1296 | ],
1297 | "packages-dev": [],
1298 | "aliases": [],
1299 | "minimum-stability": "stable",
1300 | "stability-flags": [],
1301 | "prefer-stable": false,
1302 | "prefer-lowest": false,
1303 | "platform": [],
1304 | "platform-dev": [],
1305 | "plugin-api-version": "2.6.0"
1306 | }
1307 |
--------------------------------------------------------------------------------
/docs/MIGRATION.md:
--------------------------------------------------------------------------------
1 | ### Migration for versions 1.x.x -> 2.x.x
2 |
3 | As the implementation of the `PluginIdentifiableCommand` is now being enforced by Poggit-CI, we needed to comply and include it with the virion itself (being a base framework, to reduce boilerplate code)
4 |
5 | To migrate your plugins, if you have overridden the constructor (`__construct()`) of any class that's extending `BaseCommand`, you will need to update the function's signature as it now includes the `Plugin` context before anything else.
6 |
7 | ```php
8 | public function __construct(
9 | Plugin $plugin,
10 | string $name,
11 | string $description = "",
12 | array $aliases = []
13 | )
14 | ```
15 |
16 | You will need to change the parent call (`parent::__construct($name, $description, $aliases)`) to include the plugin instance:
17 | ```php
18 | parent::__construct($plugin, $name, $description, null, $aliases);
19 | ```
20 |
21 | Along with these changes, you will need to include the `Plugin` context with your class' constructor.
22 |
23 | Because of those signature differences, you will need to update the part where your plugin registers a command that uses Commando. As an example:
24 | ```php
25 | // Example code from 1.x.x README.md
26 | $this->getServer()->getCommandMap()->register("myplugin", new MyCommand("greet", "Make the server greet you!"));
27 | // Will have to be migrated to:
28 | $this->getServer()->getCommandMap()->register("myplugin", new MyCommand($this, "greet", "Make the server greet you!"));
29 | ```
30 |
31 | Assuming you're calling `CommandMap->register()` directly from the plugin itself.
--------------------------------------------------------------------------------
/src/CortexPE/Commando/BaseCommand.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando;
31 |
32 | use CortexPE\Commando\constraint\BaseConstraint;
33 | use CortexPE\Commando\exception\InvalidErrorCode;
34 | use CortexPE\Commando\traits\ArgumentableTrait;
35 | use CortexPE\Commando\traits\IArgumentable;
36 | use InvalidArgumentException;
37 | use pocketmine\command\Command;
38 | use pocketmine\command\CommandSender;
39 | use pocketmine\lang\Translatable;
40 | use pocketmine\plugin\Plugin;
41 | use pocketmine\plugin\PluginOwned;
42 | use pocketmine\utils\TextFormat;
43 | use function array_shift;
44 | use function array_unique;
45 | use function array_unshift;
46 | use function count;
47 | use function dechex;
48 | use function str_replace;
49 |
50 | abstract class BaseCommand extends Command implements IArgumentable, IRunnable, PluginOwned {
51 | use ArgumentableTrait;
52 |
53 | public const ERR_INVALID_ARG_VALUE = 0x01;
54 | public const ERR_TOO_MANY_ARGUMENTS = 0x02;
55 | public const ERR_INSUFFICIENT_ARGUMENTS = 0x03;
56 | public const ERR_NO_ARGUMENTS = 0x04;
57 | public const ERR_INVALID_ARGUMENTS = 0x05;
58 |
59 | /** @var string[] */
60 | protected $errorMessages = [
61 | self::ERR_INVALID_ARG_VALUE => TextFormat::RED . "Invalid value '{value}' for argument #{position}. Expecting: {expected}.",
62 | self::ERR_TOO_MANY_ARGUMENTS => TextFormat::RED . "Too many arguments given.",
63 | self::ERR_INSUFFICIENT_ARGUMENTS => TextFormat::RED . "Insufficient number of arguments given.",
64 | self::ERR_NO_ARGUMENTS => TextFormat::RED . "No arguments are required for this command.",
65 | self::ERR_INVALID_ARGUMENTS => TextFormat::RED . "Invalid arguments supplied.",
66 | ];
67 |
68 | /** @var CommandSender */
69 | protected CommandSender $currentSender;
70 |
71 | /** @var BaseSubCommand[] */
72 | private array $subCommands = [];
73 |
74 | /** @var BaseConstraint[] */
75 | private array $constraints = [];
76 |
77 | /** @var Plugin */
78 | protected Plugin $plugin;
79 |
80 | public function __construct(
81 | Plugin $plugin,
82 | string $name,
83 | Translatable|string $description = "",
84 | array $aliases = []
85 | ) {
86 | $this->plugin = $plugin;
87 | parent::__construct($name, $description, null, $aliases);
88 |
89 | $this->prepare();
90 |
91 | $this->usageMessage = $this->generateUsageMessage();
92 | }
93 |
94 | public function getOwningPlugin(): Plugin {
95 | return $this->plugin;
96 | }
97 |
98 | final public function execute(CommandSender $sender, string $commandLabel, array $args){
99 | $this->currentSender = $sender;
100 | if(!$this->testPermission($sender)){
101 | return;
102 | }
103 | /** @var BaseCommand|BaseSubCommand $cmd */
104 | $cmd = $this;
105 | $passArgs = [];
106 | if(count($args) > 0){
107 | if(isset($this->subCommands[($label = $args[0])])){
108 | array_shift($args);
109 | $this->subCommands[$label]->execute($sender, $label, $args);
110 | return;
111 | }
112 |
113 | $passArgs = $this->attemptArgumentParsing($cmd, $args);
114 | } elseif($this->hasRequiredArguments()){
115 | $this->sendError(self::ERR_INSUFFICIENT_ARGUMENTS);
116 | return;
117 | }
118 | if($passArgs !== null) {
119 | foreach ($cmd->getConstraints() as $constraint){
120 | if(!$constraint->test($sender, $commandLabel, $passArgs)){
121 | $constraint->onFailure($sender, $commandLabel, $passArgs);
122 | return;
123 | }
124 | }
125 | $cmd->onRun($sender, $commandLabel, $passArgs);
126 | }
127 | }
128 |
129 | /**
130 | * @param ArgumentableTrait $ctx
131 | * @param array $args
132 | *
133 | * @return array|null
134 | */
135 | private function attemptArgumentParsing($ctx, array $args): ?array {
136 | $dat = $ctx->parseArguments($args, $this->currentSender);
137 | if(!empty(($errors = $dat["errors"]))) {
138 | foreach($errors as $error) {
139 | $this->sendError($error["code"], $error["data"]);
140 | }
141 |
142 | return null;
143 | }
144 |
145 | return $dat["arguments"];
146 | }
147 |
148 | abstract public function onRun(CommandSender $sender, string $aliasUsed, array $args): void;
149 |
150 | protected function sendUsage(): void {
151 | $this->currentSender->sendMessage(TextFormat::RED . "Usage: " . $this->getUsage());
152 | }
153 |
154 | public function sendError(int $errorCode, array $args = []): void {
155 | $str = (string)$this->errorMessages[$errorCode];
156 | foreach($args as $item => $value) {
157 | $str = str_replace('{' . $item . '}', (string) $value, $str);
158 | }
159 | $this->currentSender->sendMessage($str);
160 | $this->sendUsage();
161 | }
162 |
163 | public function setErrorFormat(int $errorCode, string $format): void {
164 | if(!isset($this->errorMessages[$errorCode])) {
165 | throw new InvalidErrorCode("Invalid error code 0x" . dechex($errorCode));
166 | }
167 | $this->errorMessages[$errorCode] = $format;
168 | }
169 |
170 | public function setErrorFormats(array $errorFormats): void {
171 | foreach($errorFormats as $errorCode => $format) {
172 | $this->setErrorFormat($errorCode, $format);
173 | }
174 | }
175 |
176 | public function registerSubCommand(BaseSubCommand $subCommand): void {
177 | $keys = $subCommand->getAliases();
178 | array_unshift($keys, $subCommand->getName());
179 | $keys = array_unique($keys);
180 | foreach($keys as $key) {
181 | if(!isset($this->subCommands[$key])) {
182 | $subCommand->setParent($this);
183 | $this->subCommands[$key] = $subCommand;
184 | } else {
185 | throw new InvalidArgumentException("SubCommand with same name / alias for '$key' already exists");
186 | }
187 | }
188 | }
189 |
190 | /**
191 | * @return BaseSubCommand[]
192 | */
193 | public function getSubCommands(): array {
194 | return $this->subCommands;
195 | }
196 |
197 | public function addConstraint(BaseConstraint $constraint) : void {
198 | $this->constraints[] = $constraint;
199 | }
200 |
201 | /**
202 | * @return BaseConstraint[]
203 | */
204 | public function getConstraints(): array {
205 | return $this->constraints;
206 | }
207 |
208 | public function getUsageMessage(): string {
209 | return $this->getUsage();
210 | }
211 |
212 | public function setCurrentSender(CommandSender $sender): void{
213 | $this->currentSender = $sender;
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/src/CortexPE/Commando/BaseSubCommand.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando;
31 |
32 | use pocketmine\command\CommandSender;
33 | use pocketmine\plugin\PluginBase;
34 | use function trim;
35 |
36 | abstract class BaseSubCommand extends BaseCommand{
37 | /** @var BaseCommand */
38 | protected BaseCommand $parent;
39 |
40 | public function __construct(PluginBase $plugin, string $name, string $description = "", array $aliases = []){
41 | parent::__construct($plugin, $name, $description, $aliases);
42 |
43 | $this->usageMessage = "";
44 | }
45 |
46 | public function getParent(): BaseCommand {
47 | return $this->parent;
48 | }
49 |
50 | /**
51 | * @param BaseCommand $parent
52 | *
53 | * @internal Used to pass the parent context from the parent command
54 | */
55 | public function setParent(BaseCommand $parent): void {
56 | $this->parent = $parent;
57 | }
58 |
59 | public function getUsage(): string{
60 | if(empty($this->usageMessage)){
61 | $parent = $this->parent;
62 | $parentNames = "";
63 |
64 | while($parent instanceof BaseSubCommand) {
65 | $parentNames = $parent->getName() . $parentNames;
66 | $parent = $parent->getParent();
67 | }
68 |
69 | if($parent instanceof BaseCommand){
70 | $parentNames = $parent->getName() . " " . $parentNames;
71 | }
72 |
73 | $this->usageMessage = $this->generateUsageMessage(trim($parentNames));
74 | }
75 |
76 | return $this->usageMessage;
77 | }
78 |
79 | public function testPermissionSilent(CommandSender $sender, ?string $permission = null): bool {
80 | if($permission === null && count($this->getPermissions()) === 0) {
81 | return true;
82 | }
83 | return parent::testPermissionSilent($sender, $permission);
84 | }
85 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/IRunnable.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando;
31 |
32 |
33 | use CortexPE\Commando\constraint\BaseConstraint;
34 |
35 | /**
36 | * Interface IRunnable
37 | *
38 | * An interface which is declares the minimum required information
39 | * to get background information for a command and/or a sub-command
40 | *
41 | * @package CortexPE\Commando
42 | */
43 | interface IRunnable {
44 | public function getName(): string;
45 |
46 | /**
47 | * @return string[]
48 | */
49 | public function getAliases(): array;
50 |
51 | public function getUsageMessage():string;
52 |
53 | /**
54 | * @return string[]
55 | */
56 | public function getPermissions(): array;
57 |
58 | /**
59 | * @return BaseConstraint[]
60 | */
61 | public function getConstraints():array;
62 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/PacketHooker.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando;
31 |
32 | use CortexPE\Commando\exception\HookAlreadyRegistered;
33 | use CortexPE\Commando\store\SoftEnumStore;
34 | use CortexPE\Commando\traits\IArgumentable;
35 | use muqsit\simplepackethandler\SimplePacketHandler;
36 | use pocketmine\command\CommandSender;
37 | use pocketmine\event\EventPriority;
38 | use pocketmine\event\Listener;
39 | use pocketmine\network\mcpe\NetworkSession;
40 | use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
41 | use pocketmine\network\mcpe\protocol\types\command\CommandEnum;
42 | use pocketmine\network\mcpe\protocol\types\command\CommandOverload;
43 | use pocketmine\network\mcpe\protocol\types\command\CommandParameter;
44 | use pocketmine\plugin\Plugin;
45 | use pocketmine\Server;
46 | use ReflectionClass;
47 | use function array_unshift;
48 | use function count;
49 |
50 | class PacketHooker implements Listener {
51 | /** @var bool */
52 | private static bool $isRegistered = false;
53 |
54 | /** @var bool */
55 | private static bool $isIntercepting = false;
56 |
57 | public static function isRegistered(): bool {
58 | return self::$isRegistered;
59 | }
60 |
61 | public static function register(Plugin $registrant): void {
62 | if(self::$isRegistered) {
63 | throw new HookAlreadyRegistered("Event listener is already registered by another plugin.");
64 | }
65 | $interceptor = SimplePacketHandler::createInterceptor($registrant, EventPriority::HIGHEST, false);
66 | $interceptor->interceptOutgoing(function(AvailableCommandsPacket $pk, NetworkSession $target) : bool{
67 | if(self::$isIntercepting)return true;
68 | $p = $target->getPlayer();
69 | foreach($pk->commandData as $commandName => $commandData) {
70 | $cmd = Server::getInstance()->getCommandMap()->getCommand($commandName);
71 | if($cmd instanceof BaseCommand) {
72 | foreach($cmd->getConstraints() as $constraint){
73 | if(!$constraint->isVisibleTo($p)){
74 | continue 2;
75 | }
76 | }
77 | $pk->commandData[$commandName]->overloads = self::generateOverloads($p, $cmd);
78 | }
79 | }
80 | $pk->softEnums = SoftEnumStore::getEnums();
81 | self::$isIntercepting = true;
82 | $target->sendDataPacket($pk);
83 | self::$isIntercepting = false;
84 | return false;
85 | });
86 |
87 | self::$isRegistered = true;
88 | }
89 |
90 | /**
91 | * @param CommandSender $cs
92 | * @param BaseCommand $command
93 | *
94 | * @return CommandOverload[]
95 | */
96 | private static function generateOverloads(CommandSender $cs, BaseCommand $command): array {
97 | $overloads = [];
98 |
99 | foreach($command->getSubCommands() as $label => $subCommand) {
100 | if(!$subCommand->testPermissionSilent($cs) || $subCommand->getName() !== $label){ // hide aliases
101 | continue;
102 | }
103 | foreach($subCommand->getConstraints() as $constraint){
104 | if(!$constraint->isVisibleTo($cs)){
105 | continue 2;
106 | }
107 | }
108 | $scParam = new CommandParameter();
109 | $scParam->paramName = $label;
110 | $scParam->paramType = AvailableCommandsPacket::ARG_FLAG_VALID | AvailableCommandsPacket::ARG_FLAG_ENUM;
111 | $scParam->isOptional = false;
112 | $scParam->enum = new CommandEnum($label, [$label]);
113 |
114 | $overloadList = self::generateOverloads($cs, $subCommand);
115 | if(!empty($overloadList)){
116 | foreach($overloadList as $overload) {
117 | $overloads[] = new CommandOverload(false, [$scParam, ...$overload->getParameters()]);
118 | }
119 | } else {
120 | $overloads[] = new CommandOverload(false, [$scParam]);
121 | }
122 | }
123 |
124 | foreach(self::generateOverloadList($command) as $overload) {
125 | $overloads[] = $overload;
126 | }
127 |
128 | return $overloads;
129 | }
130 |
131 | /**
132 | * @param IArgumentable $argumentable
133 | *
134 | * @return CommandOverload[]
135 | */
136 | private static function generateOverloadList(IArgumentable $argumentable): array {
137 | $input = $argumentable->getArgumentList();
138 | $combinations = [];
139 | $outputLength = array_product(array_map("count", $input));
140 | $indexes = [];
141 | foreach($input as $k => $charList){
142 | $indexes[$k] = 0;
143 | }
144 | do {
145 | /** @var CommandParameter[] $set */
146 | $set = [];
147 | foreach($indexes as $k => $index){
148 | $param = $set[$k] = clone $input[$k][$index]->getNetworkParameterData();
149 |
150 | if (isset($param->enum) && $param->enum instanceof CommandEnum) {
151 | $refClass = new ReflectionClass(CommandEnum::class);
152 | $refProp = $refClass->getProperty("enumName");
153 | $refProp->setAccessible(true);
154 | $refProp->setValue($param->enum, "enum#" . spl_object_id($param->enum));
155 | }
156 | }
157 | $combinations[] = new CommandOverload(false, $set);
158 |
159 | foreach($indexes as $k => $v){
160 | $indexes[$k]++;
161 | $lim = count($input[$k]);
162 | if($indexes[$k] >= $lim){
163 | $indexes[$k] = 0;
164 | continue;
165 | }
166 | break;
167 | }
168 | } while(count($combinations) !== $outputLength);
169 |
170 | return $combinations;
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/CortexPE/Commando/args/BaseArgument.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\args;
31 |
32 |
33 | use pocketmine\command\CommandSender;
34 | use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
35 | use pocketmine\network\mcpe\protocol\types\command\CommandParameter;
36 |
37 | abstract class BaseArgument {
38 | /** @var string */
39 | protected string $name;
40 | /** @var bool */
41 | protected bool $optional = false;
42 | /** @var CommandParameter */
43 | protected CommandParameter $parameterData;
44 |
45 | public function __construct(string $name, bool $optional = false) {
46 | $this->name = $name;
47 | $this->optional = $optional;
48 |
49 | $this->parameterData = new CommandParameter();
50 | $this->parameterData->paramName = $name;
51 | $this->parameterData->paramType = AvailableCommandsPacket::ARG_FLAG_VALID;
52 | $this->parameterData->paramType |= $this->getNetworkType();
53 | $this->parameterData->isOptional = $this->isOptional();
54 | }
55 |
56 | abstract public function getNetworkType(): int;
57 |
58 | /**
59 | * @param string $testString
60 | * @param CommandSender $sender
61 | *
62 | * @return bool
63 | */
64 | abstract public function canParse(string $testString, CommandSender $sender): bool;
65 |
66 | /**
67 | * @param string $argument
68 | * @param CommandSender $sender
69 | *
70 | * @return mixed
71 | */
72 | abstract public function parse(string $argument, CommandSender $sender) : mixed;
73 |
74 | /**
75 | * @return string
76 | */
77 | public function getName(): string {
78 | return $this->name;
79 | }
80 |
81 | /**
82 | * @return bool
83 | */
84 | public function isOptional(): bool {
85 | return $this->optional;
86 | }
87 |
88 | /**
89 | * Returns how much command arguments
90 | * it takes to build the full argument
91 | *
92 | * @return int
93 | */
94 | public function getSpanLength(): int {
95 | return 1;
96 | }
97 |
98 | abstract public function getTypeName(): string;
99 |
100 | public function getNetworkParameterData():CommandParameter {
101 | return $this->parameterData;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/CortexPE/Commando/args/BlockPositionArgument.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\args;
31 |
32 |
33 | use pocketmine\command\CommandSender;
34 | use pocketmine\math\Vector3;
35 | use function preg_match;
36 |
37 | class BlockPositionArgument extends Vector3Argument {
38 | public function isValidCoordinate(string $coordinate, bool $locatable): bool {
39 | return (bool)preg_match("/^(?:" . ($locatable ? "(?:~-|~\+)?" : "") . "-?\d+)" . ($locatable ? "|~" : "") . "$/", $coordinate);
40 | }
41 |
42 | public function parse(string $argument, CommandSender $sender) : Vector3{
43 | $v = parent::parse($argument, $sender);
44 |
45 | return $v->floor();
46 | }
47 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/args/BooleanArgument.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\args;
31 |
32 |
33 | use pocketmine\command\CommandSender;
34 |
35 | class BooleanArgument extends StringEnumArgument {
36 |
37 | protected const VALUES = [
38 | "true" => true,
39 | "false" => false,
40 | ];
41 |
42 | public function getTypeName(): string {
43 | return "bool";
44 | }
45 |
46 | public function getEnumName(): string {
47 | return "bool";
48 | }
49 |
50 | public function parse(string $argument, CommandSender $sender): bool{
51 | return (bool) $this->getValue($argument);
52 | }
53 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/args/FloatArgument.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\args;
31 |
32 |
33 | use pocketmine\command\CommandSender;
34 | use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
35 | use function preg_match;
36 |
37 | class FloatArgument extends BaseArgument {
38 | public function getNetworkType(): int {
39 | return AvailableCommandsPacket::ARG_TYPE_FLOAT;
40 | }
41 |
42 | public function getTypeName(): string {
43 | return "decimal";
44 | }
45 |
46 | public function canParse(string $testString, CommandSender $sender): bool {
47 | return (bool)preg_match("/^-?(?:\d+|\d*\.\d+)$/", $testString);
48 | }
49 |
50 | public function parse(string $argument, CommandSender $sender) : float{
51 | return (float) $argument;
52 | }
53 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/args/IntegerArgument.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\args;
31 |
32 |
33 | use pocketmine\command\CommandSender;
34 | use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
35 | use function preg_match;
36 |
37 | class IntegerArgument extends BaseArgument {
38 | public function getNetworkType(): int {
39 | return AvailableCommandsPacket::ARG_TYPE_INT;
40 | }
41 |
42 | public function getTypeName(): string {
43 | return "int";
44 | }
45 |
46 | public function canParse(string $testString, CommandSender $sender): bool {
47 | return (bool)preg_match("/^-?(?:\d+)$/", $testString);
48 | }
49 |
50 | public function parse(string $argument, CommandSender $sender) : int{
51 | return (int) $argument;
52 | }
53 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/args/RawStringArgument.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\args;
31 |
32 | use pocketmine\command\CommandSender;
33 | use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
34 |
35 | class RawStringArgument extends BaseArgument {
36 | public function getNetworkType(): int {
37 | return AvailableCommandsPacket::ARG_TYPE_STRING;
38 | }
39 |
40 | public function getTypeName(): string {
41 | return "string";
42 | }
43 |
44 | public function canParse(string $testString, CommandSender $sender): bool {
45 | return true;
46 | }
47 |
48 | public function parse(string $argument, CommandSender $sender) : string{
49 | return $argument;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/CortexPE/Commando/args/StringEnumArgument.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\args;
31 |
32 |
33 | use pocketmine\command\CommandSender;
34 | use pocketmine\network\mcpe\protocol\types\command\CommandEnum;
35 | use function array_keys;
36 | use function array_map;
37 | use function implode;
38 | use function preg_match;
39 | use function strtolower;
40 |
41 | abstract class StringEnumArgument extends BaseArgument {
42 |
43 | protected const VALUES = [];
44 |
45 | public function __construct(string $name, bool $optional = false) {
46 | parent::__construct($name, $optional);
47 |
48 | $this->parameterData->enum = new CommandEnum($this->getEnumName(), $this->getEnumValues());
49 | }
50 |
51 | public function getNetworkType(): int {
52 | // this will be disregarded by PM anyways because this will be considered as a string enum
53 | return -1;
54 | }
55 |
56 | public function canParse(string $testString, CommandSender $sender): bool {
57 | return (bool)preg_match(
58 | "/^(" . implode("|", array_map("\\strtolower", $this->getEnumValues())) . ")$/iu",
59 | $testString
60 | );
61 | }
62 |
63 | public abstract function getEnumName(): string;
64 |
65 | public function getValue(string $string) {
66 | return static::VALUES[strtolower($string)];
67 | }
68 |
69 | public function getEnumValues(): array {
70 | return array_keys(static::VALUES);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/CortexPE/Commando/args/TargetPlayerArgument.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\args;
31 |
32 |
33 | use pocketmine\command\CommandSender;
34 | use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
35 |
36 | class TextArgument extends RawStringArgument {
37 | public function getNetworkType(): int {
38 | return AvailableCommandsPacket::ARG_TYPE_RAWTEXT;
39 | }
40 |
41 | public function getTypeName(): string {
42 | return "text";
43 | }
44 |
45 | public function getSpanLength(): int {
46 | return PHP_INT_MAX;
47 | }
48 | public function canParse(string $testString, CommandSender $sender): bool {
49 | return $testString !== "";
50 | }
51 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/args/Vector3Argument.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\args;
31 |
32 |
33 | use pocketmine\command\CommandSender;
34 | use pocketmine\entity\Entity;
35 | use pocketmine\math\Vector3;
36 | use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
37 | use function count;
38 | use function explode;
39 | use function preg_match;
40 | use function substr;
41 |
42 | class Vector3Argument extends BaseArgument {
43 | public function getNetworkType(): int {
44 | return AvailableCommandsPacket::ARG_TYPE_POSITION;
45 | }
46 |
47 | public function getTypeName(): string {
48 | return "x y z";
49 | }
50 |
51 | public function canParse(string $testString, CommandSender $sender): bool {
52 | $coords = explode(" ", $testString);
53 | if(count($coords) === 3) {
54 | foreach($coords as $coord) {
55 | if(!$this->isValidCoordinate($coord, $sender instanceof Vector3)) {
56 | return false;
57 | }
58 | }
59 |
60 | return true;
61 | }
62 |
63 | return false;
64 | }
65 |
66 | public function isValidCoordinate(string $coordinate, bool $locatable): bool {
67 | return (bool)preg_match("/^(?:" . ($locatable ? "(\\?:~-|~\+)?" : "") . "-?(?:\d+|\d*\.\d+))" . ($locatable ? "|~" : "") . "$/", $coordinate);
68 | }
69 |
70 | public function parse(string $argument, CommandSender $sender) : Vector3{
71 | $coords = explode(" ", $argument);
72 | $vals = [];
73 | foreach($coords as $k => $coord){
74 | $offset = 0;
75 | // if it's locatable and starts with ~- or ~+
76 | if($sender instanceof Entity && preg_match("/^(?:~-|~\+)|~/", $coord)){
77 | // this will work with -n, +n and "" due to typecast later
78 | $offset = substr($coord, 1);
79 |
80 | // replace base coordinate with actual entity coordinates
81 | $position = $sender->getPosition();
82 | $coord = match ($k) {
83 | 0 => $position->x,
84 | 1 => $position->y,
85 | 2 => $position->z,
86 | };
87 | }
88 | $vals[] = (float)$coord + (float)$offset;
89 | }
90 | return new Vector3(...$vals);
91 | }
92 |
93 | public function getSpanLength(): int {
94 | return 3;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/CortexPE/Commando/constraint/BaseConstraint.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\constraint;
31 |
32 |
33 | use CortexPE\Commando\IRunnable;
34 | use pocketmine\command\CommandSender;
35 |
36 | abstract class BaseConstraint {
37 | /** @var IRunnable */
38 | protected IRunnable $context;
39 |
40 | /**
41 | * BaseConstraint constructor.
42 | *
43 | * "Context" is required so that this new-constraint-system doesn't hinder getting command info
44 | *
45 | * @param IRunnable $context
46 | */
47 | public function __construct(IRunnable $context) {
48 | $this->context = $context;
49 | }
50 |
51 | /**
52 | * @return IRunnable
53 | */
54 | public function getContext(): IRunnable {
55 | return $this->context;
56 | }
57 |
58 | abstract public function test(CommandSender $sender, string $aliasUsed, array $args): bool;
59 |
60 | abstract public function onFailure(CommandSender $sender, string $aliasUsed, array $args): void;
61 |
62 | abstract public function isVisibleTo(CommandSender $sender): bool;
63 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/constraint/ConsoleRequiredConstraint.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\constraint;
31 |
32 |
33 | use pocketmine\command\CommandSender;
34 | use pocketmine\player\Player;
35 | use pocketmine\utils\TextFormat;
36 |
37 | class ConsoleRequiredConstraint extends BaseConstraint {
38 |
39 | public function test(CommandSender $sender, string $aliasUsed, array $args): bool {
40 | return $this->isVisibleTo($sender);
41 | }
42 |
43 | public function onFailure(CommandSender $sender, string $aliasUsed, array $args): void {
44 | $sender->sendMessage(TextFormat::RED . "This command must be executed from a server console."); // f*ck off grammar police
45 | }
46 |
47 | public function isVisibleTo(CommandSender $sender): bool {
48 | return !($sender instanceof Player);
49 | }
50 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/constraint/InGameRequiredConstraint.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\constraint;
31 |
32 |
33 | use pocketmine\command\CommandSender;
34 | use pocketmine\player\Player;
35 | use pocketmine\utils\TextFormat;
36 |
37 | class InGameRequiredConstraint extends BaseConstraint {
38 |
39 | public function test(CommandSender $sender, string $aliasUsed, array $args): bool {
40 | return $this->isVisibleTo($sender);
41 | }
42 |
43 | public function onFailure(CommandSender $sender, string $aliasUsed, array $args): void {
44 | $sender->sendMessage(TextFormat::RED . "This command must be executed in-game."); // f*ck off grammar police
45 | }
46 |
47 | public function isVisibleTo(CommandSender $sender): bool {
48 | return $sender instanceof Player;
49 | }
50 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/exception/ArgumentOrderException.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\exception;
31 |
32 |
33 | class ArgumentOrderException extends CommandoException {
34 |
35 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/exception/CommandoException.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\exception;
31 |
32 |
33 | use Exception;
34 |
35 | class CommandoException extends Exception {
36 |
37 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/exception/HookAlreadyRegistered.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\exception;
31 |
32 |
33 | class HookAlreadyRegistered extends CommandoException {
34 |
35 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/exception/InvalidErrorCode.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\exception;
31 |
32 |
33 | class InvalidErrorCode extends CommandoException {
34 |
35 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/store/SoftEnumStore.php:
--------------------------------------------------------------------------------
1 | getName()] = $enum;
31 | self::broadcastSoftEnum($enum, UpdateSoftEnumPacket::TYPE_ADD);
32 | }
33 |
34 | public static function updateEnum(string $enumName, array $values):void {
35 | if(self::getEnumByName($enumName) === null){
36 | throw new CommandoException("Unknown enum named " . $enumName);
37 | }
38 | self::$enums[$enumName] = $enum = new CommandEnum($enumName, $values);
39 | self::broadcastSoftEnum($enum, UpdateSoftEnumPacket::TYPE_SET);
40 | }
41 |
42 | public static function removeEnum(string $enumName):void {
43 | if(($enum = self::getEnumByName($enumName)) === null){
44 | throw new CommandoException("Unknown enum named " . $enumName);
45 | }
46 | unset(static::$enums[$enumName]);
47 | self::broadcastSoftEnum($enum, UpdateSoftEnumPacket::TYPE_REMOVE);
48 | }
49 |
50 | public static function broadcastSoftEnum(CommandEnum $enum, int $type):void {
51 | $pk = new UpdateSoftEnumPacket();
52 | $pk->enumName = $enum->getName();
53 | $pk->values = $enum->getValues();
54 | $pk->type = $type;
55 | self::broadcastPacket($pk);
56 | }
57 |
58 | private static function broadcastPacket(ClientboundPacket $pk):void {
59 | $sv = Server::getInstance();
60 | NetworkBroadcastUtils::broadcastPackets($sv->getOnlinePlayers(), [$pk]);
61 | }
62 | }
--------------------------------------------------------------------------------
/src/CortexPE/Commando/traits/ArgumentableTrait.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\traits;
31 |
32 |
33 | use CortexPE\Commando\args\BaseArgument;
34 | use CortexPE\Commando\args\TextArgument;
35 | use CortexPE\Commando\BaseCommand;
36 | use CortexPE\Commando\exception\ArgumentOrderException;
37 | use pocketmine\command\CommandSender;
38 | use pocketmine\utils\TextFormat;
39 | use function array_slice;
40 | use function count;
41 | use function implode;
42 | use function is_array;
43 | use function rtrim;
44 | use function trim;
45 | use function usort;
46 |
47 | trait ArgumentableTrait{
48 | /** @var BaseArgument[][] */
49 | private array $argumentList = []; // [argumentPosition => [...possible BaseArgument(s)]]
50 | /** @var bool[] */
51 | private array $requiredArgumentCount = [];
52 |
53 | /**
54 | * This is where all the arguments, permissions, sub-commands, etc would be registered
55 | */
56 | abstract protected function prepare() : void;
57 |
58 | /**
59 | * @param int $position
60 | * @param BaseArgument $argument
61 | *
62 | * @throws ArgumentOrderException
63 | */
64 | public function registerArgument(int $position, BaseArgument $argument): void {
65 | if($position < 0) {
66 | throw new ArgumentOrderException("You cannot register arguments at negative positions");
67 | }
68 | if($position > 0 && !isset($this->argumentList[$position - 1])) {
69 | throw new ArgumentOrderException("There were no arguments before $position");
70 | }
71 | foreach($this->argumentList[$position - 1] ?? [] as $arg) {
72 | if($arg instanceof TextArgument) {
73 | throw new ArgumentOrderException("No other arguments can be registered after a TextArgument");
74 | }
75 | if($arg->isOptional() && !$argument->isOptional()){
76 | throw new ArgumentOrderException("You cannot register a required argument after an optional argument");
77 | }
78 | }
79 | $this->argumentList[$position][] = $argument;
80 | if(!$argument->isOptional()) {
81 | $this->requiredArgumentCount[$position] = true;
82 | }
83 | }
84 |
85 | public function parseArguments(array $rawArgs, CommandSender $sender): array {
86 | $return = [
87 | "arguments" => [],
88 | "errors" => []
89 | ];
90 | // try parsing arguments
91 | $required = count($this->requiredArgumentCount);
92 | if(!$this->hasArguments() && count($rawArgs) > 0) { // doesnt take args but sender gives args anyways
93 | $return["errors"][] = [
94 | "code" => BaseCommand::ERR_NO_ARGUMENTS,
95 | "data" => []
96 | ];
97 | }
98 | $offset = 0;
99 | $argOffset = 0;
100 | if(count($rawArgs) > 0) {
101 | foreach($this->argumentList as $pos => $possibleArguments) {
102 | // try the one that spans more first... before the others
103 | usort($possibleArguments, function (BaseArgument $a): int {
104 | if($a->getSpanLength() === PHP_INT_MAX) { // if it takes unlimited arguments, pull it down
105 | return 1;
106 | }
107 |
108 | return -1;
109 | });
110 | $parsed = false;
111 | $optional = true;
112 | foreach($possibleArguments as $argument) {
113 | $arg = trim(implode(" ", array_slice($rawArgs, $offset, ($len = $argument->getSpanLength()))));
114 | if(!$argument->isOptional()) {
115 | $optional = false;
116 | }
117 | if($arg !== "" && $argument->canParse($arg, $sender)) {
118 | $k = $argument->getName();
119 | $result = (clone $argument)->parse($arg, $sender);
120 | if(isset($return["arguments"][$k]) && !is_array($return["arguments"][$k])) {
121 | $old = $return["arguments"][$k];
122 | unset($return["arguments"][$k]);
123 | $return["arguments"][$k] = [$old];
124 | $return["arguments"][$k][] = $result;
125 | } else {
126 | $return["arguments"][$k] = $result;
127 | }
128 | if(!$optional) {
129 | $required--;
130 | }
131 | $offset += $len;
132 | ++$argOffset;
133 | $parsed = true;
134 | break;
135 | }
136 | if($offset > count($rawArgs)) {
137 | break; // we've reached the end of the argument list the user passed
138 | }
139 | }
140 | if(!$parsed && !($optional && empty($arg))) { // we tried every other possible argument type, none was satisfied
141 | $expectedArgs = $this->argumentList[$argOffset];
142 | $expected = "";
143 | foreach($expectedArgs as $expectedArg){
144 | $expected .= $expectedArg->getTypeName() . "|";
145 | }
146 |
147 | $return["errors"][] = [
148 | "code" => BaseCommand::ERR_INVALID_ARG_VALUE,
149 | "data" => [
150 | "value" => $rawArgs[$offset] ?? "",
151 | "position" => $pos + 1,
152 | "expected" => rtrim($expected, "|")
153 | ]
154 | ];
155 |
156 | return $return; // let's break it here.
157 | }
158 | }
159 | }
160 | if($offset < count($rawArgs)) { // this means that the arguments our user sent is more than the needed amount
161 | $return["errors"][] = [
162 | "code" => BaseCommand::ERR_TOO_MANY_ARGUMENTS,
163 | "data" => []
164 | ];
165 | }
166 | if($required > 0) {// We still have more unfilled required arguments
167 | $return["errors"][] = [
168 | "code" => BaseCommand::ERR_INSUFFICIENT_ARGUMENTS,
169 | "data" => []
170 | ];
171 | }
172 |
173 | // up to my testing this occurs when BaseCommand::ERR_NO_ARGUMENTS and BaseCommand::ERR_TOO_MANY_ARGUMENTS are given as errors
174 | // this only (as far as my testing) happens when command accepts arguments (e.g. a subcommand) but the user supplied invalid argument
175 | // also the error code remains as shown due to the way they are passed
176 | // have a better way? pr please :)
177 | if(
178 | count($return["errors"]) === 2 &&
179 | $return["errors"][0]["code"] === BaseCommand::ERR_NO_ARGUMENTS &&
180 | $return["errors"][1]["code"] === BaseCommand::ERR_TOO_MANY_ARGUMENTS
181 | ){
182 | unset($return["errors"]);
183 |
184 | $return["errors"][] = [
185 | "code" => BaseCommand::ERR_INVALID_ARGUMENTS,
186 | "data" => []
187 | ];
188 | }
189 |
190 | return $return;
191 | }
192 |
193 | public function generateUsageMessage(string $parent = ""): string {
194 | $name = $parent . (empty($parent) ? "" : " ") . $this->getName();
195 | $msg = TextFormat::RED . "/" . $name;
196 | $args = [];
197 | foreach($this->argumentList as $arguments){
198 | $hasOptional = false;
199 | $names = [];
200 | foreach($arguments as $argument){
201 | $names[] = $argument->getName() . ":" . $argument->getTypeName();
202 | if($argument->isOptional()){
203 | $hasOptional = true;
204 | }
205 | }
206 | $names = implode("|", $names);
207 | if($hasOptional){
208 | $args[] = "[" . $names . "]";
209 | } else {
210 | $args[] = "<" . $names . ">";
211 | }
212 | }
213 | $msg .= ((empty($args)) ? "" : " ") . implode(TextFormat::RED . " ", $args) . ": " . $this->getDescription();
214 | foreach($this->subCommands as $label => $subCommand){
215 | if($label === $subCommand->getName()){
216 | $msg .= "\n - " . $subCommand->generateUsageMessage($name);
217 | }
218 | }
219 |
220 | return trim($msg);
221 | }
222 |
223 | public function hasArguments(): bool {
224 | return !empty($this->argumentList);
225 | }
226 |
227 | public function hasRequiredArguments(): bool {
228 | foreach($this->argumentList as $arguments) {
229 | foreach($arguments as $argument) {
230 | if(!$argument->isOptional()) {
231 | return true;
232 | }
233 | }
234 | }
235 |
236 | return false;
237 | }
238 |
239 | /**
240 | * @return BaseArgument[][]
241 | */
242 | public function getArgumentList(): array {
243 | return $this->argumentList;
244 | }
245 | }
246 |
--------------------------------------------------------------------------------
/src/CortexPE/Commando/traits/IArgumentable.php:
--------------------------------------------------------------------------------
1 | .
24 | *
25 | * Written by @CortexPE
26 | *
27 | */
28 | declare(strict_types=1);
29 |
30 | namespace CortexPE\Commando\traits;
31 |
32 |
33 | use CortexPE\Commando\args\BaseArgument;
34 | use pocketmine\command\CommandSender;
35 |
36 | interface IArgumentable {
37 | public function generateUsageMessage(string $parent = ""): string;
38 | public function hasArguments(): bool;
39 |
40 | /**
41 | * @return BaseArgument[][]
42 | */
43 | public function getArgumentList(): array;
44 | public function parseArguments(array $rawArgs, CommandSender $sender): array;
45 | public function registerArgument(int $position, BaseArgument $argument): void;
46 | }
--------------------------------------------------------------------------------
/virion.yml:
--------------------------------------------------------------------------------
1 | name: Commando
2 | antigen: CortexPE\Commando
3 | api: 5.3.0
4 | version: 3.2.1
5 | author: CortexPE
6 | authors: [ParoxityTeam]
7 |
--------------------------------------------------------------------------------