├── .gitignore ├── .idea ├── .gitignore ├── artifacts │ └── CustomCommands_jar.xml ├── compiler.xml ├── encodings.xml ├── jarRepositories.xml ├── libraries │ ├── Maven__com_alibaba_fastjson_1_2_75.xml │ ├── Maven__com_google_code_gson_gson_2_8_0.xml │ ├── Maven__com_google_guava_guava_21_0.xml │ ├── Maven__commons_lang_commons_lang_2_6.xml │ ├── Maven__org_bukkit_bukkit_1_15_1_R0_1_SNAPSHOT.xml │ └── Maven__org_yaml_snakeyaml_1_25.xml ├── misc.xml ├── modules.xml ├── uiDesigner.xml └── vcs.xml ├── CustomCommands.iml ├── LICENSE ├── README.md ├── logo_small.png ├── out └── production │ ├── Custom-Commands │ ├── META-INF │ │ └── MANIFEST.MF │ ├── commands.yml │ ├── config.yml │ ├── lang │ │ └── zhcn.json │ └── plugin.yml │ └── CustomCommands │ ├── META-INF │ └── MANIFEST.MF │ ├── config.yml │ ├── plugin.yml │ └── resources │ ├── commands.yml │ └── lang │ └── zhcn.yaml ├── pom.xml ├── src └── main │ ├── java │ ├── META-INF │ │ └── MANIFEST.MF │ └── org │ │ └── taixue │ │ └── customcommands │ │ ├── Plugin.java │ │ ├── commandexecutor │ │ ├── CCSCCommandExecutor.java │ │ ├── CCSCommandExecutor.java │ │ ├── CCSECommandExecutor.java │ │ └── CCSRCommandExecutor.java │ │ ├── config │ │ ├── CommandsConfig.java │ │ ├── Config.java │ │ └── PluginConfig.java │ │ ├── customcommand │ │ ├── Command.java │ │ └── Group.java │ │ ├── language │ │ ├── Environment.java │ │ ├── Language.java │ │ └── Messages.java │ │ ├── script │ │ ├── MessageScript.java │ │ ├── Script.java │ │ ├── Scripts.java │ │ ├── SleepScript.java │ │ ├── Strings.java │ │ └── TitleScript.java │ │ └── util │ │ ├── Commands.java │ │ ├── Files.java │ │ ├── Groups.java │ │ └── Paths.java │ └── resources │ ├── commands.yml │ ├── config.yml │ ├── lang │ └── zhcn.json │ └── plugin.yml └── target └── classes ├── commands.yml ├── config.yml ├── lang └── zhcn.json └── plugin.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /../../../../../:\software engineer\Java\CustomCommands\.idea/dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/artifacts/CustomCommands_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/out/artifacts/CustomCommands_jar 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_alibaba_fastjson_1_2_75.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_code_gson_gson_2_8_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_guava_guava_21_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_lang_commons_lang_2_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_bukkit_bukkit_1_15_1_R0_1_SNAPSHOT.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_yaml_snakeyaml_1_25.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CustomCommands.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU 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 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CustomCommands:自定义指令 2 | `CustomCommands` 插件也叫 `CCS(CustomCommandS)`或 `Custom-Commands` 等,允许自己设置一些指令的格式,以简化输入。 3 | 4 | * 插件 QQ 群:`1028582500` 5 | * 作者:椽子。 6 | * 明城京联合太学,保留所有权利。 7 | * 请遵循 `GNU` 开源协议使用 `CCS`。 8 | 9 | ![CCS logo](./logo_small.png "CCS logo") 10 | 11 | ## 目录 12 | * [CCS能做什么?](#CCS能做什么?) 13 | * [给指令打包](##给指令打包) 14 | * [更改指令的参数顺序](##更改指令的参数顺序) 15 | * [基本概念](#基本概念) 16 | * [指令组](#指令组) 17 | * [指令分支](#指令分支) 18 | * [参数列表](#指令查找) 19 | * [执行指令](#指令查找) 20 | * [变量](#变量) 21 | * [前置插件](#前置插件) 22 | * [配置文件](#配置文件) 23 | * [config.yml](#config.yml) 24 | * [commands.yml](#commands.yml) 25 | * [插件指令](#插件指令) 26 | * [权限节点](#权限节点) 27 | * [画大饼](#画大饼) 28 | * [已经开发完成的功能](#已经开发完成的功能) 29 | * [正在开发的功能](#正在开发的功能) 30 | * [可能要增加的功能](#可能要增加的功能) 31 | * [高级功能](#高级功能) 32 | * [强匹配与弱匹配](#强匹配与弱匹配) 33 | * [词库机制](#词库机制) 34 | * [模式匹配机制](#模式匹配机制) 35 | * [联系方式](#联系方式) 36 | * [更新日志](#更新日志) 37 | * [4.1](#4.1) 38 | * [4.0](#4.0) 39 | * [3.0](#3.0) 40 | * [2.0](#2.0) 41 | * [1.0](#1.0) 42 | * [其他发布地址](#其他发布地址) 43 | * [感谢](#感谢) 44 | 45 | ## CCS能做什么? 46 | ### 给指令打包 47 | 在使用 `PermissionEX` (一款老牌的权限组插件)的服务器上,输入相关指令是件令人头疼的事情。 48 | 49 | 例如,你也许需要输入下面的指令,给予玩家在某个世界内的权限,并全服广播: 50 | * `/pex user <玩家ID> add <权限节点> <世界名>` 51 | * `/pex reload` 52 | * `/bc 恭喜玩家 <玩家ID> 获得了在世界 <世界名> 中的权限 <权限节点> !` 53 | 54 | `CCS` 让你可以只给出必要的 `<玩家ID>` `<权限节点>`和`<世界名>`这三个关键信息,就自动执行上面这一串指令。这就把三个指令打包为一个指令。 55 | 56 | ### 更改指令的参数顺序 57 | 如果你不喜欢下面这个指令的参数顺序 58 | * `/pex user <玩家ID> add <权限节点> <世界名>` 59 | 60 | 完全可以将其打包为另一个指令,至于在哪个位置输入`<玩家ID>`这些信息,完全你设计! 61 | 62 | ## 基本概念 63 | ### 指令组 64 | 如果你设计一组指令(执行自定义指令都需要加相同的 `/ccsr` 前缀): 65 | |格式|作用 66 | |---|--- 67 | |`/ccsr story tell <玩家>`|给玩家讲故事 68 | |`/ccsr story stop`|停止给玩家讲故事 69 | |`/ccsr taixue register `|注册在太学服务器的账号 70 | 71 | 前两条指令都以 `/ccsr story` 开头,都是和故事相关的操作。这两个指令便组成了一个指令组`story`。这两种参数形式,对应不同功能,分别是这个组的不同指令分支。 72 | 73 | 第三条指令以 `/ccsr taixue` 开头,所以属于指令组`taixue`。 74 | 75 | ### 指令分支 76 | 指令分支是在同一个指令组中,对应不同功能和参数列表的子指令。例如上面的前两条指令对应指令组 `story` 的不同指令分支。 77 | 78 | 每一个指令分支都至少需要一个确定的参数列表执行指令 79 | 80 | #### 参数列表 81 | 除去相同的`/ccsr <指令组名>`,剩余的内容叫这个指令分支的参数列表。例如: 82 | |原指令|参数列表 83 | |---|--- 84 | |`/ccsr story tell <玩家>`|`tell <玩家>` 85 | |`/ccsr story stop`|`stop` 86 | 87 | 对于上表第一个分支,`/ccsr story tell chuanwise` 是一个正确的输入,此时`<玩家>`就是`chuanwise`。 88 | 89 | `/ccsr story tell chuanwise zzz`是一个错误的输入,因为 `story` 组内没有任何一个分支是这个格式。 90 | 91 | #### 执行指令 92 | 执行指令是一个指令分支中,输入正确的参数后执行的一串指令。 93 | 94 | 例如,如果你希望玩家输入 `/ccsr story tell <玩家>` 后执行下面一串指令: 95 | 1. `/tell <玩家> 从前有座山` 96 | 1. `/tell <玩家> 山上有座庙` 97 | 1. `/tell <玩家> 庙里有个Chuanwise在讲故事` 98 | 99 | 这一串指令就是这个分支的执行指令。 100 | 101 | ### 变量 102 | 变量是一个值的代号。例如上文的 `玩家` 就是一个变量,它的值可能是 `chuanwise`,也可能是其他任何值。 103 | 104 | 变量可以在执行指令中使用,可以在玩家输入的参数中读入或自行设定。 105 | 106 | ## 前置插件 107 | 暂无 \_(:з」∠)\_。 108 | 109 | ## 配置文件 110 | ### config.yml 111 | 默认的 `config.yml` 一般足够使用,其内容为: 112 | 113 | ```yaml 114 | config: 115 | # 语言选项。zhcn 是中文 116 | lang: zhcn 117 | 118 | # 是否开启调试模式(会输出一些解析信息) 119 | debug: true 120 | 121 | # 最大迭代次数 122 | max-iterations: 10 123 | 124 | # 修改配置后是否自动保存 125 | auto-save: true 126 | 127 | # 是否开启强匹配 128 | strong-match: true 129 | ``` 130 | #### max-iterations(最大迭代次数) 131 | 将变量替换为其值的最大次数。 132 | 133 | 对变量 `{remain}`,如果它的内容是 `head {remain}`,不论怎么展开,最终的值都是 `head head head ... {remain}`。 134 | 变量 `max-iterations` 控制了变量的值中仍存在变量的情况下,最大的迭代次数,也就是上例中 `head` 的数量。 135 | 136 | #### auto-save(自动保存) 137 | 默认值:`true` 138 | 139 | 修改插件配置后是否立即保存。若选择 `false`,插件将在关闭服务器时自动保存所做的修改。你也可以使用 `/ccsc save` 手动保存。 140 | 141 | 其他相关内容请阅览高级主题[模式匹配机制](#模式匹配机制)。 142 | 143 | ### commands.yml 144 | 默认的 `commands.yml` 的内容是: 145 | 146 | ```yaml 147 | commands: 148 | # 执行一个自定义指令组的权限默认是:ccs.run.<指令组名>.<分支名> 149 | 150 | # 指令组名 151 | group-name: 152 | 153 | # 分支名 154 | branch-name: 155 | 156 | # 该分支的参数列表 157 | format: 'set {user_name} {group_name}' 158 | 159 | # 该分支的执行指令 160 | actions: 161 | - 'pex user {user_name} group set {group_name}' 162 | - 'broadcast {user_name} is a member of {group_name}.' 163 | 164 | # 执行执行指令时的身份 165 | # identify: console 166 | 167 | # usage: '格式错误时显示给指令发送者的内容' 168 | 169 | # result: '成功执行后显示给指令发送者的内容'。若无 result,则将不会发送给指令发送者任何消息。 170 | ``` 171 | 172 | #### format(参数列表) 173 | 解析输入的指令的规则,由变量定义和普通文字组成。 174 | 175 | 使用 `{}` 包围的内容是变量定义。括号内是该变量的名字。一个合规的变量名必须仅由英文字母、数字和下划线组成,且不以数字开头。如 `{favouritesc}`、`{chuanwise}` 和 `{favouritesc_chuanwise}` 都是合规的变量名。 176 | 177 | 变量 `{remain}` 是一个很特殊的变量。如果在 `format` 中定义,必须出现在末尾。
178 | 解析时候,如遇 `{remain}` ,指令剩余的所有内容都会存入这个变量中。它的内容可能包含空格,也可能为空。 179 | 180 | 例如对 `/ccsr player {name} {remain}`,对不同的输入: 181 | |输入|`{name}` 的值|`{remain}` 的值 182 | |---|---|--- 183 | |`/ccsr player chuanwise`|`chuanwise`|(空) 184 | |`/ccsr player chuanwise qwq`|`chuanwise`|`qwq` 185 | |`/ccsr player chuanwise qwq orz`|`chuanwise`|`qwq orz` 186 | 187 | #### actions(执行指令) 188 | 输入格式正确后将会执行的一串命令。 189 | 190 | `actions` 的每一个语句中都可以使用变量,格式为 `{变量名}`,它们会被替换为该变量的值。 191 | 192 | 如果出现了无法找到的变量,它们会保持原样。有关变量的查找方式,请查阅高级内容[词库机制](#词库机制)。 193 | 194 | ##### 预定义词库 195 | 下面的变量无须在 `format` 中定义便可以使用。如果在 `format` 中定义了同名的变量,则以 `format` 读入的为准。 196 | |变量名|值 197 | |---|--- 198 | |`{player}`|玩家名。如果是控制台身份,则为 `CONSOLE` 199 | |`{displayName}`|玩家显示出的名字,包含前后缀等信息 200 | |`{world}`|玩家所在世界名。控制台身份无此变量 201 | |`{group}`|当前指令分支所处的组。控制台身份无此变量 202 | |`{UUID}`|玩家的 UUID。控制台身份无此变量 203 | 204 | ##### 脚本 205 | `actions` 中以 `@` 开头的都是脚本,如下表所示: 206 | |脚本名|格式|参数解释|作用 207 | |---|---|---|--- 208 | |`sleep`|`@sleep <时长>`|停顿秒数,单位毫秒|在此处停顿若干毫秒后继续执行后面的 `actions` 语句 209 | |`message`|`@message <信息>`|一段信息,可以包含空格|将这段信息发送给指令发送者 210 | |`title`|`@title <主标题> [副标题]`|一个主标题和副标题,副标题可以包含空格|为玩家显示一个标题 211 | 212 | ##### 注意 213 | 1. 自循环
214 | `CCS` 允许你在 actions 中写入 `/ccsr` 指令,这可能会导致循环。例如下面的情况: 215 | ```yaml 216 | commands: 217 | # ... 218 | death-loop: 219 | # 分支名可以随便起 220 | this: 221 | format: '{remain}' 222 | actions: 223 | - 'ccsr death-loop {remain}' 224 | ``` 225 | 这会导致服务器后台输出大量错误信息随后崩服。
226 | 为了保护你的服务器,在设计 actions 时,强烈建议在添加额外的 `/ccsr` 时仔细考虑。 227 | 1. `@sleep 时长`:请确保停顿时长小于 `spigot.yml` 中的 `settings.timeout-time`,否则服务器会被判定为卡死,随后崩服。 228 | 例如,当 `settings.timeout-time` 为 `60` 时,意味着服务器无响应 `60` 秒会被判定为卡死。为确保不会崩服,`@sleep` 的参数应该小于 `50000`。 229 | 1. `@title` 无法被应用在控制台上。 230 | 231 | #### usage(选填) 232 | 默认值:`/ccsr {group} {format}`。 233 | 234 | 在上面的例子中,`usage` 的值默认是 `/ccsr group-name set {user_name} {group_name}` 235 | 236 | 这是描述该指令用法的字符串,他将在使用指令的人输入了一种无法被当前指令组中任何一种指令分支匹配,或能同时被多个分支匹配时显示。 237 | 238 | #### identify(选填) 239 | 默认值: `auto`。 240 | 241 | 这是执行 `actions` 时的身份,其取值和作用如下表。 242 | |`identify`|作用 243 | |---|--- 244 | |`auto`|以当前输入 `/ccsr` 指令的人的身份执行 `actions` 245 | |`console`|以控制台身份执行 `actions` 246 | |`bypass`|玩家身份跳过权限检测执行 `actions` 247 | 248 | #### result(选填) 249 | 默认值:`指令已执行`。 250 | 251 | 指令匹配成功并执行结束后,发送给指令发送者的信息。可以使用变量。 252 | 253 | ## 插件指令 254 | 所有格式是 `/ccs ` 的指令都可以被简化为 `/ccs `,例如 `/ccs config` 可以简化为 `/ccsc`。`CCSC` 也就是 `CustomCommandS Config`, `CCSR` 是 `CustomCommandS Run`。 255 | 256 | 下表中的指令对应的权限见[权限节点](#权限节点)。 257 | 258 | |指令|作用 259 | |---|--- 260 | |`/ccs reload`|重载所有设置 261 | |`/ccs version`|显示插件名、版本号等信息 262 | |`/ccs debug`|开关调试模式 263 | |`/ccsc list`|显示所有已加载的指令组 264 | |`/ccsc add `|新建指令组 265 | |`/ccsc group `|查看有关指令组``的信息 266 | |`/ccsc remove `|删除指令组`` 267 | |`/ccsc group add `|在组中添加分支`` 268 | |`/ccsc group remove `|删除组中的分支`` 269 | |`/ccsc group rename `|重命名指令组为`` 270 | |`/ccsc group command `|查看分支``的信息 271 | |`/ccsc group command rename `|重命名分支``为`` 272 | |`/ccsc group command identify `|设置执行执行指令的身份为 273 | |`/ccsc group command format `|设置该分支的参数格式 274 | |`/ccsc group command actions add `|在该分支的执行指令中追加新的指令`` 275 | |`/ccsc group command actions clear`|清空执行指令 276 | |`/ccsc group command actions remove `|删除执行指令中的第一个指令`` 277 | |`/ccsc group command actions set `|设置执行指令为指令`` 278 | |`/ccsc group command actions edit `|修改第``条执行指令为 `` 279 | |`/ccsc group command result `|修改返回信息为 ``,可以包含空格或为空 280 | |`/ccsc group command usage `|修改指令用法为 ``,可以包含空格或为空 281 | |`/ccsc group command permissions add `|在该分支的匹配权限中增加新的权限节点 `` 282 | |`/ccsc group command permissions clear`|清除该分支的匹配权限。 283 | |`/ccsc group command permissions remove `|删除该分支的匹配权限中的权限节点 `` 284 | |`/ccsc group command permissions set `|设置匹配权限为 `` 285 | |`/ccsc group command permissions edit `|修改匹配权限中的第 `` 个节点为 `` 286 | |`/ccsc group command permissions default`|将匹配权限设置为默认值,即 `ccs.run..` 287 | |`/ccsc val `|查找 `config.yml` 中的设置项 ``,并显示其值 288 | |`/ccsc val `|设置 `config.yml` 中的设置项 `` 的值为 `` 289 | |`/ccsr [arguments-list]`|执行在 `commands.yml` 内定义的指令 ` ` 290 | 291 | 相关扩展内容请阅览[高级功能](#高级功能)。 292 | 293 | ### 注意 294 | 1. 使用指令修改指令组名 / 分支名 / 分支的 `format`,将会自动修改该组所有分支 / 该分支下的所有 `usage`。 295 | 1. 上表 `<>` 包围的参数为必填参数,`[]` 包围的为选填参数,实际使用指令并不需要添加该括号。 296 | 1. 一个参数的括号中的 `|` 表示该处有多种写法。例如`` 表示此处必须写 `global` 或 `personal` 中的一个。 297 | 1. 所有的 `index` 均从 `1` 开始。 298 | 299 | 300 | ## 权限节点 301 | |权限节点|作用 302 | |---|--- 303 | |`ccs.*`|所有 CCS 权限。 304 | |`ccs.version`|查看插件名、版本等信息 305 | |`ccs.config.debug`|开关调试模式 306 | |`ccs.config.reload`|重载 CCS 插件 307 | |`ccs.config.list`|查看所有已加载的指令组 308 | |`ccs.config.add`|添加一个指令组 309 | |`ccs.config.remove`|删除一个指令组 310 | |`ccs.config.group`|配置一个指令组的设置 311 | |`ccs.run.<指令组名>.<指令分支名>`|使用指令组 `指令组名` 中的 `指令分支名` 分支 312 | |`ccs.config.val`|查看和设置一个项目 313 | |`ccs.env.reload`|重载所有在线玩家的词库 314 | |`ccs.env.global`|编辑全局词库 315 | |`ccs.env.personal`|编辑玩家私人词库 316 | 317 | ## 画大饼 318 | 欢迎提交 `issue` 反馈你希望增加的功能。 319 | 320 | ### 已经开发完成的功能 321 | 下面枚举的功能将在下一个版本更新时发布。 322 | 暂无 323 | 324 | ### 正在开发的功能 325 | 1. 使用正则表达式检查变量名。 326 | 327 | ### 可能要增加的功能 328 | 下面枚举的功能我有相关想法,但是不知道实际使用性如何,需要大家的反馈才会决定是否要开发。 329 | 1. 允许直接使用 `/<指令组名> <分支名> [参数列表]` 的形式执行指令,无需使用 `/ccsr` 330 | 331 | ## 高级功能 332 | ### 词库机制 333 | 词库是记录变量的值的一张表。 334 | 335 | #### 词库种类 336 | `CCS` 的词库分四种: 337 | 338 | |词库|该表中的变量|该表中变量的特点 339 | |---|---|--- 340 | |`format`词库|在`format`中使用`{变量名}`定义的变量|在解析输入时建立,执行结束后便不存在了 341 | |私人词库|玩家自定义的变量|长期存在,会被写入插件数据文件中。每一个玩家都有一个独立的私人词库。 342 | |公共词库|自定义的变量|长期存在,会被写入插件数据文件中。 343 | |消息词库|语言文件中定义的变量|不建议使用这里的变量,因为其值不确定 344 | 345 | 使用这三个表中的变量的方式,都是 `{变量名}`。其中私人和公共词库存在的意义在于允许玩家自行定义一些不与 `format` 产生关联的变量。 346 | 347 | #### 相关指令 348 | |指令|作用 349 | |---|--- 350 | |`/ccse global`|查看全服词库中的变量 351 | |`/ccse personal`|查看私人词库中的变量 352 | |`/ccse reload`|重新载入所有在线玩家的词库 353 | |`/ccse set `|设置词库中的变量``为<`value>` 354 | |`/ccse remove `|删除词库中的变量`` 355 | |`/ccse clear`|删除词库中所有的变量 356 | 357 | #### 使用场景 358 | 插件 `PermissionEX` 对某一个权限组的操作指令都是以 `pex group <权限组名>` 开头的。我们可将这一串内容存入一个私人变量 `{prefix}` 中,下文便不需再写 `pex group <权限组名>`。例如: 359 | 360 | ````yaml 361 | commands: 362 | group: 363 | branch1: 364 | # ... 365 | actions: 366 | - 'ccse personal set prefix pex group {group_name}' # 在当前玩家的私人词库中设置变量 {prefix} 的值为 pex group {group_name} 367 | - '{prefix} add ' # 下文便可以直接引用 {prefix} 了 368 | - '{prefix} remove ' 369 | # - '{prefix} (其他的一些以 pex group {group_name} 开头的指令)' 370 | # ... 371 | ```` 372 | 373 | 由于变量 `{prefix}` 位于玩家的私人词库中,故同一时间不同玩家的 `{prefix}` 可以是不同的值。 374 | 375 | 更重要的是这个 `{prefix}` 还可以在其他 `actions` 中直接引用!例如: 376 | ````yaml 377 | commands: 378 | pexgroup: 379 | into: 380 | format: 'into {group_name}' 381 | actions: 382 | - 'ccse personal sey prefix pex group {group_name}' 383 | remain: 384 | format: '{remain}' 385 | actions: 386 | - '{prefix} {remain}' 387 | out: 388 | format: 'out' 389 | actions: 390 | - 'ccse personal remove prefix' 391 | ```` 392 | 你可以使用 `/ccsr pexgroup into <权限组名>` 先设定下文操作的权限组,随后的 `/ccsr pexgroup <任何内容>`,都将被自动转化为 `/pex group <那个权限组名> <刚才的任何内容>`。除非输入 `/ccsr pexgroup out` 取消。 393 | 394 | 这样使用,相当于进-出工作区,或者相当于先选择一个权限组,然后对其进行操作。 395 | 396 | 如果你有编程语言基础,很容易理解这个机制很像指针。先把指令中的关键字句设置到变量中,后文直接引用,可以更大程度地简化输入,灵活变通。 397 | 398 | #### 查找变量的方式 399 | 当发现使用变量后,`CCS` 会按照下面的顺序寻找变量的值: 400 | 1. 在 `format` 中查找变量,如果找到便使用该值。 401 | 1. 在玩家的私人词库中查找变量,如果找到便使用该值。 402 | 1. 在全服的公共词库中查找变量,如果找到便使用该值。 403 | 1. 在消息词库中查找变量,如果找到便使用该值。 404 | 405 | 若经历以上步骤还是无法找到变量,它将会保持 `{变量名}` 的原样。 406 | 407 | ### 模式匹配机制 408 | 409 | ### 强匹配与弱匹配 410 | 若输入 `/ccsr taixue work into test`,如果存在一下分支能匹配该输入: 411 | 412 | 1. `/ccsr taixue {remain}` 413 | 1. `/ccsr taixue work into {workspace}` 414 | 415 | 显然用户希望匹配的是第二种格式的输入。 416 | 417 | 如果配置文件 `config.yml` 中 `strong-match` 被设置为 `true`,则 `CCS` 会认为不使用 `{remain}` 的分支是 `强匹配分支`。如果能与用户输入匹配的分支有多个且只有一个强匹配分支,则会认为用户输入的是该分支。 418 | 419 | #### 匹配权限 420 | 匹配某一个指令分支的权限。默认是 `[ ccs.run.<该分支所处组名>.<分支名> ]`。 421 | 422 | 它作为选填项,可以在 `commands.yml` 的分支下添加: 423 | ````yaml 424 | commands: 425 | group: 426 | branch1: 427 | format: 'qwq' 428 | # actions: 429 | # - ... 430 | 431 | permissions: 432 | - ccs.run.group.branch1 433 | # ... 434 | branch2: 435 | format: 'qwq' 436 | # ... 437 | permissions: 438 | - ccs.run.group.branch2 439 | ```` 440 | 441 | 只有玩家具有某一个分支的所有匹配权限时,才能匹配该分支。 442 | 443 | 例如,若玩家只具有 `ccs.run.group.branch2` 权限,则输入 `/ccsr group qwq`,虽然两个分支都能匹配,但因为匹配 `branch1` 需要权限节点 `ccs.run.group.branch1`,而玩家缺少该节点,所以 CCS 并不会检查玩家的输入能否匹配 `branch1`。最终结果是玩家输入只能匹配一个分支 `branch2`,指令成功执行。 444 | 445 | 如果你希望对同一个指令格式,拥有不同权限的人可以互不影响地执行不同的分支,使用 `permissions` 加以区分是很好的办法。 446 | 447 | 值得一提的是,如果你修改了 `permissions`,将以你指明的那一串权限节点为准。 448 | 449 | #### 查找指令分支的方式 450 | 当用户输入 `/ccsr` 开头的指令,随后的第一个单词会被当做指令组名,剩余内容是参数列表。 451 | 452 | `CCS` 首先查找是否存在该指令组。若找到,便会使用当前参数列表匹配每一个分支的 `format`。能够匹配的那些分支在下文被称为 `可匹配分支`。 453 | 1. 若没有任何可匹配分支,则告诉玩家没有任何可匹配的分支,显示玩家有权限匹配的那些分支的 `usage`。 454 | 1. 若有多个可匹配分支,但玩家都没有权限匹配,则告诉玩家缺少权限节点。 455 | 1. 若有多个可匹配分支,但玩家有权限匹配的只有一个,则匹配成功,执行 `actions`。 456 | 1. 若有多个可匹配分支,玩家也有权限匹配其中的多个,则告诉玩家当前参数格式具有二义性,显示玩家有权限匹配的那些分支的 `usage`。 457 | 458 | ## 联系方式 459 | * QQ group(QQ 群): `1028582500` 460 | * Author(作者): `Chuanwise` 461 | * E-mail(邮箱): `chuanwise@qq.com` 462 | * 明城京联合太学,保留所有权利。 463 | * Taixue, All rights reserved. 464 | 465 | ## 更新日志 466 | ### 4.2 467 | 发布于 `2021年3月20日` 468 | 1. 新增强匹配弱匹配机制,让指令输入更便捷; 469 | 2. 取消了自动卸载词库模块,修复了无法开启调试模式的问题。 470 | 3. 修复了一些已知问题。 471 | 472 | ### 4.1 473 | 发布于 `2021年3月11日` 474 | 1. 删除了默认 `result`。不写 `result` 时,将不显示 `result` 内容。 475 | 1. 修复了一些已知问题。 476 | 477 | ### 4.0 478 | 发布于 `2021年3月6日` 479 | 1. 进一步完善了消息提示系统和 `zhcn.json` 汉化提示包。 480 | 1. 新增词库机制,让使用者可以更方便地简化输入指令。 481 | 1. 修改了指令执行机制,使得 `actions` 靠前的语句可以对靠后的语句产生影响。 482 | 1. 增加了对默认变量的说明。 483 | 1. 增加了 `actions` 中的脚本。 484 | 1. 增加了 `bypass` 的 `identify`。 485 | 486 | ### 3.0 487 | 发布于 `2021年2月25日` 488 | 1. 进一步完善了消息提示系统和 `zhcn.json` 汉化提示包。 489 | 1. 完善了大部分指令,支持使用指令编辑 `commands.yml`。 490 | 1. 允许在 `actions` 中使用 `@` 开头的特殊指令。 491 | 1. 增加了默认变量:`{player}`, `{displayName}`, `{world}`, `{group}` 和 `{UUID}`。 492 | 493 | ### 2.0 494 | 发布于 `2021年2月22日` 495 | 1. 完善了消息提示系统,使用了一些颜色让插件输出更加赏心悦目。 496 | 1. 完成了 `zhcn.json` 汉化提示包。 497 | 1. 从原本的单一指令系统,升级为指令分组,按格式匹配的系统。增加了自定义指令的自由度。 498 | 1. 优化了之前代码中的一些不合理的部分。 499 | 500 | ### 1.0 501 | 发布于 `2021年2月19日`。 502 | 503 | ## 其他发布地址 504 | * [MCBBS](https://www.mcbbs.net/thread-1172706-1-1.html) 505 | 506 | ## 感谢 507 | * `Favouritesc` 508 | 1. 引导我入门了最基础的 `Minecraft` 服务器技术。 509 | 1. 为 `CCS` 的改进提供了很多很好的建议。 510 | * `Eric`:[@ExerciseBook](https://github.com/ExerciseBook) 511 | * `One47` 512 | * `Coloryr` -------------------------------------------------------------------------------- /logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuanwise/CustomCommands/c35146258efc127bfd4ecc6bf340c30b44fa44d3/logo_small.png -------------------------------------------------------------------------------- /out/production/Custom-Commands/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: sun.plugin2.main.client.PluginMain 3 | 4 | -------------------------------------------------------------------------------- /out/production/Custom-Commands/commands.yml: -------------------------------------------------------------------------------- 1 | # see https://github.com/Chuanwise/CustomCommands 2 | 3 | commands: 4 | say: 5 | this: 6 | format: '{remain}' 7 | actions: 8 | - 'say {remain}' -------------------------------------------------------------------------------- /out/production/Custom-Commands/config.yml: -------------------------------------------------------------------------------- 1 | # see https://github.com/Chuanwise/CustomCommands 2 | 3 | config: 4 | lang: 'zhcn' 5 | debug: false 6 | max-iterations: 10 7 | auto-save: true -------------------------------------------------------------------------------- /out/production/Custom-Commands/lang/zhcn.json: -------------------------------------------------------------------------------- 1 | { 2 | "messageHead": "§7[§eCustom§7-§6Commands§7]§r ", 3 | "debugHead": "§7[§eCCS§7-§cDEBUG§7]§r ", 4 | "messageEndl": "\n{messageHead}", 5 | "wrongFormatForGroup": "指令组 {group} 格式错误", 6 | "wrongFormatForCommand": "指令 {command} 错误", 7 | "undefinedGroup": "未定义指令组 {group}", 8 | "matchesError": "在指令组 {group} 中的分支 {command} 的 matches 具有语法错误", 9 | "regexSyntaxError": "形式参数 {parameter} 的正则表达式 {regex} 语法错误:{exceptionMessage}", 10 | "illegalParameterName": "形式参数 {parameter} 名应该是仅由英文字母、数字和下划线组成的字符串", 11 | "illegalVariableName": "变量 {variable} 名应该是仅由英文字母、数字和下划线组成的字符串", 12 | "redefinedParameter": "形式参数 {parameter} 重定义", 13 | "extraArgs": "指令结尾未出现 remain 变量却包含额外的实参", 14 | "illegalIdentify": "发送指令的身份只能是 auto、console、bypass 或 player:{player}", 15 | "lackPermission": "缺少权限节点:{permission}", 16 | "parameterCannotBeBull": "形式参数 {parameter} 名应该是仅由英文字母、数字和下划线组成的字符串,不能为空", 17 | "defaultResultString": "指令已执行", 18 | "illegalCommandName": "非法的指令名:{command}(位于指令组 {group} 中)", 19 | "illegalGroupName": "非法的指令组名:{group}", 20 | "exceptionInLoadingGroup": "加载指令组 {group} 时出现异常:{exception},查看控制台输出以获得详细信息", 21 | "exceptionInLoadingCommand": "加载指令 {command} 时出现异常:{exception},查看控制台输出以获得详细信息", 22 | "exceptionInLoadingFile": "读取文件 {file} 时出现异常:{exception},查看控制台输出以获得详细信息", 23 | "exceptionInExecutingCommand": "执行指令 {command} 时出现异常:{exception},查看控制台输出以获得详细信息", 24 | "exceptionInParsingCommand": "解析指令 {command} 时出现异常:{exception},查看控制台输出以获得详细信息", 25 | "exceptionInSavingCommands": "保存 commands.yml 时出现异常:{exception},查看控制台输出以获得详细信息", 26 | "exceptionInMatchingArgument": "使用正则表达式 {regex} 检查形式参数 {parameter} 时出现异常:", 27 | "exceptionInSavingEnvironment": "保存环境文件 {file} 时出现异常:{exception},查看控制台输出以获得详细信息", 28 | "exceptionInLoadingEnvironment": "加载环境文件 {file} 时出现异常:{exception},查看控制台输出以获得详细信息", 29 | "unknownException": "未知错误导致异常: {exception}", 30 | "groupNotFound": "未找到指令组:{group}", 31 | "noMatchableCommand": "未在指令组 {group} 中找到能与当前参数列表匹配的指令", 32 | "multipleCommands": "有 {size} 个指令与之匹配,请修改设置以消除歧义。", 33 | "noPermissionToMatch": "你没有权限匹配这些指令", 34 | "loadedGroups": "当前已加载的指令组:", 35 | "noAnyLoadedGroup": "没有加载任何指令组", 36 | "loadedCommand": "当前在指令组 {group} 中加载的指令有:", 37 | "noAnyLoadedCommand": "没有任何自定义指令,或 commands.yml 尚未重载。若希望重载,请使用 /ccs reload", 38 | "redefinedGroups": "重定义指令组:{group}", 39 | "redefinedCommands": "在指令组 {group} 中重定义指令:{command}", 40 | "scriptSyntaxError": "脚本 {script} 语法错误", 41 | "illegalScript": "当前环境下无法使用脚本 {script}。可能是 identify 和脚本不匹配。", 42 | "unknownScript": "未知脚本类型:{script}", 43 | "groupAlreadyExist": "指令组 {group} 已经存在了!", 44 | "groupAdded": "成功新增指令组 {group}", 45 | "groupRemoved": "成功删除指令组 {group}", 46 | "groupRenamed": "成功修改指令组名为 {group}", 47 | "commandAdded": "成功在添加指令组 {group} 中添加指令 {command}", 48 | "commandAlreadyExist": "指令组 {group} 中已经存在指令 {command}", 49 | "commandNotFound": "没有在指令组 {group} 中找到指令 {command},请考虑使用 /ccsc group {group} 查看当前组中的所有指令", 50 | "commandRemoved": "成功删除指令组 {group} 中的指令 {command}", 51 | "commandRenamed": "成功修改指令组 {group} 中的指令名为 {command}", 52 | "identifySet": "成功设置执行身份为 {identify}", 53 | "formatSet": "成功设置解析格式为 {format}", 54 | "illegalFormat": "解析格式 {format} 中存在语法错误", 55 | "resultSet": "成功设置结果信息为 {result}", 56 | "actionAdded": "成功追加执行指令 {action}", 57 | "actionNotFound": "没有在指令组 {group} 中的分支 {command} 下找到执行指令 {action},请考虑使用 /ccsr group {group} command {command} 以查看当前分支的信息", 58 | "actionRemoved": "成功移除执行指令 {action}", 59 | "actionsCleared": "成功清除执行指令", 60 | "actionsSet": "成功设置执行指令为 {action}", 61 | "actionEdited": "成功编辑第 {index} 条执行指令为 {action}", 62 | "illegalIndex": "错误的序号值:{index},它应该是处于 [1, {top}] 的整数", 63 | "permissionAlreadyExist": "指令分支 {command} 中已经存在必要权限 {permission}", 64 | "permissionAdded": "成功在指令分支 {command} 中添加必要权限 {permission}", 65 | "permissionNotFound": "没有在指令组 {group} 中的分支 {command} 下找到必要权限 {permission},请考虑使用 /ccsr group {group} command {command} 以查看当前分支的信息", 66 | "permissionRemoved": "成功删除指令分支 {command} 中的必要权限 {permission}", 67 | "permissionsCleared": "成功清空指令分支 {command} 中的必要权限。请注意 CustomCommands 不会自动添加关键权限 ccs.run.{group}.{command},任何人都可以匹配并执行当前分支 {command}。如需要添加该项,请考虑使用 /ccsc group {group} permissions default", 68 | "permissionsSet": "成功设置指令分支 {command} 中的必要权限为 {permission}", 69 | "permissionEdited": "成功编辑第 {index} 条必要权限为 {action}", 70 | "setPermissionsToDefault": "成功设置指令分支 {command} 中的必要权限为默认的 ccs.run.{group}.{command}", 71 | "groupSummary": "{group} ({size} 个指令分支)", 72 | "groupDetailsTitle": "--- 指令组:{group} ({size} 个指令分支) ---", 73 | "commandSummary": "{command} >> {format}, {size} actions", 74 | "commandDetailsTitle": "--- {command} ---", 75 | "commandsSaved": "成功保存指令配置文件", 76 | "operatorMustBePlayer": "当前操作只能由玩家发起", 77 | "wrongEnvironment": "{file} 不是合法的变量表文件", 78 | "cannotLoadEnvironment": "无法加载变量表:{file}", 79 | "unknownUUID": "未知玩家:UUID:{UUID}", 80 | "environmentLoaded": "成功加载环境文件 {file}", 81 | "variableSet": "变量 {variable} 已被设置为值 {value}", 82 | "variableNotFound": "未找到变量 {variable}", 83 | "variableRemoved": "成功删除变量 {variable}", 84 | "environmentCleared": "已清除环境中的所有变量", 85 | "loadingEnvironment": "正在加载环境 {environment}(位于文件 {file} 中)", 86 | "variableShouldBeString": "变量 {variable} 应该是一个字符串", 87 | "failToLoadEnvironment": "加载文件 {file} 中的环境失败", 88 | "loadedVariableTitle": "--- 环境 {environment} 中加载的变量 ({size} 个)---", 89 | "noAnyLoadedVariable": "该环境中没有加载任何变量", 90 | "onlinePlayerEnvironmentsLoaded": "已加载所有在线玩家的环境" 91 | } -------------------------------------------------------------------------------- /out/production/Custom-Commands/plugin.yml: -------------------------------------------------------------------------------- 1 | name: Custom-Commands 2 | main: io.github.taixue.plugin.customcommands.CustomCommandPlugin 3 | author: Chuanwise 4 | version: 4.0 5 | website: https://github.com/Chuanwise/CustomCommands/ 6 | 7 | # softdepend: [PlaceholderAPI] 8 | 9 | commands: 10 | customcommands: 11 | description: Generic Custom-commands command 12 | aliases: [ccs] 13 | usage: | 14 | Usage: 15 | /ccs reload reload all configurations 16 | /ccs version show version and some other information 17 | /ccs debug enable or disable debug mode 18 | /ccs sames with /ccs 19 | customcommandsconfig: 20 | description: Generic Custom-commands command for configuring 21 | aliases: [ccsc, ccsconfig] 22 | usage: | 23 | Usage: 24 | /ccsc val [set-to] get or set a variable in config 25 | customcommandsrun: 26 | description: Run configured commands 27 | aliases: [ccsr, ccsrun] 28 | usage: | 29 | Usage: 30 | /ccsr [arguments-list] 31 | customcommandsenvironment: 32 | description: Set, edit or remove a variable 33 | aliases: [ccse, ccsenv] 34 | usage: | 35 | Usage: 36 | /ccse set 37 | /ccse remove 38 | /ccse clear 39 | /ccse reload 40 | 41 | permissions: 42 | ccs.*: 43 | default: op 44 | description: Give players with op everything by default 45 | children: 46 | ccs.run.*: true 47 | ccs.version: 48 | default: true 49 | description: Permission to see version, name and other information of CustomCommands 50 | ccs.debug: 51 | default: op 52 | description: enable or disable debug mode 53 | ccs.reload: 54 | default: op 55 | description: reload all configurations 56 | ccs.config.val.set: 57 | default: op 58 | description: set value of variable in config.yml 59 | ccs.config.val.look: 60 | default: op 61 | description: look value of variable in config.yml 62 | ccs.env.global: 63 | default: op 64 | ccs.env.personal: 65 | default: true 66 | ccs.env.reload: 67 | default: op 68 | 69 | -------------------------------------------------------------------------------- /out/production/CustomCommands/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: sun.plugin2.main.client.PluginMain 3 | 4 | -------------------------------------------------------------------------------- /out/production/CustomCommands/config.yml: -------------------------------------------------------------------------------- 1 | config: 2 | lang: 'zhcn' 3 | debug: false 4 | max-iterations: 10 -------------------------------------------------------------------------------- /out/production/CustomCommands/plugin.yml: -------------------------------------------------------------------------------- 1 | name: Custom-Commands 2 | main: io.github.taixue.plugin.customcommands.CustomCommandPlugin 3 | author: Chuanwise 4 | version: 1 5 | 6 | commands: 7 | customcommands: 8 | description: Generic Custom-commands command 9 | aliases: [ccs] 10 | usage: | 11 | Usage: 12 | /ccs reload reload all configurations 13 | /ccs version show version and some other information 14 | /ccs debug enable or disable debug mode 15 | /ccs sames with /ccs 16 | customcommandsconfig: 17 | description: Generic Custom-commands command for configuring 18 | aliases: [ccsc, ccsconfig] 19 | usage: | 20 | Usage: 21 | /ccsc val [set-to] get or set a variable in config 22 | customcommandsrun: 23 | description: Run configured commands 24 | aliases: [ccsr, ccsrun] 25 | usage: | 26 | Usage: 27 | /ccsr [arguments-list] 28 | 29 | permissions: 30 | ccs.*: 31 | default: op 32 | description: Give players with op everything by default 33 | children: 34 | ccs.run.*: true 35 | ccs.debug: 36 | default: op 37 | description: open or close debug 38 | ccs.reload: 39 | default: op 40 | description: reload all configurations 41 | ccs.config.val: 42 | default: op 43 | children: 44 | ccs.config.val.set: true 45 | ccs.config.val.look: true 46 | ccs.config.val.set: 47 | default: op 48 | description: set value of variable in config.yml 49 | ccs.config.val.look: 50 | default: op 51 | description: look value of variable in config.yml 52 | 53 | -------------------------------------------------------------------------------- /out/production/CustomCommands/resources/commands.yml: -------------------------------------------------------------------------------- 1 | # see https://github.com/Chuanwise/CustomCommands 2 | commands: 3 | # Permission to execute a command is: ccs.run. 4 | 5 | # (required) 6 | # : 7 | broadcast: 8 | # (required) 9 | # format: rule to parser command inputted by command sender 10 | # You can define some variable in here, like: {variable-name} 11 | # a legal variable name should only consist of English alphas, digits and underlines. 12 | # the {remain} is a special variable: it's optional, can only appear at the end of 13 | # format string when using it. 14 | # 15 | format: '{remain}' 16 | 17 | # (optional) 18 | # usage: a string describing usage of this command. 19 | # The usage will be send to command sender when he input wrong command, 20 | # If usage doesn't exist, it'll be "/ccsr " instead. 21 | 22 | # usage: '(unfinished usage string)' 23 | 24 | # (required) 25 | # actions: commands will be executed after a user has permission "ccs.run." 26 | # input correct command. 27 | # [Warning] CustomCommands allow you to input some ccsr command in actions, 28 | # Sometime It maybe cause some loop, which may make server shutdown. 29 | # So you must design actions carefully when actions include other ccsr command. 30 | actions: 31 | - 'pex user {argument_name} group set {remain}' 32 | - 'you are ugly!' 33 | 34 | # (optional) 35 | # identify: identify of action commands sender, is "auto" or "console" 36 | # "auto" means the action commands sender is the same with ccsr command sender. 37 | identify: console -------------------------------------------------------------------------------- /out/production/CustomCommands/resources/lang/zhcn.yaml: -------------------------------------------------------------------------------- 1 | # The lang.yml is unfinished so it's useless temporarily. 2 | 3 | lang: 4 | message-head: '[CustomCommands] ' 5 | no-any-loaded-commands: '没有任何自定义指令,或 commands.yml 尚未重载。若希望重载,请使用 /ccs reload' 6 | wrong-format-for-commands-file: '自定义指令 {command_name} 错误:command 应该是 MemorySection' 7 | undefined-command: '未定义指令:{command_name}' 8 | wrong-format-for-commands-para: '形式参数 {para_name} 名应该是仅由英文字母、数字和下划线组成的字符串' 9 | extra-args: '指令结尾未出现 remain 变量却包含额外的实参' 10 | wrong-identify: '发送指令的身份只能是 auto 或 console' -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.taixue 8 | customcommands 9 | 4.0 10 | 11 | 12 | 13 | com.alibaba 14 | fastjson 15 | 1.2.75 16 | 17 | 18 | 19 | org.bukkit 20 | bukkit 21 | 1.15.1-R0.1-SNAPSHOT 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/java/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: sun.plugin2.main.client.PluginMain 3 | 4 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/Plugin.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands; 2 | 3 | import org.bukkit.ChatColor; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.event.EventHandler; 6 | import org.bukkit.event.Listener; 7 | import org.bukkit.event.server.PluginEnableEvent; 8 | import org.bukkit.plugin.java.JavaPlugin; 9 | import org.taixue.customcommands.commandexecutor.CCSCCommandExecutor; 10 | import org.taixue.customcommands.commandexecutor.CCSCommandExecutor; 11 | import org.taixue.customcommands.commandexecutor.CCSECommandExecutor; 12 | import org.taixue.customcommands.commandexecutor.CCSRCommandExecutor; 13 | import org.taixue.customcommands.config.CommandsConfig; 14 | import org.taixue.customcommands.config.PluginConfig; 15 | import org.taixue.customcommands.language.Environment; 16 | import org.taixue.customcommands.language.Messages; 17 | import org.taixue.customcommands.util.Files; 18 | import org.taixue.customcommands.util.Paths; 19 | import org.yaml.snakeyaml.error.YAMLException; 20 | 21 | import java.io.File; 22 | 23 | public class Plugin extends JavaPlugin { 24 | public static final String VERSION = "4.2"; 25 | public static final String NAME = "CustomCommands"; 26 | public static final String AUTHOR = "Chuanwise"; 27 | public static final String ORGANIZATION = "Taixue"; 28 | public static final String GITHUB = "https://github.com/Chuanwise/CustomCommands"; 29 | public static final String MCBBS = "https://www.mcbbs.net/thread-1172706-1-1.html"; 30 | public static final String QQ_GROUP = "1028582500"; 31 | 32 | public static Plugin plugin; 33 | 34 | public static PluginConfig pluginConfig; 35 | public static CommandsConfig commandsConfig; 36 | 37 | public static boolean debug = false; 38 | public static boolean autoSave = true; 39 | public static boolean strongMath = true; 40 | public static int waitForUnload = 5 * 60000; 41 | 42 | public static final CCSCommandExecutor CCS_COMMAND_EXECUTOR = new CCSCommandExecutor(); 43 | public static final CCSCCommandExecutor CCSC_COMMAND_EXECUTOR = new CCSCCommandExecutor(); 44 | public static final CCSRCommandExecutor CCSR_COMMAND_EXECUTOR = new CCSRCommandExecutor(); 45 | public static final CCSECommandExecutor CCSE_COMMAND_EXECUTOR = new CCSECommandExecutor(); 46 | 47 | private static File configFile; 48 | private static File commandsFile; 49 | 50 | public static void load(Plugin plugin) { 51 | Plugin.plugin = plugin; 52 | Messages.setLogger(Plugin.plugin.getLogger()); 53 | setCommandExecutors(); 54 | 55 | if (!Plugin.plugin.getDataFolder().exists() && !Plugin.plugin.getDataFolder().mkdirs()) { 56 | Messages.severeString("Directory " + Plugin.plugin.getDataFolder().getName() + " doesn't exist and cannot be created!"); 57 | return; 58 | } 59 | 60 | if (!checkFrontPlugins()) { 61 | Messages.severeString("Lack some front plugins, can not load" + NAME + "."); 62 | return; 63 | } 64 | 65 | configFile = new File(Plugin.plugin.getDataFolder(), Paths.CONFIG); 66 | commandsFile = new File(Plugin.plugin.getDataFolder(), Paths.COMMANDS); 67 | 68 | Messages.infoString("----------[" + NAME + " " + VERSION +"]----------"); 69 | Messages.hello(); 70 | Messages.infoString("---------- loading ----------"); 71 | Messages.infoString(Messages.blue("loading config...")); 72 | loadConfig(); 73 | Messages.infoString(Messages.blue("loading language...")); 74 | loadLanguage(); 75 | Messages.infoString(Messages.blue("loading commands...")); 76 | loadCommands(); 77 | // Messages.infoString(Messages.blue("registing events...")); 78 | // registerEvents(); 79 | reloadEnvironment(); 80 | Messages.infoString("------ load configurations completely :) ------"); 81 | } 82 | 83 | private static boolean checkFrontPlugins() { 84 | return true; 85 | } 86 | 87 | public static void reload() { 88 | load(plugin); 89 | } 90 | 91 | public static void loadConfig() { 92 | try { 93 | if (!configFile.exists()) { 94 | plugin.saveDefaultConfig(); 95 | } 96 | pluginConfig = new PluginConfig(configFile, "config"); 97 | debug = ((Boolean) pluginConfig.get("debug", false)); 98 | autoSave = ((Boolean) pluginConfig.get("auto-save", true)); 99 | strongMath = ((Boolean) pluginConfig.get("strong-match", true)); 100 | waitForUnload = ((Integer) pluginConfig.get("wait-for-unload", 5 * 60000)); 101 | } 102 | catch (YAMLException exception) { 103 | exception.printStackTrace(); 104 | } 105 | } 106 | 107 | private static boolean loadLanguage() { 108 | Messages.setLogger(Plugin.plugin.getLogger()); 109 | return Messages.setLanguage(((String) pluginConfig.get("lang", "en"))); 110 | } 111 | 112 | public static void loadCommands() { 113 | if (!commandsFile.exists()) { 114 | if (!Files.fileCopy(Paths.COMMANDS, commandsFile)) { 115 | Messages.severeString("cannot create the default commands.yml"); 116 | } 117 | } 118 | commandsConfig = new CommandsConfig(); 119 | } 120 | 121 | public static void saveConfigFile() { 122 | try { 123 | pluginConfig.save(); 124 | } 125 | catch (Exception exception) { 126 | Messages.severeString(exception + " at saving config.yml"); 127 | exception.printStackTrace(); 128 | } 129 | } 130 | 131 | public static void saveCommands() { 132 | try { 133 | commandsConfig.save(); 134 | } 135 | catch (Exception exception) { 136 | Messages.severeString(exception + " at saving commands.yml"); 137 | exception.printStackTrace(); 138 | } 139 | } 140 | 141 | public static void close() { 142 | Messages.infoString("----------[" + NAME + " " + VERSION +"]----------"); 143 | Messages.infoString("\033[1;33msaving config.yml \033[0m"); 144 | saveConfigFile(); 145 | Messages.infoString("\033[1;33msaving commands.yml \033[0m"); 146 | saveCommands(); 147 | Messages.infoString("------ all configuration saved ------"); 148 | Messages.hello(); 149 | Messages.infoString("------ Think you for using CustomCommands, see you :) ------"); 150 | } 151 | 152 | public static void loadOnlinePlayerEnvironment() { 153 | for (Player player: plugin.getServer().getOnlinePlayers()) { 154 | Messages.infoString(Messages.yellow("loading player: " + player.getName() + "'s environment...")); 155 | Environment.load(player); 156 | } 157 | } 158 | 159 | public static void loadGlobalEnvironment() { 160 | Messages.infoString(Messages.yellow("loading global environment...")); 161 | } 162 | 163 | private static void setCommandExecutors() { 164 | plugin.getCommand("customcommandsrun").setExecutor(CCSR_COMMAND_EXECUTOR); 165 | plugin.getCommand("customcommandsconfig").setExecutor(CCSC_COMMAND_EXECUTOR); 166 | plugin.getCommand("customcommands").setExecutor(CCS_COMMAND_EXECUTOR); 167 | plugin.getCommand("customcommandsenvironment").setExecutor(CCSE_COMMAND_EXECUTOR); 168 | } 169 | 170 | public static void reloadEnvironment() { 171 | Environment.clear(); 172 | Messages.infoString(Messages.blue("loading global environments...")); 173 | loadGlobalEnvironment(); 174 | Messages.infoString(Messages.blue("loading online players' environments...")); 175 | loadOnlinePlayerEnvironment(); 176 | } 177 | 178 | @Override 179 | public void onEnable() { 180 | load(this); 181 | } 182 | 183 | @Override 184 | public void onDisable() { 185 | close(); 186 | } 187 | } -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/commandexecutor/CCSCCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.commandexecutor; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.taixue.customcommands.Plugin; 5 | import org.taixue.customcommands.customcommand.Group; 6 | import org.taixue.customcommands.language.Messages; 7 | import org.taixue.customcommands.util.Commands; 8 | import org.taixue.customcommands.script.Strings; 9 | import org.bukkit.command.Command; 10 | import org.bukkit.command.CommandExecutor; 11 | import org.bukkit.command.CommandSender; 12 | 13 | import java.util.Objects; 14 | 15 | 16 | public class CCSCCommandExecutor implements CommandExecutor { 17 | 18 | @Override 19 | public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) { 20 | String permissionNode; 21 | if (strings.length == 0) { 22 | return false; 23 | } 24 | 25 | if (strings[0].equalsIgnoreCase("val") && strings.length > 1) { 26 | permissionNode = "ccs.config.val"; 27 | Messages.setVariable("permission", permissionNode); 28 | if (commandSender.hasPermission(permissionNode)) { 29 | return val(commandSender, command, s, strings); 30 | } 31 | else { 32 | Messages.sendMessage(commandSender, "lackPermission"); 33 | return true; 34 | } 35 | } 36 | 37 | if (strings[0].equalsIgnoreCase("list")) { 38 | permissionNode = "ccs.config.list"; 39 | Messages.setVariable("permission", permissionNode); 40 | if (commandSender.hasPermission(permissionNode)) { 41 | return list(commandSender, command, s, strings); 42 | } 43 | else { 44 | Messages.sendMessage(commandSender, "lackPermission"); 45 | return true; 46 | } 47 | } 48 | 49 | if (strings[0].equalsIgnoreCase("save") && strings.length == 1) { 50 | saveCommands(commandSender); 51 | Messages.sendMessage(commandSender, "commandsSaved"); 52 | return true; 53 | } 54 | 55 | if (strings[0].equalsIgnoreCase("add")) { 56 | permissionNode = "ccs.config.add"; 57 | Messages.setVariable("permission", permissionNode); 58 | if (commandSender.hasPermission(permissionNode)) { 59 | boolean result = add(commandSender, command, s, strings); 60 | if (result && Plugin.autoSave) { 61 | saveCommands(commandSender); 62 | } 63 | return result; 64 | } 65 | else { 66 | Messages.sendMessage(commandSender, "lackPermission"); 67 | return true; 68 | } 69 | } 70 | 71 | if (strings[0].equalsIgnoreCase("group")) { 72 | permissionNode = "ccs.config.group"; 73 | Messages.setVariable("permission", permissionNode); 74 | if (commandSender.hasPermission(permissionNode)) { 75 | boolean result = group(commandSender, command, s, strings); 76 | if (result && Plugin.autoSave) { 77 | saveCommands(commandSender); 78 | } 79 | return result; 80 | 81 | } 82 | else { 83 | Messages.sendMessage(commandSender, "lackPermission"); 84 | return true; 85 | } 86 | } 87 | 88 | if (strings[0].equalsIgnoreCase("remove")) { 89 | permissionNode = "ccs.config.remove"; 90 | Messages.setVariable("permission", permissionNode); 91 | if (commandSender.hasPermission(permissionNode)) { 92 | boolean result = remove(commandSender, command, s, strings); 93 | if (result && Plugin.autoSave) { 94 | saveCommands(commandSender); 95 | } 96 | return result; 97 | 98 | } 99 | else { 100 | Messages.sendMessage(commandSender, "lackPermission"); 101 | return true; 102 | } 103 | } 104 | 105 | return false; 106 | } 107 | 108 | private boolean list(CommandSender commandSender, Command command, String s, String[] strings) { 109 | if (strings.length == 1) { 110 | if (Plugin.commandsConfig.getGroups().isEmpty()) { 111 | Messages.sendMessage(commandSender, "noAnyLoadedGroup"); 112 | } 113 | else { 114 | Messages.sendMessage(commandSender, "loadedGroups"); 115 | for (Group group: Plugin.commandsConfig.getGroups()) { 116 | Messages.setVariable("group", group.getName()); 117 | Messages.setVariable("size", group.getCommands().size()); 118 | Messages.sendMessage(commandSender, "groupSummary"); 119 | } 120 | } 121 | return true; 122 | } 123 | else { 124 | return false; 125 | } 126 | } 127 | 128 | private boolean val(CommandSender commandSender, Command command, String s, String[] strings) { 129 | String valName = strings[1]; 130 | switch (strings.length) { 131 | case 2: 132 | Messages.setVariable("permission", "ccs.config.val.look"); 133 | if (commandSender.hasPermission("ccs.config.val.look")) { 134 | Object object = Plugin.pluginConfig.get(valName, null); 135 | if (Objects.isNull(object)) { 136 | Messages.sendMessage(commandSender, "wrongConfigItem"); 137 | } 138 | else { 139 | Messages.sendMessage(commandSender, valName + " : " + object); 140 | } 141 | } else { 142 | Messages.sendMessage(commandSender, "lackPermission"); 143 | } 144 | return true; 145 | case 3: 146 | Messages.setVariable("permission", "ccs.config.val.set"); 147 | if (commandSender.hasPermission("ccs.config.val.set")) { 148 | Plugin.pluginConfig.set(valName, strings[2]); 149 | Plugin.saveConfigFile(); 150 | Messages.sendMessage(commandSender, valName + " set to " + strings[2] + " completely!"); 151 | Plugin.loadConfig(); 152 | } else { 153 | Messages.sendMessage(commandSender, "lackPermission"); 154 | } 155 | return true; 156 | default: 157 | return false; 158 | } 159 | } 160 | 161 | private boolean add(CommandSender commandSender, Command command, String s, String[] strings) { 162 | if (strings.length == 2) { 163 | String groupName = strings[1]; 164 | Messages.setVariable("group", groupName); 165 | if (Strings.isLegalGroupName(groupName)) { 166 | if (Objects.isNull(Plugin.commandsConfig.getGroup(groupName))) { 167 | Group group = new Group(groupName); 168 | Plugin.commandsConfig.addGroup(group); 169 | Messages.sendMessage(commandSender, "groupAdded"); 170 | } else { 171 | Messages.sendMessage(commandSender, "groupAlreadyExist"); 172 | } 173 | } 174 | else { 175 | Messages.sendMessage(commandSender, "illegalGroupName"); 176 | } 177 | return true; 178 | } 179 | return false; 180 | } 181 | 182 | private boolean remove(CommandSender commandSender, Command command, String s, String[] strings) { 183 | if (strings.length == 2) { 184 | String groupName = strings[1]; 185 | Messages.setVariable("group", groupName); 186 | if (Objects.isNull(Plugin.commandsConfig.getGroup(groupName))) { 187 | Messages.sendMessage(commandSender, "groupNotFound"); 188 | } 189 | else { 190 | Plugin.commandsConfig.removeGroup(groupName); 191 | Messages.sendMessage(commandSender, "groupRemoved"); 192 | } 193 | return true; 194 | } 195 | return false; 196 | } 197 | 198 | private boolean group(CommandSender commandSender, Command command, String s, String[] strings) { 199 | if (strings.length < 2) { 200 | return false; 201 | } 202 | String groupName = strings[1]; 203 | Group group = Plugin.commandsConfig.getGroup(groupName); 204 | Messages.setVariable("group", groupName); 205 | if (Objects.isNull(group)) { 206 | Messages.sendMessage(commandSender, "groupNotFound"); 207 | return true; 208 | } 209 | 210 | if (strings.length == 2) { 211 | showGroupDetail(commandSender, group); 212 | return true; 213 | } 214 | 215 | if (strings.length == 3) { 216 | return false; 217 | } 218 | 219 | String firstOperator = strings[2]; 220 | String commandName = strings[3]; 221 | Messages.setVariable("command", commandName); 222 | org.taixue.customcommands.customcommand.Command currentCommand = group.getCommand(commandName); 223 | 224 | if (firstOperator.equalsIgnoreCase("add") && strings.length == 4) { 225 | if (Strings.isLegalCommandName(commandName)) { 226 | if (Objects.isNull(currentCommand)) { 227 | 228 | currentCommand = Commands.getDefaultCommand(group, commandName); 229 | group.addCommand(currentCommand); 230 | Messages.sendMessage(commandSender, "commandAdded"); 231 | } else { 232 | Messages.sendMessage(commandSender, "commandAlreadyExist"); 233 | } 234 | } else { 235 | Messages.sendMessage(commandSender, "illegalCommandName"); 236 | } 237 | return true; 238 | } 239 | 240 | if (firstOperator.equalsIgnoreCase("remove") && strings.length == 4) { 241 | if (Objects.isNull(currentCommand)) { 242 | Messages.sendMessage(commandSender, "commandNotFound"); 243 | } 244 | else { 245 | group.removeCommand(commandName); 246 | Messages.sendMessage(commandSender, "commandRemoved"); 247 | } 248 | return true; 249 | } 250 | 251 | if (firstOperator.equalsIgnoreCase("rename") && strings.length == 4) { 252 | groupName = strings[3]; 253 | Messages.setVariable("group", groupName); 254 | if (Objects.isNull(Plugin.commandsConfig.getGroup(groupName))) { 255 | if (Strings.isLegalGroupName(groupName)) { 256 | group.setName(groupName); 257 | Messages.sendMessage(commandSender, "groupRenamed"); 258 | } 259 | else { 260 | Messages.sendMessage(commandSender, "illegalGroupName"); 261 | } 262 | } 263 | else { 264 | Messages.setVariable("group", "groupAlreadyExist"); 265 | } 266 | return true; 267 | } 268 | 269 | if (firstOperator.equalsIgnoreCase("command")) { 270 | if (Objects.isNull(currentCommand)) { 271 | Messages.sendMessage(commandSender, "commandNotFound"); 272 | return true; 273 | } 274 | if (strings.length == 4) { 275 | showCommandDetail(commandSender, currentCommand); 276 | return true; 277 | } 278 | 279 | String secondOperator = strings[4]; 280 | if (secondOperator.equalsIgnoreCase("rename") && strings.length == 6) { 281 | commandName = strings[5]; 282 | Messages.setVariable("command", commandName); 283 | if (Objects.isNull(group.getCommand(commandName))) { 284 | if (Strings.isLegalCommandName(commandName)) { 285 | currentCommand.setName(commandName); 286 | Messages.sendMessage(commandSender, "commandRenamed"); 287 | } 288 | else { 289 | Messages.sendMessage(commandSender, "illegalCommandName"); 290 | } 291 | } 292 | else { 293 | Messages.sendMessage(commandSender, "commandAlreadyExist"); 294 | } 295 | return true; 296 | } 297 | 298 | if (secondOperator.equalsIgnoreCase("identify") && strings.length == 6) { 299 | boolean set = false; 300 | String identify = strings[5]; 301 | Messages.setVariable("identify", identify); 302 | 303 | if (identify.equalsIgnoreCase("auto")) { 304 | currentCommand.setIdentify(org.taixue.customcommands.customcommand.Command.Identify.AUTO); 305 | set = true; 306 | } 307 | if (identify.equalsIgnoreCase("console")) { 308 | currentCommand.setIdentify(org.taixue.customcommands.customcommand.Command.Identify.CONSOLE); 309 | set = true; 310 | } 311 | if (identify.equalsIgnoreCase("bypass")) { 312 | currentCommand.setIdentify(org.taixue.customcommands.customcommand.Command.Identify.BYPASS); 313 | set = true; 314 | } 315 | if (set) { 316 | Messages.sendMessage(commandSender, "identifySet"); 317 | } 318 | else { 319 | Messages.sendMessage(commandSender, "illegalIdentify"); 320 | } 321 | return false; 322 | } 323 | 324 | if (secondOperator.equalsIgnoreCase("result")) { 325 | String result = Strings.getRemainString(strings, 5); 326 | Messages.setVariable("result", result); 327 | currentCommand.setResultString(result); 328 | Messages.sendMessage(commandSender, "resultSet"); 329 | } 330 | 331 | if (secondOperator.equalsIgnoreCase("usage")) { 332 | String usage = Strings.getRemainString(strings, 5); 333 | Messages.setVariable("usage", usage); 334 | currentCommand.setUsageString(usage); 335 | Messages.sendMessage(commandSender, "usageSet"); 336 | } 337 | 338 | if (secondOperator.equalsIgnoreCase("format")) { 339 | String format = Strings.getRemainString(strings, 5); 340 | String elderFormat = currentCommand.getFormat(); 341 | 342 | Messages.setVariable("format", format); 343 | currentCommand.setFormat(format); 344 | if (currentCommand.isLegalParameters()) { 345 | Messages.sendMessage(commandSender, "formatSet"); 346 | } 347 | else { 348 | Messages.sendMessage(commandSender, "illegalFormat"); 349 | currentCommand.setFormat(elderFormat); 350 | } 351 | return true; 352 | } 353 | 354 | if (secondOperator.equalsIgnoreCase("actions") && strings.length >= 6) { 355 | String lastOperator = strings[5]; 356 | String action; 357 | 358 | if (lastOperator.equalsIgnoreCase("edit") && strings.length >= 7) { 359 | int index = Strings.getIndex(commandSender, strings[6], currentCommand.getActions().length); 360 | if (index == -1) { 361 | return true; 362 | } 363 | index--; 364 | action = Strings.getRemainString(strings, 7); 365 | 366 | Messages.setVariable("action", action); 367 | 368 | currentCommand.getActions()[index] = action; 369 | Messages.sendMessage(commandSender, "actionEdited"); 370 | return true; 371 | } 372 | 373 | if (lastOperator.equalsIgnoreCase("clear") && strings.length == 6) { 374 | currentCommand.setActions(new String[0]); 375 | Messages.sendMessage(commandSender, "actionsCleared"); 376 | return true; 377 | } 378 | 379 | action = Strings.getRemainString(strings, 6); 380 | Messages.setVariable("action", action); 381 | 382 | if (lastOperator.equalsIgnoreCase("add")) { 383 | currentCommand.addAction(action); 384 | Messages.sendMessage(commandSender, "actionAdded"); 385 | return true; 386 | } 387 | 388 | if (lastOperator.equalsIgnoreCase("remove")) { 389 | if (currentCommand.containsAction(action)) { 390 | currentCommand.removeAction(action); 391 | Messages.sendMessage(commandSender, "actionRemoved"); 392 | } 393 | else { 394 | Messages.sendMessage(commandSender, "actionNotFound"); 395 | } 396 | return true; 397 | } 398 | 399 | if (lastOperator.equalsIgnoreCase("set")) { 400 | currentCommand.setActions(new String[]{action}); 401 | Messages.sendMessage(commandSender, "actionsSet"); 402 | return true; 403 | } 404 | } 405 | 406 | if (secondOperator.equalsIgnoreCase("permissions") && strings.length >= 6) { 407 | String lastOperator = strings[5]; 408 | String permission; 409 | 410 | if (lastOperator.equalsIgnoreCase("edit") && strings.length == 8) { 411 | int index = Strings.getIndex(commandSender, strings[6], currentCommand.getPermissions().length); 412 | if (index == -1) { 413 | return true; 414 | } 415 | index--; 416 | 417 | permission = strings[7]; 418 | Messages.setVariable("permission", permission); 419 | 420 | currentCommand.getPermissions()[index] = permission; 421 | Messages.sendMessage(commandSender, "permissionEdited"); 422 | return true; 423 | } 424 | 425 | if (lastOperator.equalsIgnoreCase("clear") && strings.length == 6) { 426 | currentCommand.setPermissions(new String[0]); 427 | Messages.sendMessage(commandSender, "permissionsCleared"); 428 | return true; 429 | } 430 | 431 | if (lastOperator.equalsIgnoreCase("default") && strings.length == 6) { 432 | currentCommand.setPermissions(new String[]{"ccs.run." + currentCommand.getGroup() + "." + currentCommand.getName()}); 433 | Messages.sendMessage(commandSender, "setPermissionsToDefault"); 434 | return true; 435 | } 436 | 437 | permission = strings[6]; 438 | Messages.setVariable("permission", permission); 439 | 440 | if (lastOperator.equalsIgnoreCase("add")) { 441 | if (currentCommand.containsPermission(permission)) { 442 | Messages.sendMessage(commandSender, "permissionAlreadyExist"); 443 | } 444 | else { 445 | currentCommand.addPermission(permission); 446 | Messages.sendMessage(commandSender, "permissionAdded"); 447 | } 448 | return true; 449 | } 450 | 451 | if (lastOperator.equalsIgnoreCase("remove")) { 452 | if (currentCommand.containsPermission(permission)) { 453 | currentCommand.removePermissions(permission); 454 | Messages.sendMessage(commandSender, "permissionRemoved"); 455 | } 456 | else { 457 | Messages.sendMessage(commandSender, "permissionNotFound"); 458 | } 459 | return true; 460 | } 461 | 462 | if (lastOperator.equalsIgnoreCase("set")) { 463 | currentCommand.setPermissions(new String[]{permission}); 464 | Messages.sendMessage(commandSender, "permissionsSet"); 465 | } 466 | } 467 | } 468 | 469 | return false; 470 | } 471 | 472 | private void showGroupDetail(CommandSender sender, Group group) { 473 | Messages.setVariable("group", group.getName()); 474 | int size = group.getCommands().size(); 475 | Messages.setVariable("size", size); 476 | 477 | Messages.sendMessage(sender, "groupDetailsTitle"); 478 | if (size == 0) { 479 | Messages.sendMessage(sender, "noAnyLoadedCommand"); 480 | } 481 | else { 482 | Messages.sendMessage(sender, "loadedCommand"); 483 | for (org.taixue.customcommands.customcommand.Command command : group.getCommands()) { 484 | Messages.setVariable("format", command.getFormat()); 485 | Messages.setVariable("command", command.getName()); 486 | Messages.setVariable("size", command.getActions().length); 487 | Messages.sendMessage(sender, "commandSummary"); 488 | } 489 | } 490 | } 491 | 492 | private void showCommandDetail(CommandSender sender, org.taixue.customcommands.customcommand.Command command) { 493 | Messages.setVariable("command", command.getName()); 494 | Messages.setVariable("group", command.getGroup().getName()); 495 | Messages.sendMessage(sender, "commandDetailsTitle"); 496 | 497 | Messages.sendMessageString(sender, "group: " + command.getGroup().getName()); 498 | Messages.sendMessageString(sender, "name: " + command.getName()); 499 | Messages.sendMessageString(sender, "format: " + command.getFormat()); 500 | Messages.sendMessageString(sender, "usage: " + command.getUsageString()); 501 | if (command.getActions().length == 0) { 502 | Messages.sendMessageString(sender, "actions (0): (empty)"); 503 | } 504 | else { 505 | Messages.sendMessageString(sender, "actions (" + command.getActions().length + "): "); 506 | for (int index = 0; index < command.getActions().length; index++) { 507 | Messages.sendMessageString(sender, (index + 1) + " > " + command.getActions()[index]); 508 | } 509 | } 510 | Messages.sendMessageString(sender, "result: " + command.getResultString()); 511 | if (command.getPermissions().length == 0) { 512 | Messages.sendMessageString(sender, "permissions (0): (empty)"); 513 | } 514 | else { 515 | Messages.sendMessageString(sender, "permissions (" + command.getPermissions().length + "): "); 516 | for (int index = 0; index < command.getPermissions().length; index++) { 517 | Messages.setVariable("index", index + 1); 518 | Messages.sendMessageString(sender, (index + 1) + " > " + command.getPermissions()[index]); 519 | } 520 | } 521 | Messages.sendMessageString(sender, "identify: " + command.getIdentifyString()); 522 | } 523 | 524 | private void saveCommands(CommandSender sender) { 525 | try { 526 | Plugin.commandsConfig.save(); 527 | } 528 | catch (Exception exception) { 529 | Messages.setException(exception); 530 | Messages.sendMessage(sender, "exceptionInSavingCommands"); 531 | exception.printStackTrace(); 532 | } 533 | } 534 | } 535 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/commandexecutor/CCSCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.commandexecutor; 2 | 3 | import org.taixue.customcommands.Plugin; 4 | import org.taixue.customcommands.language.Messages; 5 | import org.bukkit.command.Command; 6 | import org.bukkit.command.CommandExecutor; 7 | import org.bukkit.command.CommandSender; 8 | 9 | import java.util.Arrays; 10 | 11 | public class CCSCommandExecutor implements CommandExecutor { 12 | @Override 13 | public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) { 14 | if (strings.length == 0) { 15 | return false; 16 | } 17 | if (strings.length == 1) { 18 | if (strings[0].equalsIgnoreCase("version")) { 19 | Messages.setNewVariable("permission", "ccs.version"); 20 | if (commandSender.hasPermission("ccs.version")) { 21 | Messages.sendMessageString(commandSender, "Plugin name: " + Plugin.NAME); 22 | Messages.sendMessageString(commandSender, "Version: " + Plugin.VERSION); 23 | Messages.sendMessageString(commandSender, "Author: " + Plugin.AUTHOR); 24 | Messages.sendMessageString(commandSender, "Organization: " + Plugin.ORGANIZATION); 25 | Messages.sendMessageString(commandSender, "Github: " + Plugin.GITHUB); 26 | Messages.sendMessageString(commandSender, "Mcbbs: " + Plugin.MCBBS); 27 | Messages.sendMessageString(commandSender, "QQ group: " + Plugin.QQ_GROUP); 28 | 29 | Messages.sendMessageString(commandSender, "Remember to give me a star :)"); 30 | return true; 31 | } 32 | else { 33 | Messages.sendMessage(commandSender, "lackPermission"); 34 | } 35 | } 36 | if (strings[0].equalsIgnoreCase("reload")) { 37 | Messages.setNewVariable("permission", "ccs.config.reload"); 38 | if (commandSender.hasPermission("ccs.config.reload")) { 39 | Plugin.reload(); 40 | Messages.infoString(commandSender.getName() + " reloaded CustomCommands."); 41 | Messages.sendMessageString(commandSender, "CustomCommands reload completely!"); 42 | } else { 43 | Messages.sendMessage(commandSender, "lackPermission"); 44 | } 45 | return true; 46 | } 47 | if (strings[0].equalsIgnoreCase("debug")) { 48 | Messages.setNewVariable("permission", "ccs.config.debug"); 49 | if (commandSender.hasPermission("ccs.config.debug")) { 50 | if (Plugin.debug) { 51 | Messages.sendMessageString(commandSender, "Debug: off"); 52 | } else { 53 | Messages.sendMessageString(commandSender, "Debug: on"); 54 | } 55 | Plugin.debug = !Plugin.debug; 56 | Plugin.pluginConfig.set("debug", Plugin.debug); 57 | Plugin.saveConfigFile(); 58 | } else { 59 | Messages.sendMessageString(commandSender, "lackPermission"); 60 | } 61 | return true; 62 | } 63 | else { 64 | return false; 65 | } 66 | } 67 | if (strings[0].equalsIgnoreCase("config")) { 68 | return Plugin.CCSC_COMMAND_EXECUTOR.onCommand( 69 | commandSender, 70 | command, 71 | s, 72 | Arrays.asList(strings).subList(1, strings.length).toArray(strings)); 73 | } 74 | if (strings[0].equalsIgnoreCase("run")) { 75 | return Plugin.CCSR_COMMAND_EXECUTOR.onCommand( 76 | commandSender, 77 | command, 78 | s, 79 | Arrays.asList(strings).subList(1, strings.length).toArray(strings)); 80 | } 81 | if (strings[0].equalsIgnoreCase("env")) { 82 | return Plugin.CCSE_COMMAND_EXECUTOR.onCommand( 83 | commandSender, 84 | command, 85 | s, 86 | Arrays.asList(strings).subList(1, strings.length).toArray(strings)); 87 | } 88 | return false; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/commandexecutor/CCSECommandExecutor.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.commandexecutor; 2 | 3 | import org.taixue.customcommands.Plugin; 4 | import org.taixue.customcommands.language.Environment; 5 | import org.taixue.customcommands.language.Messages; 6 | import org.taixue.customcommands.script.Strings; 7 | import org.bukkit.command.Command; 8 | import org.bukkit.command.CommandExecutor; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.entity.Player; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.Objects; 15 | 16 | 17 | public class CCSECommandExecutor implements CommandExecutor { 18 | @Override 19 | public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) { 20 | if (strings.length == 0) { 21 | return false; 22 | } 23 | String permissionNode = null; 24 | if (strings.length == 1 && strings[0].equalsIgnoreCase("reload")) { 25 | permissionNode = "ccs.env.reload"; 26 | Messages.setVariable("permission", permissionNode); 27 | if (commandSender.hasPermission(permissionNode)) { 28 | Plugin.reloadEnvironment(); 29 | Messages.sendMessage(commandSender, "onlinePlayerEnvironmentsLoaded"); 30 | } 31 | else { 32 | Messages.sendMessage(commandSender, "lackPermission"); 33 | } 34 | return true; 35 | } 36 | String firstOperator = strings[0]; 37 | if ((firstOperator.equalsIgnoreCase("global") || 38 | firstOperator.equalsIgnoreCase("personal"))) { 39 | Player player; 40 | if (firstOperator.equalsIgnoreCase("global")) { 41 | permissionNode = "ccs.env.global"; 42 | Messages.setVariable("permission", permissionNode); 43 | if (commandSender.hasPermission(permissionNode)) { 44 | player = null; 45 | } 46 | else { 47 | Messages.sendMessage(commandSender, "lackPermission"); 48 | return true; 49 | } 50 | } 51 | else { 52 | permissionNode = "ccs.env.personal"; 53 | Messages.setVariable("permission", permissionNode); 54 | if (commandSender.hasPermission(permissionNode)) { 55 | if (commandSender instanceof Player) { 56 | player = ((Player) commandSender); 57 | } else { 58 | Messages.sendMessage(commandSender, "operatorMustBePlayer"); 59 | return true; 60 | } 61 | } 62 | else { 63 | Messages.sendMessage(commandSender, "lackPermission"); 64 | return true; 65 | } 66 | } 67 | 68 | if (strings.length == 1) { 69 | Map env; 70 | if (Objects.isNull(player)) { 71 | env = Environment.getPlayerEnvironment(null); 72 | 73 | if (Objects.isNull(env) || env.isEmpty()) { 74 | Messages.sendMessage(commandSender, "noAnyLoadedVariable"); 75 | return true; 76 | } 77 | HashMap messageVariables = Messages.getEnvironment(); 78 | 79 | Messages.setVariable("size", messageVariables.size()); 80 | Messages.sendMessage(commandSender, "loadedMessageVariableTitle"); 81 | for (String variable: messageVariables.keySet()) { 82 | Messages.sendMessageString(commandSender, " > " + variable + ": " + messageVariables.get(variable)); 83 | } 84 | 85 | Messages.setVariable("environment", "global"); 86 | Messages.setVariable("size", env.size()); 87 | Messages.sendMessage(commandSender, "loadedVariableTitle"); 88 | 89 | for (String variable: env.keySet()) { 90 | Messages.sendMessageString(commandSender, " > " + variable + ": " + env.get(variable)); 91 | } 92 | } 93 | else { 94 | env = Environment.getPlayerEnvironment((Player) commandSender); 95 | if (Objects.isNull(env) || env.isEmpty()) { 96 | Messages.sendMessage(commandSender, "noAnyLoadedVariable"); 97 | return true; 98 | } 99 | 100 | Messages.setVariable("environment", "personal: " + commandSender.getName()); 101 | Messages.setVariable("size", env.size()); 102 | Messages.sendMessage(commandSender, "loadedVariableTitle"); 103 | 104 | for (String variable: env.keySet()) { 105 | Messages.sendMessageString(commandSender, " > " + variable + ": " + env.get(variable)); 106 | } 107 | } 108 | return true; 109 | } 110 | 111 | 112 | String secondOperator = strings[1]; 113 | 114 | if (secondOperator.equalsIgnoreCase("set") && strings.length >= 3) { 115 | String variableName = strings[2]; 116 | Messages.setVariable("variable", variableName); 117 | String value = Strings.getRemainString(strings, 3); 118 | Messages.setVariable("value", value); 119 | 120 | if (Strings.isLegalVariableName(variableName)) { 121 | Environment.put(player, variableName, value); 122 | Messages.sendMessage(commandSender, "variableSet"); 123 | } 124 | else { 125 | Messages.sendMessage(commandSender, "illegalVariableName"); 126 | } 127 | return true; 128 | } 129 | 130 | // global remove 131 | if (secondOperator.equalsIgnoreCase("remove") && strings.length == 3) { 132 | String variableName = strings[2]; 133 | Messages.setVariable("variable", variableName); 134 | 135 | if (Environment.remove(player, variableName)) { 136 | Messages.sendMessage(commandSender, "variableRemoved"); 137 | } 138 | else { 139 | Messages.sendMessage(commandSender, "variableNotFound"); 140 | } 141 | return true; 142 | } 143 | 144 | // global clear 145 | if (secondOperator.equalsIgnoreCase("clear") && strings.length == 2) { 146 | Environment.clear(player); 147 | Messages.sendMessage(commandSender, "environmentCleared"); 148 | return true; 149 | } 150 | return false; 151 | } 152 | return false; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/commandexecutor/CCSRCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.commandexecutor; 2 | 3 | import org.taixue.customcommands.Plugin; 4 | import org.taixue.customcommands.customcommand.Command; 5 | import org.taixue.customcommands.customcommand.Group; 6 | import org.taixue.customcommands.script.Script; 7 | import org.taixue.customcommands.language.Environment; 8 | import org.taixue.customcommands.language.Messages; 9 | import org.taixue.customcommands.util.Commands; 10 | import org.taixue.customcommands.script.Scripts; 11 | import org.bukkit.Bukkit; 12 | import org.bukkit.command.CommandExecutor; 13 | import org.bukkit.command.CommandSender; 14 | import org.bukkit.entity.Player; 15 | 16 | import java.security.MessageDigest; 17 | import java.util.ArrayList; 18 | import java.util.Map; 19 | import java.util.Objects; 20 | 21 | /** 22 | * Run the command defined in commands.yml 23 | */ 24 | public class CCSRCommandExecutor implements CommandExecutor { 25 | 26 | public boolean scriptRunner(String script) { 27 | return true; 28 | } 29 | 30 | @Override 31 | public boolean onCommand(CommandSender commandSender, org.bukkit.command.Command command, String s, String[] strings) { 32 | if (strings.length >= 1) { 33 | // 设置一些变量 34 | Messages.setVariable("player", commandSender.getName()); 35 | if (commandSender instanceof Player) { 36 | Messages.setVariable("displayName", ((Player) commandSender).getDisplayName()); 37 | Messages.setVariable("UUID", ((Player) commandSender).getUniqueId().toString()); 38 | Messages.setVariable("world", ((Player) commandSender).getWorld().getName()); 39 | } 40 | 41 | String groupName = strings[0]; 42 | Group group = Plugin.commandsConfig.getGroup(groupName); 43 | Messages.setVariable("group", groupName); 44 | 45 | if (Objects.isNull(group)) { 46 | Messages.sendMessage(commandSender, "undefinedGroup"); 47 | return true; 48 | } 49 | 50 | boolean isOp = commandSender.isOp(); 51 | try { 52 | ArrayList matchableCommands = group.getCommands(strings); 53 | ArrayList commands = Commands.screenUsableCommand(commandSender, matchableCommands); 54 | Command customCommand = null; 55 | 56 | if (commands.isEmpty()) { 57 | if (matchableCommands.isEmpty()) { 58 | Messages.sendMessage(commandSender, "noMatchableCommand"); 59 | ArrayList allCommands = Commands.screenUsableCommand(commandSender, group.getCommands()); 60 | 61 | if (!allCommands.isEmpty()) { 62 | Messages.sendMessage(commandSender, "loadedCommand"); 63 | for (Command cmd : allCommands) { 64 | Messages.sendMessage(commandSender, cmd.getUsageString()); 65 | } 66 | } 67 | } 68 | else { 69 | Messages.sendMessage(commandSender, "noPermissionToMatch"); 70 | } 71 | return true; 72 | } 73 | else if (commands.size() != 1) { 74 | // 去除非强匹配分支 75 | int hasRemainCommandCounter = 0; 76 | for (Command cmd: commands) { 77 | if (cmd.hasRemain()) { 78 | hasRemainCommandCounter++; 79 | } 80 | else { 81 | customCommand = cmd; 82 | } 83 | } 84 | // 如果有多个强匹配分支 85 | if (commands.size() - hasRemainCommandCounter != 1 || !Plugin.strongMath) { 86 | Messages.setVariable("size", Integer.toString(commands.size())); 87 | Messages.sendMessage(commandSender, "multipleCommands"); 88 | for (Command cmd : commands) { 89 | Messages.sendMessageString(commandSender, cmd.getUsageString()); 90 | } 91 | return true; 92 | } 93 | // 若只有一个强匹配,则采用该匹配 94 | } 95 | else { 96 | customCommand = commands.get(0); 97 | } 98 | 99 | // personal variables 100 | if (Plugin.debug) { 101 | try { 102 | Map personalEnvironment; 103 | if (commandSender instanceof Player && Environment.containsPlayer(((Player) commandSender))) { 104 | personalEnvironment = Environment.getPlayerEnvironment((Player) commandSender); 105 | Messages.debugString(commandSender, "personal variables:"); 106 | if (personalEnvironment.isEmpty()) { 107 | Messages.debugString(commandSender, "(no any personal variables)"); 108 | } else { 109 | for (String variableName : personalEnvironment.keySet()) { 110 | Messages.debugString(commandSender, " > " + variableName + ": " + personalEnvironment.get(variableName)); 111 | } 112 | } 113 | } else { 114 | Messages.debugString(commandSender, "No personal variables, because you aren't a player or your environment hasn't be load yet."); 115 | } 116 | } 117 | catch (Exception exception) { 118 | Messages.setVariable("exception", exception.toString()); 119 | Messages.sendMessage(commandSender, "unknownException"); 120 | exception.printStackTrace(); 121 | } 122 | } 123 | 124 | // global variables 125 | if (Plugin.debug) { 126 | try { 127 | Map globalEnvironment = Environment.getPlayerEnvironment(null); 128 | Messages.debugString(commandSender, "global variables:"); 129 | if (Objects.isNull(globalEnvironment) || globalEnvironment.isEmpty()) { 130 | Messages.debugString(commandSender, "(no any global variables)"); 131 | } else { 132 | for (String variableName : globalEnvironment.keySet()) { 133 | Messages.debugString(commandSender, " > " + variableName + ": " + globalEnvironment.get(variableName)); 134 | } 135 | } 136 | } 137 | catch (Exception exception) { 138 | Messages.setVariable("exception", exception.toString()); 139 | Messages.sendMessage(commandSender, "unknownException"); 140 | exception.printStackTrace(); 141 | } 142 | } 143 | 144 | if (Plugin.debug) { 145 | Messages.debugString(commandSender, "format: " + customCommand.getFormat()); 146 | } 147 | 148 | if (customCommand.parseCommand(commandSender, strings)) { 149 | if (Plugin.debug) { 150 | Messages.debugString(commandSender, "variable-value list:"); 151 | if (customCommand.getVariableValues().isEmpty()) { 152 | Messages.debugString(commandSender, "(There is no any variables)"); 153 | } 154 | else for (String para: customCommand.getVariableValues().keySet()) { 155 | Messages.debugString(commandSender, " > " + para + ": " + customCommand.getVariableValues().get(para)); 156 | } 157 | } 158 | } 159 | else { 160 | Messages.sendMessage(commandSender, "unmatchable"); 161 | return true; 162 | } 163 | 164 | CommandSender actionSender; 165 | Player player = null; 166 | 167 | switch (customCommand.getIdentify()) { 168 | case AUTO: 169 | actionSender = commandSender; 170 | break; 171 | case BYPASS: 172 | commandSender.setOp(true); 173 | actionSender = commandSender; 174 | break; 175 | case CONSOLE: 176 | actionSender = Bukkit.getConsoleSender(); 177 | break; 178 | default: 179 | actionSender = commandSender; 180 | Messages.sendMessage(commandSender, "illegalIdentify"); 181 | break; 182 | } 183 | if (commandSender instanceof Player) { 184 | player = (Player) commandSender; 185 | } 186 | 187 | if (Plugin.debug) { 188 | Messages.debugString(commandSender, "executing..."); 189 | if (customCommand.getActions().length == 0) { 190 | Messages.debugString(commandSender, "(no any action command)"); 191 | } 192 | } 193 | 194 | for (String unparsedCommand: customCommand.getActions()) { 195 | if (Plugin.debug) { 196 | Messages.debugString(commandSender, "unparsed: " + unparsedCommand); 197 | } 198 | String action = Messages.replaceVariableString(player, customCommand.replaceVariables(unparsedCommand)); 199 | if (Plugin.debug) { 200 | Messages.debugString(commandSender, "parse to: " + action); 201 | } 202 | if (action.startsWith("@")) { 203 | Script script = Scripts.parseScript(action, actionSender); 204 | if (Objects.nonNull(script)) { 205 | script.run(); 206 | } 207 | continue; 208 | } 209 | try { 210 | if (!commandSender.getServer().dispatchCommand(actionSender, action)) { 211 | if (commandSender instanceof Player) { 212 | ((Player) commandSender).chat(action); 213 | } 214 | } 215 | } 216 | catch (Exception exception) { 217 | Messages.setVariable("exception", exception.toString()); 218 | Messages.sendMessage(commandSender, "exceptionInExecutingCommand"); 219 | exception.printStackTrace(); 220 | } 221 | } 222 | 223 | if (Objects.nonNull(customCommand.getResultString())) { 224 | Messages.sendMessageString(commandSender, customCommand.getFormattedResultString()); 225 | } 226 | } 227 | catch (Exception exception) { 228 | Messages.setVariable("exception", exception.toString()); 229 | Messages.sendMessage(commandSender, "unknownException"); 230 | exception.printStackTrace(); 231 | } 232 | finally { 233 | commandSender.setOp(isOp); 234 | } 235 | return true; 236 | } 237 | else { 238 | return false; 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/config/CommandsConfig.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.config; 2 | 3 | import com.sun.istack.internal.NotNull; 4 | import org.taixue.customcommands.customcommand.Command; 5 | import org.taixue.customcommands.language.Messages; 6 | import org.taixue.customcommands.customcommand.Group; 7 | import org.taixue.customcommands.util.Groups; 8 | import org.taixue.customcommands.Plugin; 9 | import org.taixue.customcommands.script.Strings; 10 | import org.bukkit.configuration.ConfigurationSection; 11 | import org.bukkit.configuration.MemorySection; 12 | import org.bukkit.configuration.file.YamlConfiguration; 13 | 14 | import java.io.File; 15 | import java.io.IOException; 16 | import java.util.*; 17 | 18 | public class CommandsConfig extends Config { 19 | 20 | private ArrayList groups = new ArrayList<>(); 21 | 22 | public CommandsConfig(File file, String head) { 23 | super(file, head); 24 | load(); 25 | } 26 | 27 | public CommandsConfig() { 28 | this(new File(Plugin.plugin.getDataFolder(), "commands.yml"), "commands"); 29 | } 30 | 31 | public void load() { 32 | Messages.setNewVariable("file", file.getName()); 33 | try { 34 | Map groupsMap = configSection.getValues(false); 35 | Set loadedGroups = new HashSet<>(); 36 | for (String groupName: groupsMap.keySet()) { 37 | Messages.setVariable("group", groupName); 38 | if (loadedGroups.contains(groupName)) { 39 | Messages.severeLanguage("redefinedGroups"); 40 | } 41 | else { 42 | if (Strings.isLegalGroupName(groupName)) { 43 | loadedGroups.add(groupName); 44 | try { 45 | addGroup(Groups.loadFromMemorySection(((MemorySection) groupsMap.get(groupName)))); 46 | } catch (ClassCastException classCastException) { 47 | Messages.severeLanguage("wrongFormatForGroup"); 48 | } catch (Exception exception) { 49 | Messages.setException(exception); 50 | Messages.severeLanguage("exceptionInLoadingGroup"); 51 | exception.printStackTrace(); 52 | } 53 | 54 | } 55 | else { 56 | Messages.severeLanguage("illegalGroupName"); 57 | } 58 | } 59 | } 60 | } 61 | catch (Exception exception) { 62 | Messages.setException(exception); 63 | Messages.severeLanguage("exceptionInLoadingFile"); 64 | exception.printStackTrace(); 65 | } 66 | } 67 | 68 | @NotNull 69 | public ArrayList getCommands(String[] arguments) { 70 | if (arguments.length == 0) { 71 | return null; 72 | } 73 | Group group = getGroup(arguments[0]); 74 | return group.getCommands(arguments); 75 | } 76 | 77 | /** 78 | * 通过组名查找指令组 79 | * @param groupName 组名 80 | * @return 指令组 81 | */ 82 | public Group getGroup(String groupName) { 83 | for (Group group: groups) { 84 | if (group.getName().equals(groupName)) { 85 | return group; 86 | } 87 | } 88 | return null; 89 | } 90 | 91 | public void reload() { 92 | groups.clear(); 93 | fileConfiguration = YamlConfiguration.loadConfiguration(file); 94 | configSection = ((MemorySection) fileConfiguration.get("commands")); 95 | load(); 96 | } 97 | 98 | public void addGroup(Group group) { 99 | groups.add(group); 100 | } 101 | 102 | public ArrayList getGroups() { 103 | return groups; 104 | } 105 | 106 | public void removeGroup(String groupName) { 107 | groups.remove(getGroup(groupName)); 108 | } 109 | 110 | @Override 111 | public void save() throws IOException { 112 | // fileConfiguration.set("commands", null); 113 | configSection = fileConfiguration.createSection("commands"); 114 | for (Group group: groups) { 115 | ConfigurationSection groupSection = configSection.createSection(group.getName()); 116 | for (Command command: group.getCommands()) { 117 | ConfigurationSection commandSection = groupSection.createSection(command.getName()); 118 | commandSection.set("format", command.getFormat()); 119 | commandSection.set("actions", command.getActions()); 120 | 121 | if (!isDefaultUsage(command)) { 122 | commandSection.set("usage", command.getUsageString()); 123 | } 124 | // commandSection.set("matches", command.getMatches()); 125 | 126 | if (!isDefaultIdentify(command)) { 127 | commandSection.set("identify", command.getIdentifyString()); 128 | } 129 | 130 | if (Objects.nonNull(command.getResultString())) { 131 | commandSection.set("result", command.getResultString()); 132 | } 133 | 134 | if (!isDefaultPermissions(command)) { 135 | commandSection.set("permissions", command.getPermissions()); 136 | } 137 | } 138 | } 139 | super.save(); 140 | } 141 | 142 | public boolean isDefaultUsage(Command command) { 143 | return command.getUsageString().equals("/ccsr " + 144 | command.getGroup().getName() + " " + 145 | command.getFormat()); 146 | } 147 | 148 | public boolean isDefaultIdentify(Command command) { 149 | return command.getIdentify() == Command.Identify.AUTO; 150 | } 151 | 152 | public boolean isDefaultPermissions(Command command) { 153 | return command.getPermissions().length == 1 && 154 | command.getPermissions()[0].equals("ccs.run." + command.getGroup().getName() + "." + command.getName()); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/config/Config.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.config; 2 | 3 | import org.bukkit.configuration.ConfigurationSection; 4 | import org.bukkit.configuration.MemorySection; 5 | import org.bukkit.configuration.file.FileConfiguration; 6 | import org.bukkit.configuration.file.YamlConfiguration; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.util.Objects; 11 | 12 | public abstract class Config { 13 | protected FileConfiguration fileConfiguration; 14 | protected ConfigurationSection configSection; 15 | protected File file; 16 | 17 | public Config(File file, String head) { 18 | setFileConfiguration(YamlConfiguration.loadConfiguration(file)); 19 | setFile(file); 20 | configSection = Objects.requireNonNull(((MemorySection) fileConfiguration.get(head))); 21 | } 22 | 23 | public FileConfiguration getFileConfiguration() { 24 | return fileConfiguration; 25 | } 26 | 27 | public ConfigurationSection getConfigSection() { 28 | return configSection; 29 | } 30 | 31 | public void setConfigSection(MemorySection configSection) { 32 | this.configSection = configSection; 33 | } 34 | 35 | public void setFileConfiguration(FileConfiguration fileConfiguration) { 36 | this.fileConfiguration = fileConfiguration; 37 | } 38 | 39 | public File getFile() { 40 | return file; 41 | } 42 | 43 | public void setFile(File file) { 44 | this.file = file; 45 | } 46 | 47 | public void save() throws IOException { 48 | fileConfiguration.save(file); 49 | } 50 | 51 | public Object get(String path) { 52 | return configSection.get(path); 53 | } 54 | 55 | public Object get(String path, Object defaultValue) { 56 | return configSection.get(path, defaultValue); 57 | } 58 | 59 | public void set(String path, Object value) { 60 | configSection.set(path, value); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/config/PluginConfig.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.config; 2 | 3 | import org.taixue.customcommands.Plugin; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | 8 | public class PluginConfig extends Config{ 9 | public PluginConfig(File file, String head) { 10 | super(file, head); 11 | } 12 | 13 | public PluginConfig() { 14 | this(new File(Plugin.plugin.getDataFolder(), "config.yml"), "config"); 15 | } 16 | 17 | @Override 18 | public void save() throws IOException { 19 | super.save(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/customcommand/Command.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.customcommand; 2 | 3 | import org.taixue.customcommands.Plugin; 4 | import org.taixue.customcommands.language.Messages; 5 | import org.taixue.customcommands.script.Strings; 6 | import org.bukkit.command.CommandSender; 7 | 8 | import java.util.*; 9 | import java.util.regex.Matcher; 10 | import java.util.regex.PatternSyntaxException; 11 | 12 | public class Command { 13 | // 本指令所属的组 14 | private Group group; 15 | 16 | private String name; 17 | private String format; 18 | private String[] parameters; 19 | private String[] actions; 20 | 21 | private Map variableValues = new HashMap<>(); 22 | private Map matches = new HashMap<>(); 23 | 24 | // 格式错误时返回的内容 25 | private String usageString; 26 | // 格式正确时返回内容 27 | private String resultString; 28 | 29 | private String[] permissions; 30 | 31 | public enum Identify { 32 | CONSOLE, 33 | AUTO, 34 | BYPASS, 35 | PLAYER 36 | } 37 | private String identifyPlayer; 38 | 39 | private Identify identify = Identify.AUTO; 40 | 41 | public Command(String commandName) { 42 | setName(commandName); 43 | } 44 | 45 | public Command() { 46 | setName(""); 47 | } 48 | 49 | /** 50 | * 解析并将变量值存储 51 | * @param sender Command sender 52 | * @param arguments arguments list, doesn't starts with command name. 53 | * @return true only if it's correct arguments. 54 | */ 55 | public boolean parseCommand(CommandSender sender, String[] arguments) { 56 | Messages.setVariable("command", name); 57 | Messages.setVariable("permission", "ccs.run." + group.getName() +"." + name); 58 | 59 | int paraIndex = 0, argsIndex = 1; 60 | while (paraIndex < parameters.length && argsIndex < arguments.length) { 61 | String para = parameters[paraIndex ++]; 62 | String arg = arguments[argsIndex ++]; 63 | 64 | Messages.setVariable("parameter", para); 65 | 66 | if (para.startsWith("{")) { 67 | String parameterName = para.substring(1, para.length() - 1); 68 | variableValues.put(parameterName, arg); 69 | } 70 | else if (!para.equals(arg)) { 71 | return false; 72 | } 73 | } 74 | 75 | if (paraIndex < parameters.length) { 76 | // 形参多余:若多余的是 remain 则将其设置为空,否则语法错误 77 | if (paraIndex == parameters.length - 1 && parameters[paraIndex].equals("{remain}")) { 78 | Messages.setVariable("parameter", "remain"); 79 | variableValues.put("remain", ""); 80 | return true; 81 | } 82 | else { 83 | return false; 84 | } 85 | } 86 | 87 | if (argsIndex < arguments.length) { 88 | // 实参多余:若最后一个形参是 remain,那全部都放进去,否则语法错误 89 | if (parameters[parameters.length - 1].equals("{remain}")) { 90 | StringBuilder remainValue = new StringBuilder(variableValues.getOrDefault("remain", "")); 91 | while (argsIndex < arguments.length) { 92 | remainValue.append(" ").append(arguments[argsIndex]); 93 | argsIndex++; 94 | } 95 | variableValues.put("remain", remainValue.toString()); 96 | return true; 97 | } 98 | else { 99 | return false; 100 | } 101 | } 102 | 103 | return true; 104 | } 105 | 106 | public ArrayList getParsedActions() { 107 | ArrayList actionStrings = new ArrayList<>(); 108 | 109 | for (String cmd: actions) { 110 | actionStrings.add(Messages.replaceVariableString(replaceVariables(cmd))); 111 | } 112 | return actionStrings; 113 | } 114 | 115 | /** 116 | * 解析输入合法性 117 | * @param arguments 参数列表 118 | * @return true 当且仅当输入合法 119 | */ 120 | public boolean isLegalArguments(String[] arguments) { 121 | if (arguments.length == 0 || !arguments[0].equals(group.getName())) { 122 | return false; 123 | } 124 | 125 | int argIndex = 1; 126 | int paraIndex = 0; 127 | while (argIndex < arguments.length && paraIndex < parameters.length) { 128 | String argument = arguments[argIndex ++]; 129 | String parameter = parameters[paraIndex ++]; 130 | 131 | if (parameter.charAt(0) != '{' && !parameter.equals(argument)) { 132 | return false; 133 | } 134 | if (parameter.charAt(0) == '{') { 135 | String parameterName = parameter.substring(1, parameter.length() - 1); 136 | Messages.setVariable("parameter", parameterName); 137 | 138 | if (matches.containsKey(parameterName)) { 139 | try { 140 | String regex = matches.get(parameterName); 141 | Messages.setVariable("regex", regex); 142 | if (!argument.matches(regex)) { 143 | return false; 144 | } 145 | } catch (PatternSyntaxException exception) { 146 | Messages.setException(exception); 147 | Messages.severeLanguage("exceptionInMatchingArgument"); 148 | exception.printStackTrace(); 149 | return false; 150 | } 151 | } 152 | } 153 | } 154 | 155 | boolean endWithRemain = (parameters.length == 0 ? false : parameters[parameters.length - 1].equals("{remain}")); 156 | if (argIndex < arguments.length && !endWithRemain) { 157 | return false; 158 | } 159 | if (paraIndex < parameters.length && !endWithRemain) { 160 | return false; 161 | } 162 | return true; 163 | } 164 | 165 | public boolean isLegalParameters() { 166 | Set variableNames = new HashSet<>(); 167 | for (int index = 0; index < parameters.length; index++) { 168 | String parameter = parameters[index]; 169 | if (parameter.charAt(0) == '{') { 170 | // 检查变量名合法性 171 | if (parameter.matches("\\{" + Strings.LEGAL_VARIABLE_NAME_REGEX + "\\}")) { 172 | String parameterName = parameter.substring(1, parameter.length() - 1); 173 | Messages.setVariable("parameter", parameterName); 174 | // 变量重定义,或不在末尾使用 remain 175 | if (variableNames.contains(parameterName) || 176 | (index != parameters.length - 1 && parameterName.equals("remain"))) { 177 | return false; 178 | } 179 | else { 180 | variableNames.add(parameterName); 181 | } 182 | } 183 | else { 184 | return false; 185 | } 186 | } 187 | } 188 | return true; 189 | } 190 | 191 | public boolean isLegalMatches() { 192 | Set variableNames = new HashSet<>(); 193 | for (String parameter: parameters) { 194 | if (parameter.charAt(0) == '{') { 195 | variableNames.add(parameter.substring(1, parameter.length() - 1)); 196 | } 197 | } 198 | for (String regexHead: matches.keySet()) { 199 | Messages.setVariable("parameter", regexHead); 200 | if (regexHead.equalsIgnoreCase("remain")) { 201 | return false; 202 | } 203 | if (!variableNames.contains(regexHead)) { 204 | return false; 205 | } 206 | try { 207 | "".matches(matches.get(regexHead)); 208 | } 209 | catch (PatternSyntaxException exception) { 210 | Messages.setException(exception); 211 | Messages.severeLanguage("regexSyntaxError"); 212 | return false; 213 | } 214 | } 215 | return true; 216 | } 217 | 218 | /** 219 | * 替换字符串内所有变量名为其对应值 220 | * @param string 替换前的字符串 221 | * @return 替换后的字符串 222 | */ 223 | public String replaceVariables(String string) { 224 | final int maxInteractions = ((Integer) Plugin.pluginConfig.get("max-iterations")); 225 | int left, right; 226 | 227 | for (int counter = 0; 228 | string.contains("{") && counter < maxInteractions; 229 | counter++) { 230 | left = string.indexOf("{"); 231 | right = string.indexOf("}", left); 232 | 233 | if (left < right - 1) { 234 | String variableName = string.substring(left + 1, right); 235 | String value = variableValues.get(variableName); 236 | if (Objects.nonNull(value)) { 237 | string = string.replaceAll("\\{" + Matcher.quoteReplacement(variableName) + "\\}", value); 238 | } 239 | } 240 | } 241 | return string; 242 | } 243 | 244 | public String getName() { 245 | return name; 246 | } 247 | 248 | public String getFormat() { 249 | return format; 250 | } 251 | 252 | public void setName(String name) { 253 | this.name = name; 254 | } 255 | 256 | public void setFormat(String format) { 257 | this.format = format; 258 | String[] splittedParameters = format.split("\\s"); 259 | ArrayList parameters = new ArrayList<>(); 260 | for (String parameter: splittedParameters) { 261 | if (!parameter.isEmpty()) { 262 | parameters.add(parameter); 263 | } 264 | } 265 | this.parameters = parameters.toArray(new String[0]); 266 | setUsageToDefault(); 267 | } 268 | 269 | public void setActions(String[] actions) { 270 | this.actions = actions; 271 | } 272 | 273 | public String[] getActions() { 274 | return actions; 275 | } 276 | 277 | public void setUsageString(String usageString) { 278 | this.usageString = usageString; 279 | } 280 | 281 | public String getUsageString() { 282 | return usageString; 283 | } 284 | 285 | public void setIdentify(Identify identify) { 286 | this.identify = identify; 287 | } 288 | 289 | public Identify getIdentify() { 290 | return identify; 291 | } 292 | 293 | public String getIdentifyString() { 294 | if (identify == Identify.PLAYER) { 295 | return "player:" + getIdentifyPlayer(); 296 | } 297 | else { 298 | return identify.toString().toLowerCase(); 299 | } 300 | } 301 | 302 | public String getIdentifyPlayer() { 303 | return identifyPlayer; 304 | } 305 | 306 | public void setResultString(String resultString) { 307 | this.resultString = resultString; 308 | } 309 | 310 | public String getResultString() { 311 | return resultString; 312 | } 313 | 314 | public String[] getParameters() { 315 | return parameters; 316 | } 317 | 318 | public Group getGroup() { 319 | return group; 320 | } 321 | 322 | public void setGroup(Group group) { 323 | this.group = group; 324 | } 325 | 326 | public Map getVariableValues() { 327 | return variableValues; 328 | } 329 | 330 | public void setPermissions(String[] permissions) { 331 | this.permissions = permissions; 332 | } 333 | 334 | public String[] getPermissions() { 335 | return permissions; 336 | } 337 | 338 | public String getFormattedResultString() { 339 | return replaceVariables(getResultString()); 340 | } 341 | 342 | public void addAction(String actionString) { 343 | actions = Arrays.copyOf(actions, actions.length + 1); 344 | actions[actions.length - 1] = actionString; 345 | } 346 | 347 | public void removeAction(String actionString) { 348 | List actionList = Arrays.asList(actions); 349 | actionList.remove(actionString); 350 | actions = actionList.toArray(new String[0]); 351 | } 352 | 353 | public void addPermission(String permissionString) { 354 | permissions = Arrays.copyOf(permissions, permissions.length + 1); 355 | permissions[permissions.length - 1] = permissionString; 356 | } 357 | 358 | public void removePermissions(String permissionString) { 359 | List permissionList = Arrays.asList(permissions); 360 | permissionList.remove(permissionString); 361 | permissions = permissionList.toArray(new String[0]); 362 | } 363 | 364 | public boolean containsAction(String actionString) { 365 | for (String action: actions) { 366 | if (action.equals(actionString)) { 367 | return true; 368 | } 369 | } 370 | return false; 371 | } 372 | 373 | public boolean containsPermission(String permissionString) { 374 | for (String action: permissions) { 375 | if (action.equals(permissionString)) { 376 | return true; 377 | } 378 | } 379 | return false; 380 | } 381 | 382 | public void setMatches(Map matches) { 383 | this.matches = matches; 384 | } 385 | 386 | public Map getMatches() { 387 | return matches; 388 | } 389 | 390 | public void setUsageToDefault() { 391 | setUsageString("/ccsr " + getGroup().getName() + " " + getFormat()); 392 | } 393 | 394 | public void setIdentifyPlayer(String identifyPlayer) { 395 | this.identifyPlayer = identifyPlayer; 396 | identify = Identify.PLAYER; 397 | } 398 | 399 | public boolean hasRemain() { 400 | for (int i = parameters.length - 1; i >= 0; i --) { 401 | if (parameters[i].equals("{remain}")) { 402 | return true; 403 | } 404 | } 405 | return false; 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/customcommand/Group.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.customcommand; 2 | 3 | import com.sun.istack.internal.NotNull; 4 | import com.sun.istack.internal.Nullable; 5 | 6 | import java.util.ArrayList; 7 | 8 | public class Group { 9 | private String name; 10 | private ArrayList commands = new ArrayList<>(); 11 | 12 | public Group() { 13 | this(""); 14 | } 15 | 16 | public Group(String name) { 17 | setName(name); 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public void setName(@NotNull String name) { 25 | this.name = name; 26 | for (Command command: commands) { 27 | command.setUsageToDefault(); 28 | } 29 | } 30 | 31 | public ArrayList getCommands() { 32 | return commands; 33 | } 34 | 35 | /** 36 | * 将一个指令加入当前的指令组中 37 | * @param command 38 | */ 39 | public void addCommand(@NotNull Command command) { 40 | commands.add(command); 41 | command.setGroup(this); 42 | } 43 | 44 | /** 45 | * 通过参数查找可匹配的指令列表 46 | * @param arguments 参数列表 47 | * @return 可与之匹配的指令列表 48 | */ 49 | @Nullable 50 | public ArrayList getCommands(@NotNull String[] arguments) { 51 | if (arguments.length == 0 || !arguments[0].equals(name)) { 52 | return null; 53 | } 54 | ArrayList result = new ArrayList<>(); 55 | for (Command command: commands) { 56 | if (command.isLegalArguments(arguments)) { 57 | result.add(command); 58 | } 59 | } 60 | return result; 61 | } 62 | 63 | /** 64 | * 通过指令名查找指令 65 | * @param commandName 66 | * @return 67 | */ 68 | @Nullable 69 | public Command getCommand(@NotNull String commandName) { 70 | for (Command command: commands) { 71 | if (command.getName().equals(commandName)) { 72 | return command; 73 | } 74 | } 75 | return null; 76 | } 77 | 78 | public void removeCommand(@NotNull String commandName) { 79 | commands.remove(getCommand(commandName)); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/language/Environment.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.language; 2 | 3 | import com.sun.istack.internal.Nullable; 4 | import org.taixue.customcommands.Plugin; 5 | import org.bukkit.configuration.ConfigurationSection; 6 | import org.bukkit.configuration.file.YamlConfiguration; 7 | import org.bukkit.entity.Player; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | import java.util.Objects; 14 | 15 | public class Environment { 16 | private static final File directory = new File(Plugin.plugin.getDataFolder(), "environment"); 17 | // Player null means 'global' 18 | private static final Map> environment = new HashMap<>(); 19 | 20 | public Environment() { 21 | if (!directory.exists() || !directory.isDirectory()) { 22 | directory.mkdirs(); 23 | } 24 | } 25 | 26 | public static boolean containsPlayer(Player player) { 27 | for (Player p: environment.keySet()) { 28 | if (Objects.isNull(p)) { 29 | continue; 30 | } 31 | if (p.getUniqueId().toString().equals(player.getUniqueId().toString())) { 32 | return true; 33 | } 34 | } 35 | return false; 36 | } 37 | 38 | public static void put(Player player, String variableName, String value) { 39 | Map playerEnvironment = getPlayerEnvironment(player); 40 | if (Objects.isNull(playerEnvironment)) { 41 | playerEnvironment = new HashMap<>(); 42 | environment.put(player, playerEnvironment); 43 | } 44 | playerEnvironment.put(variableName, value); 45 | saveEnvironment(player); 46 | } 47 | 48 | public static boolean remove(Player player, String variableName) { 49 | Map environment = getPlayerEnvironment(player); 50 | if (Objects.isNull(environment) || !environment.containsKey(variableName)) { 51 | return false; 52 | } 53 | environment.remove(variableName); 54 | saveEnvironment(player); 55 | return true; 56 | } 57 | 58 | public static void clear(Player player) { 59 | if (containsPlayer(player)) { 60 | environment.put(player, new HashMap<>()); 61 | saveEnvironment(player); 62 | } 63 | } 64 | 65 | public static String get(Player player, String key) { 66 | if (containsPlayer(player)) { 67 | return environment.get(player).getOrDefault(key, null); 68 | } 69 | else { 70 | return null; 71 | } 72 | } 73 | 74 | @Nullable 75 | public static String getVariable(Player player, String key) { 76 | String value = null; 77 | if (Objects.nonNull(player)) { 78 | value = get(player, key); 79 | } 80 | if (Objects.isNull(value)) { 81 | value = get(null, key); 82 | } 83 | return Objects.isNull(value) ? Messages.getVariable(key) : value; 84 | } 85 | 86 | public static boolean load(Player player) { 87 | return load(player, getPlayerEnvironmentFile(player)); 88 | } 89 | 90 | public static boolean load(Player player, File file) { 91 | try { 92 | Messages.setVariable("file", file.getName()); 93 | ConfigurationSection root = ((ConfigurationSection) YamlConfiguration.loadConfiguration(file).get("environment")); 94 | if (Objects.isNull(root)) { 95 | return false; 96 | } 97 | Map currentMap = root.getValues(false); 98 | for (Object object: currentMap.values()) { 99 | if (!(object instanceof String)) { 100 | Messages.severeLanguage("variableShouldBeString"); 101 | return false; 102 | } 103 | } 104 | environment.put(player,((Map) (Object) currentMap)); 105 | return true; 106 | } 107 | catch (Exception exception) { 108 | Messages.setException(exception); 109 | Messages.severeLanguage("exceptionInLoadingEnvironment"); 110 | exception.printStackTrace(); 111 | return false; 112 | } 113 | } 114 | 115 | @Nullable 116 | public static Map getPlayerEnvironment(@Nullable Player player) { 117 | return environment.getOrDefault(player, null); 118 | } 119 | 120 | private static File getPlayerEnvironmentFile(@Nullable Player player) { 121 | return new File(directory, (Objects.isNull(player) ? "global" : player.getUniqueId().toString()) + ".yml"); 122 | } 123 | 124 | public static boolean saveEnvironment(@Nullable Player player) { 125 | return saveEnvironment(getPlayerEnvironmentFile(player), environment.get(player)); 126 | } 127 | 128 | public static boolean saveEnvironment(File saveTo, Map environment) { 129 | Messages.setVariable("UUID", saveTo.getName()); 130 | if (!saveTo.exists()) { 131 | try { 132 | saveTo.createNewFile(); 133 | } 134 | catch (IOException ioException) { 135 | Messages.setException(ioException); 136 | Messages.severeLanguage("exceptionInSavingEnvironment"); 137 | ioException.printStackTrace(); 138 | return false; 139 | } 140 | } 141 | try { 142 | YamlConfiguration yaml = new YamlConfiguration(); 143 | yaml.set("environment", environment); 144 | yaml.save(saveTo); 145 | return true; 146 | } 147 | catch (Exception exception) { 148 | Messages.setException(exception); 149 | Messages.severeLanguage("exceptionInSavingEnvironment"); 150 | exception.printStackTrace(); 151 | return false; 152 | } 153 | } 154 | 155 | public static void clear() { 156 | environment.clear(); 157 | } 158 | 159 | public static void unload(Player player) { 160 | environment.remove(player); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/language/Language.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.language; 2 | 3 | public class Language { 4 | public String messageHead; 5 | public String debugHead; 6 | public String messageEndl; 7 | public String wrongFormatForGroup; 8 | public String wrongFormatForCommand; 9 | public String undefinedGroup; 10 | public String matchesError; 11 | public String regexSyntaxError; 12 | public String illegalParameterName; 13 | public String illegalVariableName; 14 | public String redefinedParameter; 15 | public String extraArgs; 16 | public String illegalIdentify; 17 | public String lackPermission; 18 | public String parameterCannotBeBull; 19 | public String illegalCommandName; 20 | public String illegalGroupName; 21 | public String exceptionInLoadingGroup; 22 | public String exceptionInLoadingCommand; 23 | public String exceptionInLoadingFile; 24 | public String exceptionInExecutingCommand; 25 | public String exceptionInParsingCommand; 26 | public String exceptionInSavingCommands; 27 | public String exceptionInMatchingArgument; 28 | public String exceptionInSavingEnvironment; 29 | public String exceptionInLoadingEnvironment; 30 | public String unknownException; 31 | public String groupNotFound; 32 | public String noMatchableCommand; 33 | public String multipleCommands; 34 | public String noPermissionToMatch; 35 | public String loadedGroups; 36 | public String noAnyLoadedGroup; 37 | public String loadedCommand; 38 | public String noAnyLoadedCommand; 39 | public String redefinedGroups; 40 | public String redefinedCommands; 41 | public String scriptSyntaxError; 42 | public String illegalScript; 43 | public String unknownScript; 44 | public String groupAlreadyExist; 45 | public String groupAdded; 46 | public String groupRemoved; 47 | public String groupRenamed; 48 | public String commandAdded; 49 | public String commandAlreadyExist; 50 | public String commandNotFound; 51 | public String commandRemoved; 52 | public String commandRenamed; 53 | public String identifySet; 54 | public String formatSet; 55 | public String illegalFormat; 56 | public String resultSet; 57 | public String actionAdded; 58 | public String actionNotFound; 59 | public String actionRemoved; 60 | public String actionsCleared; 61 | public String actionsSet; 62 | public String actionEdited; 63 | public String illegalIndex; 64 | public String permissionAlreadyExist; 65 | public String permissionAdded; 66 | public String permissionNotFound; 67 | public String permissionRemoved; 68 | public String permissionsCleared; 69 | public String permissionsSet; 70 | public String permissionEdited; 71 | public String setPermissionsToDefault; 72 | public String groupSummary; 73 | public String groupDetailsTitle; 74 | public String commandSummary; 75 | public String commandDetailsTitle; 76 | public String commandsSaved; 77 | public String operatorMustBePlayer; 78 | public String wrongEnvironment; 79 | public String cannotLoadEnvironment; 80 | public String unknownUUID; 81 | public String environmentLoaded; 82 | public String variableSet; 83 | public String variableNotFound; 84 | public String variableRemoved; 85 | public String environmentCleared; 86 | public String loadingEnvironment; 87 | public String variableShouldBeString; 88 | public String failToLoadEnvironment; 89 | public String loadedVariableTitle; 90 | public String noAnyLoadedVariable; 91 | public String onlinePlayerEnvironmentsLoaded; 92 | public String wattingPlayerLeave; 93 | public String unloadedPlayerEnvironment; 94 | public String interruptToWaitPlayerLeave; 95 | public String loadedMessageVariableTitle; 96 | } -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/language/Messages.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.language; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.sun.istack.internal.NotNull; 5 | import com.sun.istack.internal.Nullable; 6 | import org.taixue.customcommands.Plugin; 7 | import org.taixue.customcommands.util.Paths; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.entity.Player; 10 | 11 | import java.lang.reflect.Field; 12 | import java.util.HashMap; 13 | import java.util.Objects; 14 | import java.util.logging.Logger; 15 | 16 | public class Messages { 17 | private Messages() {} 18 | 19 | private static Language language; 20 | private static Logger logger; 21 | 22 | private static HashMap environment = new HashMap<>(); 23 | 24 | public static boolean setLanguage(@NotNull String languageCode) { 25 | if (Objects.nonNull(language)) { 26 | return true; 27 | } 28 | try { 29 | language = JSON.parseObject(Plugin.plugin.getResource(Paths.LANG_DIR + Paths.SPLIT + languageCode + ".json"), 30 | Language.class); 31 | return true; 32 | } 33 | catch (Exception exception) { 34 | severeString("Fail to load language file: " + language + ".json " + ", because: " + exception); 35 | exception.printStackTrace(); 36 | return false; 37 | } 38 | } 39 | 40 | public static Language getLanguage() { 41 | return language; 42 | } 43 | 44 | public static void setLogger(@NotNull Logger logger) { 45 | Messages.logger = logger; 46 | } 47 | 48 | public static void setException(@NotNull Exception exception) { 49 | setVariable("exception", exception.getClass().getName()); 50 | setVariable("exceptionMessage", exception.getMessage()); 51 | } 52 | 53 | public static void setVariable(@NotNull String variableName, @NotNull String value) { 54 | environment.put(variableName, value); 55 | } 56 | 57 | public static void setVariable(@NotNull String variableName, int value) { 58 | setVariable(variableName, Integer.toString(value)); 59 | } 60 | 61 | public static void setNewVariable(@NotNull String variableName, @NotNull String value) { 62 | clearVariables(); 63 | setVariable(variableName, value); 64 | } 65 | 66 | @Nullable 67 | public static String getVariable(@NotNull String key) { 68 | return environment.getOrDefault(key, null); 69 | } 70 | 71 | public static HashMap getEnvironment() { 72 | return environment; 73 | } 74 | 75 | public static void clearVariables() { 76 | environment.clear(); 77 | } 78 | 79 | public static String replaceVariableString(@NotNull String string) { 80 | return replaceVariableString(null, string); 81 | } 82 | @NotNull 83 | public static String replaceVariableString(Player player, @NotNull String string) { 84 | if (!string.contains("{")) { 85 | return string; 86 | } 87 | StringBuilder stringBuilder = new StringBuilder(string); 88 | int lparen = 0, rparen = 0; 89 | 90 | while (stringBuilder.indexOf("{") != -1) { 91 | lparen = stringBuilder.indexOf("{", rparen); 92 | rparen = stringBuilder.indexOf("}", lparen); 93 | 94 | if (lparen != -1 && 95 | rparen != -1 && 96 | rparen > lparen + 1) { 97 | String variableName = stringBuilder.substring(lparen + 1, rparen); 98 | String variableValue = Environment.getVariable(player, variableName); 99 | if (Objects.nonNull(variableValue)) { 100 | if (variableName.contains("exception")) { 101 | stringBuilder.replace(lparen, rparen + 1, red(variableValue)); 102 | } 103 | else { 104 | stringBuilder.replace(lparen, rparen + 1, variableValue); 105 | } 106 | } 107 | } 108 | else { 109 | break; 110 | } 111 | } 112 | return stringBuilder.toString(); 113 | } 114 | 115 | @NotNull 116 | public static String replaceVariableLanguage(@NotNull String messageName) { 117 | try { 118 | Field message = Language.class.getField(messageName); 119 | return replaceVariableString(((String) message.get(language))); 120 | } 121 | catch (Exception noSuchFieldException) { 122 | return messageName; 123 | } 124 | } 125 | 126 | public static void sendMessageString(@NotNull CommandSender sender, String message) { 127 | if (Objects.isNull(language)) { 128 | sender.sendMessage("Unexpected error: cannot load language file, please check if syntax errors exist."); 129 | sender.sendMessage("[" + Plugin.NAME + "]" + message); 130 | severeString("Unexpected error: cannot load language file, please check if syntax errors exist."); 131 | } 132 | else { 133 | sender.sendMessage(language.messageHead + message); 134 | } 135 | } 136 | 137 | public static void sendMessageStringAndLog(@NotNull CommandSender sender, String message) { 138 | sendMessage(sender, message); 139 | infoString(sender.getName() + " << " + message); 140 | } 141 | 142 | public static void sendMessage(@NotNull CommandSender sender, String messageName) { 143 | sendMessageString(sender, replaceVariableLanguage(messageName)); 144 | } 145 | 146 | public static void infoString(@NotNull String string) { 147 | logger.info(replaceVariableString(string)); 148 | } 149 | 150 | public static void warningString(@NotNull String string) { 151 | logger.warning(replaceVariableString(string)); 152 | } 153 | 154 | public static void severeString(@NotNull String string) { 155 | logger.severe(replaceVariableString(string)); 156 | } 157 | 158 | public static void infoLang(@NotNull String messageName) { 159 | infoString(replaceVariableLanguage(messageName)); 160 | } 161 | 162 | public static void warningLang(@NotNull String messageName) { 163 | warningString(replaceVariableLanguage(messageName)); 164 | } 165 | 166 | public static void severeLanguage(@NotNull String messageName) { 167 | severeString(replaceVariableLanguage(messageName)); 168 | } 169 | 170 | public static void debugString(@NotNull CommandSender sender, @NotNull String string) { 171 | sender.sendMessage(language.debugHead + string); 172 | } 173 | 174 | public static void hello() { 175 | infoString(yellow("Nice to meet you! o(* ̄▽ ̄*)ブ")); 176 | infoString(purple("CustomCommands is written by Chuanwise, open source under GPL GNU license")); 177 | Messages.infoString(white("You can support us in following websites:")); 178 | Messages.infoString(yellow("Github: ") + Plugin.GITHUB + gray("(Remember to give me a star :>)")); 179 | Messages.infoString(yellow("MCBBS: ") + Plugin.MCBBS); 180 | Messages.infoString("Join the QQ group: " + red(Plugin.QQ_GROUP) + " to get the newest update and some tech-suppositions."); 181 | } 182 | 183 | public static String white(String string) { 184 | return "\033[30;33m" + string + "\33[0m"; 185 | } 186 | 187 | public static String red(String string) { 188 | return "\033[31;33m" + string + "\33[0m"; 189 | } 190 | 191 | public static String green(String string) { 192 | return "\033[32;33m" + string + "\33[0m"; 193 | } 194 | 195 | public static String yellow(String string) { 196 | return "\033[33;33m" + string + "\33[0m"; 197 | } 198 | 199 | public static String blue(String string) { 200 | return "\033[34;33m" + string + "\33[0m"; 201 | } 202 | 203 | public static String purple(String string) { 204 | return "\033[35;33m" + string + "\33[0m"; 205 | } 206 | 207 | public static String cyan(String string) { 208 | return "\033[36;33m" + string + "\33[0m"; 209 | } 210 | 211 | public static String gray(String string) { 212 | return "\033[36;33m" + string + "\33[0m"; 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/script/MessageScript.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.script; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.taixue.customcommands.language.Messages; 5 | 6 | public class MessageScript extends Script { 7 | private CommandSender commandSender; 8 | private String message; 9 | 10 | public MessageScript(CommandSender commandSender) { 11 | setCommandSender(commandSender); 12 | } 13 | 14 | public void setCommandSender(CommandSender commandSender) { 15 | this.commandSender = commandSender; 16 | } 17 | 18 | public CommandSender getCommandSender() { 19 | return commandSender; 20 | } 21 | 22 | public void setMessage(String message) { 23 | this.message = message; 24 | } 25 | 26 | public String getMessage() { 27 | return message; 28 | } 29 | 30 | @Override 31 | public void run() { 32 | commandSender.sendMessage(Messages.replaceVariableString(message)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/script/Script.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.script; 2 | 3 | public abstract class Script { 4 | protected String name; 5 | 6 | public Script(String name) { 7 | setName(name); 8 | } 9 | 10 | public Script() { 11 | } 12 | 13 | public void setName(String name) { 14 | this.name = name; 15 | } 16 | 17 | public String getName() { 18 | return name; 19 | } 20 | 21 | public abstract void run(); 22 | } -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/script/Scripts.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.script; 2 | 3 | import com.sun.istack.internal.NotNull; 4 | import com.sun.istack.internal.Nullable; 5 | import org.taixue.customcommands.language.Messages; 6 | import org.taixue.customcommands.Plugin; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.Objects; 13 | 14 | public class Scripts { 15 | private Scripts() {} 16 | 17 | @Nullable 18 | public static Script parseScript(@NotNull String string, @NotNull CommandSender sender) { 19 | Script result = null; 20 | String name; 21 | String[] arguments; 22 | 23 | if (string.contains(" ")) { 24 | name = string.substring(1, string.indexOf(" ")); 25 | ArrayList argumentsResult = new ArrayList<>(); 26 | for (String argument: string.substring(name.length() + 1).trim().split("\\s")) { 27 | if (!argument.isEmpty()) { 28 | argumentsResult.add(argument); 29 | } 30 | } 31 | arguments = argumentsResult.toArray(new String[0]); 32 | } 33 | else { 34 | name = string.substring(1); 35 | arguments = new String[0]; 36 | } 37 | 38 | if (Plugin.debug) { 39 | Messages.debugString(sender, "script: " + string); 40 | Messages.debugString(sender, "name: @" + name); 41 | Messages.debugString(sender, "args: " + Arrays.toString(arguments)); 42 | } 43 | 44 | Messages.setVariable("script", name); 45 | 46 | switch (name) { 47 | case "sleep": 48 | if (arguments.length == 1 && arguments[0].matches("\\d+")) { 49 | SleepScript sleepScript = new SleepScript(); 50 | sleepScript.setTime(Integer.parseInt(arguments[0])); 51 | result = sleepScript; 52 | } 53 | break; 54 | case "title": 55 | String mainTitle, subTitle; 56 | if (!(sender instanceof Player)) { 57 | Messages.sendMessage(sender, "illegalScript"); 58 | } 59 | else if (arguments.length != 0) { 60 | mainTitle = arguments[0]; 61 | if (arguments.length >= 1) { 62 | subTitle = Strings.getRemainString(arguments, 1); 63 | } 64 | else { 65 | subTitle = null; 66 | } 67 | TitleScript titleScript = new TitleScript((Player) sender); 68 | titleScript.setMainTitle(mainTitle); 69 | titleScript.setSubTitle(subTitle); 70 | result = titleScript; 71 | } 72 | break; 73 | case "message": 74 | if (arguments.length >= 1) { 75 | String message = Strings.getRemainString(arguments, 0); 76 | MessageScript messageScript = new MessageScript(sender); 77 | messageScript.setMessage(message); 78 | result = messageScript; 79 | } 80 | break; 81 | default: 82 | Messages.sendMessage(sender, "unknownScript"); 83 | return null; 84 | } 85 | if (Objects.isNull(result)) { 86 | Messages.sendMessage(sender, "scriptSyntaxError"); 87 | } 88 | return result; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/script/SleepScript.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.script; 2 | 3 | public class SleepScript extends Script { 4 | private int time = 0; 5 | @Override 6 | public void run() { 7 | try { 8 | Thread.sleep(time); 9 | } 10 | catch (InterruptedException interruptedException) { 11 | interruptedException.printStackTrace(); 12 | } 13 | } 14 | 15 | public int getTime() { 16 | return time; 17 | } 18 | 19 | public void setTime(int time) { 20 | this.time = time; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/script/Strings.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.script; 2 | 3 | import com.sun.istack.internal.NotNull; 4 | import org.taixue.customcommands.language.Messages; 5 | import org.bukkit.command.CommandSender; 6 | 7 | public class Strings { 8 | private Strings() {} 9 | 10 | public static final String LEGAL_COMMAND_NAME_REGEX = "[a-zA-z0-9_][a-zA-z0-9_\\-]*"; 11 | public static final String LEGAL_VARIABLE_NAME_REGEX = "[a-zA-z_][a-zA-z0-9_]*"; 12 | public static final String LEGAL_GROUP_NAME_REGEX = "[^\\-].*"; 13 | 14 | public static final String DEFAULT_REGEX = ".+"; 15 | 16 | public static boolean isLegalCommandName(@NotNull String commandName) { 17 | return commandName.matches(LEGAL_COMMAND_NAME_REGEX); 18 | } 19 | 20 | public static boolean isLegalVariableName(@NotNull String variableName) { 21 | return variableName.matches(LEGAL_VARIABLE_NAME_REGEX); 22 | } 23 | 24 | public static boolean isLegalGroupName(@NotNull String variableName) { 25 | return variableName.matches(LEGAL_GROUP_NAME_REGEX); 26 | } 27 | 28 | 29 | public static String getRemainString(String[] strings, int beginIndex) { 30 | if (strings.length <= beginIndex) { 31 | return ""; 32 | } 33 | StringBuilder resultBuilder = new StringBuilder(strings[beginIndex]); 34 | for (int index = beginIndex + 1; index < strings.length; index++) { 35 | resultBuilder.append(" ").append(strings[index]); 36 | } 37 | return resultBuilder.toString(); 38 | } 39 | 40 | public static int getIndex(CommandSender commandSender, String indexString, int top) { 41 | Messages.setVariable("index", indexString); 42 | Messages.setVariable("top", top); 43 | if (indexString.matches("\\d+")) { 44 | int result = Integer.parseInt(indexString); 45 | if (result <= top && result >= 1) { 46 | return result; 47 | } 48 | else { 49 | Messages.sendMessage(commandSender, "illegalIndex"); 50 | return -1; 51 | } 52 | } 53 | else { 54 | Messages.sendMessage(commandSender, "illegalIndex"); 55 | return -1; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/script/TitleScript.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.script; 2 | 3 | import org.bukkit.entity.Player; 4 | 5 | public class TitleScript extends Script { 6 | Player player; 7 | String mainTitle, subTitle; 8 | 9 | public TitleScript(Player player) { 10 | setPlayer(player); 11 | } 12 | 13 | public void setMainTitle(String mainTitle) { 14 | this.mainTitle = mainTitle; 15 | } 16 | 17 | public void setSubTitle(String subTitle) { 18 | this.subTitle = subTitle; 19 | } 20 | 21 | public void setPlayer(Player player) { 22 | this.player = player; 23 | } 24 | 25 | public Player getPlayer() { 26 | return player; 27 | } 28 | 29 | public String getMainTitle() { 30 | return mainTitle; 31 | } 32 | 33 | public String getSubTitle() { 34 | return subTitle; 35 | } 36 | 37 | @Override 38 | public void run() { 39 | player.sendTitle(mainTitle, subTitle); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/util/Commands.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.util; 2 | 3 | import com.sun.istack.internal.NotNull; 4 | import com.sun.istack.internal.Nullable; 5 | import org.taixue.customcommands.customcommand.Command; 6 | import org.taixue.customcommands.customcommand.Group; 7 | import org.taixue.customcommands.language.Messages; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.configuration.MemorySection; 10 | 11 | import java.util.ArrayList; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | 15 | public class Commands { 16 | private Commands() {} 17 | 18 | @NotNull 19 | public static Command loadFromMemorySection(@NotNull Group addTo, 20 | @NotNull MemorySection memorySection) { 21 | Command result = new Command(); 22 | result.setName(memorySection.getName()); 23 | 24 | Messages.setVariable("command", result.getName()); 25 | result.setGroup(addTo); 26 | 27 | result.setFormat(((String) memorySection.get("format"))); 28 | Messages.setVariable("format", result.getFormat()); 29 | 30 | result.setActions(((List) memorySection.get("actions")).toArray(new String[0])); 31 | 32 | if (memorySection.contains("usage")) { 33 | result.setUsageString(((String) memorySection.get("usage"))); 34 | } 35 | else { 36 | result.setUsageString("/ccsr " + addTo.getName() + " " + result.getFormat()); 37 | } 38 | Messages.setVariable("usage", result.getUsageString()); 39 | 40 | if (memorySection.contains("identify")) { 41 | String identifyString = ((String) memorySection.get("identify")); 42 | Messages.setVariable("identify", identifyString); 43 | 44 | if (identifyString.contains(":")) { 45 | if (identifyString.startsWith("player")) { 46 | result.setIdentifyPlayer(identifyString.substring(identifyString.indexOf(":") + 1).trim()); 47 | } 48 | } 49 | else { 50 | result.setIdentify(Command.Identify.valueOf(identifyString.toUpperCase())); 51 | } 52 | } 53 | else { 54 | Messages.setVariable("identify", "auto"); 55 | result.setIdentify(Command.Identify.AUTO); 56 | } 57 | 58 | 59 | if (memorySection.contains("result")) { 60 | result.setResultString(((String) memorySection.get("result"))); 61 | } 62 | else { 63 | result.setResultString(null); 64 | } 65 | Messages.setVariable("result", result.getResultString()); 66 | 67 | if (memorySection.contains("permissions")) { 68 | result.setPermissions(((List) memorySection.get("permissions")).toArray(new String[0])); 69 | } 70 | else { 71 | result.setPermissions(new String[]{"ccs.run." + addTo.getName() + "." + result.getName()}); 72 | } 73 | 74 | result.setMatches(new HashMap<>()); 75 | // if (memorySection.contains("matches")) { 76 | // result.setMatches((Map) (Object) ((MemorySection) memorySection.get("matches")).getValues(false)); 77 | // } 78 | // else { 79 | // result.setMatches(new HashMap<>()); 80 | // } 81 | 82 | return result; 83 | } 84 | 85 | /** 86 | * 检查一个 CommandSender 是否具有使用某一个指令的权限 87 | * @param commandSender 88 | * @param command 89 | * @return 90 | */ 91 | public static boolean hasPermission(@NotNull CommandSender commandSender, 92 | @NotNull Command command) { 93 | boolean hasPermission = true; 94 | for (String permission: command.getPermissions()) { 95 | if (!commandSender.hasPermission(permission)) { 96 | return false; 97 | } 98 | } 99 | return true; 100 | } 101 | 102 | @NotNull 103 | public static ArrayList screenUsableCommand(@NotNull CommandSender commandSender, 104 | @NotNull ArrayList commands) { 105 | ArrayList result = new ArrayList<>(); 106 | for (Command command: commands) { 107 | if (hasPermission(commandSender, command)) { 108 | result.add(command); 109 | } 110 | } 111 | return result; 112 | } 113 | 114 | @NotNull 115 | public static ArrayList getNoRemainCommands(@NotNull ArrayList commands) { 116 | commands.removeIf(e -> e.hasRemain()); 117 | return commands; 118 | } 119 | 120 | public static boolean isLegalCommandMemorySection(@NotNull MemorySection memorySection) { 121 | if (memorySection.contains("format") && 122 | memorySection.contains("actions") && 123 | memorySection.get("format") instanceof String && 124 | memorySection.get("actions") instanceof List) { 125 | 126 | if (memorySection.contains("permissions") && !(memorySection.get("permissions") instanceof List)) { 127 | return false; 128 | } 129 | if (memorySection.contains("identify") && !(memorySection.get("identify") instanceof String && 130 | ((String) memorySection.get("identify")).matches("console|auto|bypass|player:\\w+"))) { 131 | return false; 132 | } 133 | if (memorySection.contains("usage") && !(memorySection.get("usage") instanceof String)) { 134 | return false; 135 | } 136 | if (memorySection.contains("result") && !(memorySection.get("result") instanceof String)) { 137 | return false; 138 | } 139 | if (memorySection.contains("matches") && !(memorySection.get("matches") instanceof List)) { 140 | return false; 141 | } 142 | return true; 143 | } 144 | else { 145 | return false; 146 | } 147 | } 148 | 149 | @NotNull 150 | public static Command getDefaultCommand(@NotNull Group group, String name) { 151 | Command command = new Command(name); 152 | Messages.setVariable("group", group.getName()); 153 | Messages.setVariable("command", command.getName()); 154 | command.setFormat("{remain}"); 155 | command.setActions(new String[0]); 156 | command.setUsageString("/ccsr " + group.getName() + " " + command.getFormat()); 157 | command.setIdentify(Command.Identify.AUTO); 158 | command.setResultString(null); 159 | command.setPermissions(new String[]{"ccs.run." + group.getName() + "." + command.getName()}); 160 | return command; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/util/Files.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.util; 2 | 3 | import com.sun.istack.internal.NotNull; 4 | 5 | import java.io.*; 6 | import java.util.Objects; 7 | 8 | public class Files { 9 | 10 | /** 11 | * 将一个 jar 内的文件复制到某地 12 | * @param srcFilePath jar 内的文件名 13 | * @param fos 复制到的 File 14 | * @return boolean true 当且仅当复制成功 15 | */ 16 | public static boolean fileCopy(@NotNull String srcFilePath, @NotNull File fos){ 17 | boolean flag = false; 18 | try { 19 | try (BufferedInputStream fis = new BufferedInputStream(Objects.requireNonNull(Files.class.getClassLoader().getResourceAsStream(srcFilePath))); 20 | BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(fos))) { 21 | byte[] buf = new byte[1024]; 22 | int c = 0; 23 | while ((c = fis.read(buf)) != -1) { 24 | bufferedOutputStream.write(buf, 0, c); 25 | } 26 | flag = true; 27 | } 28 | } catch (IOException e) { 29 | e.printStackTrace(); 30 | } 31 | catch (NullPointerException nullPointerException) { 32 | return false; 33 | } 34 | return flag; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/util/Groups.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.util; 2 | 3 | import com.sun.istack.internal.NotNull; 4 | import org.taixue.customcommands.customcommand.Command; 5 | import org.taixue.customcommands.customcommand.Group; 6 | import org.taixue.customcommands.language.Messages; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.configuration.MemorySection; 9 | 10 | import java.util.HashSet; 11 | import java.util.Map; 12 | import java.util.Set; 13 | 14 | public class Groups { 15 | private Groups() {} 16 | 17 | @NotNull 18 | public static Group loadFromMemorySection(@NotNull MemorySection memorySection) { 19 | Group result = new Group(); 20 | result.setName(memorySection.getName()); 21 | 22 | Messages.setVariable("group", result.getName()); 23 | 24 | Map commandMap = memorySection.getValues(false); 25 | Set loadedCommands = new HashSet<>(); 26 | for (String commandName: commandMap.keySet()) { 27 | Messages.setVariable("command", commandName); 28 | try { 29 | MemorySection subMemorySection = ((MemorySection) commandMap.get(commandName)); 30 | 31 | if (loadedCommands.contains(commandName)) { 32 | Messages.severeLanguage("redefinedCommands"); 33 | } 34 | else { 35 | if (Commands.isLegalCommandMemorySection(subMemorySection)) { 36 | loadedCommands.add(commandName); 37 | Command command = Commands.loadFromMemorySection(result, subMemorySection); 38 | if (command.isLegalParameters()) { 39 | if (command.isLegalMatches()) { 40 | result.addCommand(command); 41 | } 42 | else { 43 | Messages.severeLanguage("matchesError"); 44 | } 45 | } else { 46 | Messages.severeLanguage("illegalParameterName"); 47 | } 48 | } else { 49 | Messages.severeLanguage("wrongFormatForCommand"); 50 | } 51 | } 52 | } 53 | catch (Exception exception) { 54 | Messages.setException(exception); 55 | Messages.severeLanguage("exceptionInLoadingCommand"); 56 | exception.printStackTrace(); 57 | } 58 | } 59 | return result; 60 | } 61 | 62 | public static boolean hasPermission(@NotNull CommandSender commandSender, @NotNull Group group) { 63 | return hasPermission(commandSender, group.getName()); 64 | } 65 | 66 | public static boolean hasPermission(@NotNull CommandSender commandSender, @NotNull String groupName) { 67 | String permissionNode = "ccs.run." + groupName; 68 | Messages.setVariable("permission", permissionNode); 69 | return commandSender.hasPermission(permissionNode); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/org/taixue/customcommands/util/Paths.java: -------------------------------------------------------------------------------- 1 | package org.taixue.customcommands.util; 2 | 3 | public class Paths { 4 | private Paths() {} 5 | 6 | public static final String SPLIT = "/"; 7 | 8 | public static final String LANG_DIR = "lang"; 9 | 10 | public static final String CONFIG = "config.yml"; 11 | public static final String COMMANDS = "commands.yml"; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/commands.yml: -------------------------------------------------------------------------------- 1 | # see https://github.com/Chuanwise/CustomCommands 2 | 3 | commands: 4 | say: 5 | this: 6 | format: '{remain}' 7 | actions: 8 | - 'say {remain}' -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | # see https://github.com/Chuanwise/CustomCommands 2 | 3 | config: 4 | lang: 'zhcn' 5 | debug: false 6 | max-iterations: 10 7 | auto-save: true 8 | strong-match: true -------------------------------------------------------------------------------- /src/main/resources/lang/zhcn.json: -------------------------------------------------------------------------------- 1 | { 2 | "messageHead": "§7[§eCustom§7-§6Commands§7]§r ", 3 | "debugHead": "§7[§eCCS§7-§cDEBUG§7]§r ", 4 | "messageEndl": "\n{messageHead}", 5 | "wrongFormatForGroup": "指令组 {group} 格式错误", 6 | "wrongFormatForCommand": "指令 {command} 错误", 7 | "undefinedGroup": "未定义指令组 {group}", 8 | "matchesError": "在指令组 {group} 中的分支 {command} 的 matches 具有语法错误", 9 | "regexSyntaxError": "形式参数 {parameter} 的正则表达式 {regex} 语法错误:{exceptionMessage}", 10 | "illegalParameterName": "形式参数 {parameter} 名应该是仅由英文字母、数字和下划线组成的字符串", 11 | "illegalVariableName": "变量 {variable} 名应该是仅由英文字母、数字和下划线组成的字符串", 12 | "redefinedParameter": "形式参数 {parameter} 重定义", 13 | "extraArgs": "指令结尾未出现 remain 变量却包含额外的实参", 14 | "illegalIdentify": "发送指令的身份只能是 auto、console、bypass 或 player:{player}", 15 | "lackPermission": "缺少权限节点:{permission}", 16 | "parameterCannotBeBull": "形式参数 {parameter} 名应该是仅由英文字母、数字和下划线组成的字符串,不能为空", 17 | "illegalCommandName": "非法的指令名:{command}(位于指令组 {group} 中)", 18 | "illegalGroupName": "非法的指令组名:{group}", 19 | "exceptionInLoadingGroup": "加载指令组 {group} 时出现异常:{exception},查看控制台输出以获得详细信息", 20 | "exceptionInLoadingCommand": "加载指令 {command} 时出现异常:{exception},查看控制台输出以获得详细信息", 21 | "exceptionInLoadingFile": "读取文件 {file} 时出现异常:{exception},查看控制台输出以获得详细信息", 22 | "exceptionInExecutingCommand": "执行指令 {command} 时出现异常:{exception},查看控制台输出以获得详细信息", 23 | "exceptionInParsingCommand": "解析指令 {command} 时出现异常:{exception},查看控制台输出以获得详细信息", 24 | "exceptionInSavingCommands": "保存 commands.yml 时出现异常:{exception},查看控制台输出以获得详细信息", 25 | "exceptionInMatchingArgument": "使用正则表达式 {regex} 检查形式参数 {parameter} 时出现异常:", 26 | "exceptionInSavingEnvironment": "保存环境文件 {file} 时出现异常:{exception},查看控制台输出以获得详细信息", 27 | "exceptionInLoadingEnvironment": "加载环境文件 {file} 时出现异常:{exception},查看控制台输出以获得详细信息", 28 | "unknownException": "未知错误导致异常: {exception}", 29 | "groupNotFound": "未找到指令组:{group}", 30 | "noMatchableCommand": "未在指令组 {group} 中找到能与当前参数列表匹配的指令", 31 | "multipleCommands": "有 {size} 个指令与之匹配,请修改设置以消除歧义。", 32 | "noPermissionToMatch": "你没有权限匹配这些指令", 33 | "loadedGroups": "当前已加载的指令组:", 34 | "noAnyLoadedGroup": "没有加载任何指令组", 35 | "loadedCommand": "当前在指令组 {group} 中加载的指令有:", 36 | "noAnyLoadedCommand": "没有任何自定义指令,或 commands.yml 尚未重载。若希望重载,请使用 /ccs reload", 37 | "redefinedGroups": "重定义指令组:{group}", 38 | "redefinedCommands": "在指令组 {group} 中重定义指令:{command}", 39 | "scriptSyntaxError": "脚本 {script} 语法错误", 40 | "illegalScript": "当前环境下无法使用脚本 {script}。可能是 identify 和脚本不匹配。", 41 | "unknownScript": "未知脚本类型:{script}", 42 | "groupAlreadyExist": "指令组 {group} 已经存在了!", 43 | "groupAdded": "成功新增指令组 {group}", 44 | "groupRemoved": "成功删除指令组 {group}", 45 | "groupRenamed": "成功修改指令组名为 {group}", 46 | "commandAdded": "成功在添加指令组 {group} 中添加指令 {command}", 47 | "commandAlreadyExist": "指令组 {group} 中已经存在指令 {command}", 48 | "commandNotFound": "没有在指令组 {group} 中找到指令 {command},请考虑使用 /ccsc group {group} 查看当前组中的所有指令", 49 | "commandRemoved": "成功删除指令组 {group} 中的指令 {command}", 50 | "commandRenamed": "成功修改指令组 {group} 中的指令名为 {command}", 51 | "identifySet": "成功设置执行身份为 {identify}", 52 | "formatSet": "成功设置解析格式为 {format}", 53 | "illegalFormat": "解析格式 {format} 中存在语法错误", 54 | "resultSet": "成功设置结果信息为 {result}", 55 | "actionAdded": "成功追加执行指令 {action}", 56 | "actionNotFound": "没有在指令组 {group} 中的分支 {command} 下找到执行指令 {action},请考虑使用 /ccsr group {group} command {command} 以查看当前分支的信息", 57 | "actionRemoved": "成功移除执行指令 {action}", 58 | "actionsCleared": "成功清除执行指令", 59 | "actionsSet": "成功设置执行指令为 {action}", 60 | "actionEdited": "成功编辑第 {index} 条执行指令为 {action}", 61 | "illegalIndex": "错误的序号值:{index},它应该是处于 [1, {top}] 的整数", 62 | "permissionAlreadyExist": "指令分支 {command} 中已经存在必要权限 {permission}", 63 | "permissionAdded": "成功在指令分支 {command} 中添加必要权限 {permission}", 64 | "permissionNotFound": "没有在指令组 {group} 中的分支 {command} 下找到必要权限 {permission},请考虑使用 /ccsr group {group} command {command} 以查看当前分支的信息", 65 | "permissionRemoved": "成功删除指令分支 {command} 中的必要权限 {permission}", 66 | "permissionsCleared": "成功清空指令分支 {command} 中的必要权限。请注意 CustomCommands 不会自动添加关键权限 ccs.run.{group}.{command},任何人都可以匹配并执行当前分支 {command}。如需要添加该项,请考虑使用 /ccsc group {group} permissions default", 67 | "permissionsSet": "成功设置指令分支 {command} 中的必要权限为 {permission}", 68 | "permissionEdited": "成功编辑第 {index} 条必要权限为 {action}", 69 | "setPermissionsToDefault": "成功设置指令分支 {command} 中的必要权限为默认的 ccs.run.{group}.{command}", 70 | "groupSummary": "{group} ({size} 个指令分支)", 71 | "groupDetailsTitle": "--- 指令组:{group} ({size} 个指令分支) ---", 72 | "commandSummary": "{command} >> {format}, {size} actions", 73 | "commandDetailsTitle": "--- {command} ---", 74 | "commandsSaved": "成功保存指令配置文件", 75 | "operatorMustBePlayer": "当前操作只能由玩家发起", 76 | "wrongEnvironment": "{file} 不是合法的变量表文件", 77 | "cannotLoadEnvironment": "无法加载变量表:{file}", 78 | "unknownUUID": "未知玩家:UUID:{UUID}", 79 | "environmentLoaded": "成功加载环境文件 {file}", 80 | "variableSet": "变量 {variable} 已被设置为值 {value}", 81 | "variableNotFound": "未找到变量 {variable}", 82 | "variableRemoved": "成功删除变量 {variable}", 83 | "environmentCleared": "已清除环境中的所有变量", 84 | "loadingEnvironment": "正在加载环境 {environment}(位于文件 {file} 中)", 85 | "variableShouldBeString": "变量 {variable} 应该是一个字符串", 86 | "failToLoadEnvironment": "加载文件 {file} 中的环境失败", 87 | "loadedVariableTitle": "--- 环境 {environment} 中加载的变量 ({size} 个)---", 88 | "noAnyLoadedVariable": "该环境中没有加载任何变量", 89 | "onlinePlayerEnvironmentsLoaded": "已加载所有在线玩家的环境", 90 | "wattingPlayerLeave": "正在等待玩家 {player} 离开 {timeout} 秒后卸载玩家的私人变量表", 91 | "unloadedPlayerEnvironment": "已卸载玩家 {player} 的私人变量表", 92 | "interruptToWaitPlayerLeave": "玩家 {player} 加入服务器,停止等待卸载玩家的变量表", 93 | "loadedMessageVariableTitle": "--- 全局消息环境中加载的变量 ({size} 个)---" 94 | } -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: Custom-Commands 2 | main: org.taixue.customcommands.Plugin 3 | author: Chuanwise 4 | version: 4.2 5 | website: https://github.com/Chuanwise/CustomCommands/ 6 | 7 | # softdepend: [PlaceholderAPI] 8 | 9 | commands: 10 | customcommands: 11 | description: Generic Custom-commands command 12 | aliases: [ccs] 13 | usage: | 14 | Usage: 15 | /ccs reload reload all configurations 16 | /ccs version show version and some other information 17 | /ccs debug enable or disable debug mode 18 | /ccs sames with /ccs 19 | ... (see https://github.com/Chuanwise/CustomCommands) 20 | customcommandsconfig: 21 | description: Generic Custom-commands command for configuring 22 | aliases: [ccsc, ccsconfig] 23 | usage: 'see: https://github.com/Chuanwise/CustomCommands' 24 | customcommandsrun: 25 | description: Run configured commands 26 | aliases: [ccsr, ccsrun] 27 | usage: | 28 | Usage: 29 | /ccsr [arguments-list] 30 | ... (see https://github.com/Chuanwise/CustomCommands) 31 | customcommandsenvironment: 32 | description: Set, edit or remove a variable 33 | aliases: [ccse, ccsenv] 34 | usage: | 35 | Usage: 36 | /ccse set 37 | /ccse remove 38 | /ccse clear 39 | /ccse reload 40 | ... (see https://github.com/Chuanwise/CustomCommands) 41 | 42 | permissions: 43 | ccs.*: 44 | default: op 45 | description: Give players with op everything by default 46 | children: 47 | ccs.run.*: true 48 | ccs.version: 49 | default: true 50 | description: Permission to see version, name and other information of CustomCommands 51 | ccs.debug: 52 | default: op 53 | description: enable or disable debug mode 54 | ccs.reload: 55 | default: op 56 | description: reload all configurations 57 | ccs.config.val.set: 58 | default: op 59 | description: set value of variable in config.yml 60 | ccs.config.val.look: 61 | default: op 62 | description: look value of variable in config.yml 63 | ccs.env.global: 64 | default: op 65 | ccs.env.personal: 66 | default: true 67 | ccs.env.reload: 68 | default: op 69 | 70 | -------------------------------------------------------------------------------- /target/classes/commands.yml: -------------------------------------------------------------------------------- 1 | # see https://github.com/Chuanwise/CustomCommands 2 | 3 | commands: 4 | say: 5 | this: 6 | format: '{remain}' 7 | actions: 8 | - 'say {remain}' -------------------------------------------------------------------------------- /target/classes/config.yml: -------------------------------------------------------------------------------- 1 | # see https://github.com/Chuanwise/CustomCommands 2 | 3 | config: 4 | lang: 'zhcn' 5 | debug: false 6 | max-iterations: 10 7 | auto-save: true 8 | strong-match: true -------------------------------------------------------------------------------- /target/classes/lang/zhcn.json: -------------------------------------------------------------------------------- 1 | { 2 | "messageHead": "§7[§eCustom§7-§6Commands§7]§r ", 3 | "debugHead": "§7[§eCCS§7-§cDEBUG§7]§r ", 4 | "messageEndl": "\n{messageHead}", 5 | "wrongFormatForGroup": "指令组 {group} 格式错误", 6 | "wrongFormatForCommand": "指令 {command} 错误", 7 | "undefinedGroup": "未定义指令组 {group}", 8 | "matchesError": "在指令组 {group} 中的分支 {command} 的 matches 具有语法错误", 9 | "regexSyntaxError": "形式参数 {parameter} 的正则表达式 {regex} 语法错误:{exceptionMessage}", 10 | "illegalParameterName": "形式参数 {parameter} 名应该是仅由英文字母、数字和下划线组成的字符串", 11 | "illegalVariableName": "变量 {variable} 名应该是仅由英文字母、数字和下划线组成的字符串", 12 | "redefinedParameter": "形式参数 {parameter} 重定义", 13 | "extraArgs": "指令结尾未出现 remain 变量却包含额外的实参", 14 | "illegalIdentify": "发送指令的身份只能是 auto、console、bypass 或 player:{player}", 15 | "lackPermission": "缺少权限节点:{permission}", 16 | "parameterCannotBeBull": "形式参数 {parameter} 名应该是仅由英文字母、数字和下划线组成的字符串,不能为空", 17 | "illegalCommandName": "非法的指令名:{command}(位于指令组 {group} 中)", 18 | "illegalGroupName": "非法的指令组名:{group}", 19 | "exceptionInLoadingGroup": "加载指令组 {group} 时出现异常:{exception},查看控制台输出以获得详细信息", 20 | "exceptionInLoadingCommand": "加载指令 {command} 时出现异常:{exception},查看控制台输出以获得详细信息", 21 | "exceptionInLoadingFile": "读取文件 {file} 时出现异常:{exception},查看控制台输出以获得详细信息", 22 | "exceptionInExecutingCommand": "执行指令 {command} 时出现异常:{exception},查看控制台输出以获得详细信息", 23 | "exceptionInParsingCommand": "解析指令 {command} 时出现异常:{exception},查看控制台输出以获得详细信息", 24 | "exceptionInSavingCommands": "保存 commands.yml 时出现异常:{exception},查看控制台输出以获得详细信息", 25 | "exceptionInMatchingArgument": "使用正则表达式 {regex} 检查形式参数 {parameter} 时出现异常:", 26 | "exceptionInSavingEnvironment": "保存环境文件 {file} 时出现异常:{exception},查看控制台输出以获得详细信息", 27 | "exceptionInLoadingEnvironment": "加载环境文件 {file} 时出现异常:{exception},查看控制台输出以获得详细信息", 28 | "unknownException": "未知错误导致异常: {exception}", 29 | "groupNotFound": "未找到指令组:{group}", 30 | "noMatchableCommand": "未在指令组 {group} 中找到能与当前参数列表匹配的指令", 31 | "multipleCommands": "有 {size} 个指令与之匹配,请修改设置以消除歧义。", 32 | "noPermissionToMatch": "你没有权限匹配这些指令", 33 | "loadedGroups": "当前已加载的指令组:", 34 | "noAnyLoadedGroup": "没有加载任何指令组", 35 | "loadedCommand": "当前在指令组 {group} 中加载的指令有:", 36 | "noAnyLoadedCommand": "没有任何自定义指令,或 commands.yml 尚未重载。若希望重载,请使用 /ccs reload", 37 | "redefinedGroups": "重定义指令组:{group}", 38 | "redefinedCommands": "在指令组 {group} 中重定义指令:{command}", 39 | "scriptSyntaxError": "脚本 {script} 语法错误", 40 | "illegalScript": "当前环境下无法使用脚本 {script}。可能是 identify 和脚本不匹配。", 41 | "unknownScript": "未知脚本类型:{script}", 42 | "groupAlreadyExist": "指令组 {group} 已经存在了!", 43 | "groupAdded": "成功新增指令组 {group}", 44 | "groupRemoved": "成功删除指令组 {group}", 45 | "groupRenamed": "成功修改指令组名为 {group}", 46 | "commandAdded": "成功在添加指令组 {group} 中添加指令 {command}", 47 | "commandAlreadyExist": "指令组 {group} 中已经存在指令 {command}", 48 | "commandNotFound": "没有在指令组 {group} 中找到指令 {command},请考虑使用 /ccsc group {group} 查看当前组中的所有指令", 49 | "commandRemoved": "成功删除指令组 {group} 中的指令 {command}", 50 | "commandRenamed": "成功修改指令组 {group} 中的指令名为 {command}", 51 | "identifySet": "成功设置执行身份为 {identify}", 52 | "formatSet": "成功设置解析格式为 {format}", 53 | "illegalFormat": "解析格式 {format} 中存在语法错误", 54 | "resultSet": "成功设置结果信息为 {result}", 55 | "actionAdded": "成功追加执行指令 {action}", 56 | "actionNotFound": "没有在指令组 {group} 中的分支 {command} 下找到执行指令 {action},请考虑使用 /ccsr group {group} command {command} 以查看当前分支的信息", 57 | "actionRemoved": "成功移除执行指令 {action}", 58 | "actionsCleared": "成功清除执行指令", 59 | "actionsSet": "成功设置执行指令为 {action}", 60 | "actionEdited": "成功编辑第 {index} 条执行指令为 {action}", 61 | "illegalIndex": "错误的序号值:{index},它应该是处于 [1, {top}] 的整数", 62 | "permissionAlreadyExist": "指令分支 {command} 中已经存在必要权限 {permission}", 63 | "permissionAdded": "成功在指令分支 {command} 中添加必要权限 {permission}", 64 | "permissionNotFound": "没有在指令组 {group} 中的分支 {command} 下找到必要权限 {permission},请考虑使用 /ccsr group {group} command {command} 以查看当前分支的信息", 65 | "permissionRemoved": "成功删除指令分支 {command} 中的必要权限 {permission}", 66 | "permissionsCleared": "成功清空指令分支 {command} 中的必要权限。请注意 CustomCommands 不会自动添加关键权限 ccs.run.{group}.{command},任何人都可以匹配并执行当前分支 {command}。如需要添加该项,请考虑使用 /ccsc group {group} permissions default", 67 | "permissionsSet": "成功设置指令分支 {command} 中的必要权限为 {permission}", 68 | "permissionEdited": "成功编辑第 {index} 条必要权限为 {action}", 69 | "setPermissionsToDefault": "成功设置指令分支 {command} 中的必要权限为默认的 ccs.run.{group}.{command}", 70 | "groupSummary": "{group} ({size} 个指令分支)", 71 | "groupDetailsTitle": "--- 指令组:{group} ({size} 个指令分支) ---", 72 | "commandSummary": "{command} >> {format}, {size} actions", 73 | "commandDetailsTitle": "--- {command} ---", 74 | "commandsSaved": "成功保存指令配置文件", 75 | "operatorMustBePlayer": "当前操作只能由玩家发起", 76 | "wrongEnvironment": "{file} 不是合法的变量表文件", 77 | "cannotLoadEnvironment": "无法加载变量表:{file}", 78 | "unknownUUID": "未知玩家:UUID:{UUID}", 79 | "environmentLoaded": "成功加载环境文件 {file}", 80 | "variableSet": "变量 {variable} 已被设置为值 {value}", 81 | "variableNotFound": "未找到变量 {variable}", 82 | "variableRemoved": "成功删除变量 {variable}", 83 | "environmentCleared": "已清除环境中的所有变量", 84 | "loadingEnvironment": "正在加载环境 {environment}(位于文件 {file} 中)", 85 | "variableShouldBeString": "变量 {variable} 应该是一个字符串", 86 | "failToLoadEnvironment": "加载文件 {file} 中的环境失败", 87 | "loadedVariableTitle": "--- 环境 {environment} 中加载的变量 ({size} 个)---", 88 | "noAnyLoadedVariable": "该环境中没有加载任何变量", 89 | "onlinePlayerEnvironmentsLoaded": "已加载所有在线玩家的环境", 90 | "wattingPlayerLeave": "正在等待玩家 {player} 离开 {timeout} 秒后卸载玩家的私人变量表", 91 | "unloadedPlayerEnvironment": "已卸载玩家 {player} 的私人变量表", 92 | "interruptToWaitPlayerLeave": "玩家 {player} 加入服务器,停止等待卸载玩家的变量表", 93 | "loadedMessageVariableTitle": "--- 全局消息环境中加载的变量 ({size} 个)---" 94 | } -------------------------------------------------------------------------------- /target/classes/plugin.yml: -------------------------------------------------------------------------------- 1 | name: Custom-Commands 2 | main: org.taixue.customcommands.Plugin 3 | author: Chuanwise 4 | version: 4.2 5 | website: https://github.com/Chuanwise/CustomCommands/ 6 | 7 | # softdepend: [PlaceholderAPI] 8 | 9 | commands: 10 | customcommands: 11 | description: Generic Custom-commands command 12 | aliases: [ccs] 13 | usage: | 14 | Usage: 15 | /ccs reload reload all configurations 16 | /ccs version show version and some other information 17 | /ccs debug enable or disable debug mode 18 | /ccs sames with /ccs 19 | ... (see https://github.com/Chuanwise/CustomCommands) 20 | customcommandsconfig: 21 | description: Generic Custom-commands command for configuring 22 | aliases: [ccsc, ccsconfig] 23 | usage: 'see: https://github.com/Chuanwise/CustomCommands' 24 | customcommandsrun: 25 | description: Run configured commands 26 | aliases: [ccsr, ccsrun] 27 | usage: | 28 | Usage: 29 | /ccsr [arguments-list] 30 | ... (see https://github.com/Chuanwise/CustomCommands) 31 | customcommandsenvironment: 32 | description: Set, edit or remove a variable 33 | aliases: [ccse, ccsenv] 34 | usage: | 35 | Usage: 36 | /ccse set 37 | /ccse remove 38 | /ccse clear 39 | /ccse reload 40 | ... (see https://github.com/Chuanwise/CustomCommands) 41 | 42 | permissions: 43 | ccs.*: 44 | default: op 45 | description: Give players with op everything by default 46 | children: 47 | ccs.run.*: true 48 | ccs.version: 49 | default: true 50 | description: Permission to see version, name and other information of CustomCommands 51 | ccs.debug: 52 | default: op 53 | description: enable or disable debug mode 54 | ccs.reload: 55 | default: op 56 | description: reload all configurations 57 | ccs.config.val.set: 58 | default: op 59 | description: set value of variable in config.yml 60 | ccs.config.val.look: 61 | default: op 62 | description: look value of variable in config.yml 63 | ccs.env.global: 64 | default: op 65 | ccs.env.personal: 66 | default: true 67 | ccs.env.reload: 68 | default: op 69 | 70 | --------------------------------------------------------------------------------