From dc142b4fb3fcedb84fa29d7d1aee45437147c3ae Mon Sep 17 00:00:00 2001 From: Mateus Moreira Date: Tue, 31 Jul 2018 20:10:31 +0100 Subject: [PATCH] Uploading main project --- LICENSE | 674 ++++++++++++++++++ pom.xml | 116 +++ .../mattmoreira/citizenscmd/CitizensCMD.java | 446 ++++++++++++ .../citizenscmd/Listeners/NPCListener.java | 281 ++++++++ .../citizenscmd/Listeners/UpdateEvent.java | 43 ++ .../citizenscmd/commands/CMDAdd.java | 68 ++ .../citizenscmd/commands/CMDCooldown.java | 48 ++ .../citizenscmd/commands/CMDEdit.java | 117 +++ .../citizenscmd/commands/CMDHelp.java | 54 ++ .../citizenscmd/commands/CMDList.java | 71 ++ .../citizenscmd/commands/CMDPrice.java | 48 ++ .../citizenscmd/commands/CMDReload.java | 103 +++ .../citizenscmd/commands/CMDRemove.java | 88 +++ .../commands/base/CommandBase.java | 87 +++ .../commands/base/CommandHandler.java | 218 ++++++ .../citizenscmd/files/CooldownHandler.java | 166 +++++ .../citizenscmd/files/DataHandler.java | 412 +++++++++++ .../citizenscmd/files/LangHandler.java | 124 ++++ .../citizenscmd/metrics/Metrics.java | 661 +++++++++++++++++ .../permissions/PermissionsManager.java | 60 ++ .../schedulers/ConfirmScheduler.java | 47 ++ .../schedulers/CooldownScheduler.java | 34 + .../schedulers/UpdateScheduler.java | 42 ++ .../citizenscmd/updater/SpigotUpdater.java | 86 +++ .../citizenscmd/utility/DisplayFormat.java | 25 + .../citizenscmd/utility/EnumTypes.java | 33 + .../citizenscmd/utility/IHandler.java | 30 + .../mattmoreira/citizenscmd/utility/Path.java | 101 +++ .../citizenscmd/utility/TimeUtil.java | 177 +++++ .../mattmoreira/citizenscmd/utility/Util.java | 171 +++++ src/main/resources/config.yml | 18 + src/main/resources/lang/bg.yml | 62 ++ src/main/resources/lang/en.yml | 63 ++ src/main/resources/lang/pt.yml | 5 + src/main/resources/lang/ro.yml | 62 ++ src/main/resources/plugin.yml | 52 ++ 36 files changed, 4893 insertions(+) create mode 100644 LICENSE create mode 100644 pom.xml create mode 100644 src/main/java/me/mattmoreira/citizenscmd/CitizensCMD.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/Listeners/NPCListener.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/Listeners/UpdateEvent.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/commands/CMDAdd.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/commands/CMDCooldown.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/commands/CMDEdit.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/commands/CMDHelp.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/commands/CMDList.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/commands/CMDPrice.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/commands/CMDReload.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/commands/CMDRemove.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/commands/base/CommandBase.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/commands/base/CommandHandler.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/files/CooldownHandler.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/files/DataHandler.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/files/LangHandler.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/metrics/Metrics.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/permissions/PermissionsManager.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/schedulers/ConfirmScheduler.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/schedulers/CooldownScheduler.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/schedulers/UpdateScheduler.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/updater/SpigotUpdater.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/utility/DisplayFormat.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/utility/EnumTypes.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/utility/IHandler.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/utility/Path.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/utility/TimeUtil.java create mode 100644 src/main/java/me/mattmoreira/citizenscmd/utility/Util.java create mode 100644 src/main/resources/config.yml create mode 100644 src/main/resources/lang/bg.yml create mode 100644 src/main/resources/lang/en.yml create mode 100644 src/main/resources/lang/pt.yml create mode 100644 src/main/resources/lang/ro.yml create mode 100644 src/main/resources/plugin.yml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..65b8b5d --- /dev/null +++ b/pom.xml @@ -0,0 +1,116 @@ + + + 4.0.0 + + me.mattmoreira.plugins + citizens-cmd + 2.0-BETA + jar + + CitizensCMD + + citizens-cmd + + UTF-8 + + + + CitizensCMD + clean package + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-shade-plugin + 3.1.0 + + + package + + shade + + + true + + + + + + + + src/main/resources + true + + + + + + + + spigotmc-repo + https://hub.spigotmc.org/nexus/content/groups/public/ + + + sonatype + https://oss.sonatype.org/content/groups/public/ + + + rayzr-repo + https://cdn.rawgit.com/Rayzr522/maven-repo/master/ + + + everything + http://repo.citizensnpcs.co/ + + + placeholderapi + http://repo.extendedclip.com/content/repositories/placeholderapi/ + + + vault-repo + http://nexus.hc.to/content/repositories/pub_releases + + + + + + org.spigotmc + spigot-api + 1.13-R0.1-SNAPSHOT + provided + + + net.citizensnpcs + citizensapi + 2.0.23-SNAPSHOT + provided + + + me.rayzr522 + jsonmessage + 1.0.0 + + + me.clip + placeholderapi + 2.9.1 + provided + + + net.milkbowl.vault + VaultAPI + 1.6 + provided + + + \ No newline at end of file diff --git a/src/main/java/me/mattmoreira/citizenscmd/CitizensCMD.java b/src/main/java/me/mattmoreira/citizenscmd/CitizensCMD.java new file mode 100644 index 0000000..0405c57 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/CitizensCMD.java @@ -0,0 +1,446 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd; + +import me.mattmoreira.citizenscmd.Listeners.NPCListener; +import me.mattmoreira.citizenscmd.Listeners.UpdateEvent; +import me.mattmoreira.citizenscmd.commands.*; +import me.mattmoreira.citizenscmd.commands.base.CommandHandler; +import me.mattmoreira.citizenscmd.files.CooldownHandler; +import me.mattmoreira.citizenscmd.files.DataHandler; +import me.mattmoreira.citizenscmd.files.LangHandler; +import me.mattmoreira.citizenscmd.metrics.Metrics; +import me.mattmoreira.citizenscmd.permissions.PermissionsManager; +import me.mattmoreira.citizenscmd.schedulers.CooldownScheduler; +import me.mattmoreira.citizenscmd.schedulers.UpdateScheduler; +import me.mattmoreira.citizenscmd.updater.SpigotUpdater; +import me.mattmoreira.citizenscmd.utility.DisplayFormat; +import net.milkbowl.vault.economy.Economy; +import org.bukkit.Bukkit; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.util.HashMap; +import java.util.stream.Stream; + +import static me.mattmoreira.citizenscmd.utility.Util.*; + +public final class CitizensCMD extends JavaPlugin { + + /** + * Supported languages + */ + private final String[] REGISTERED_LANG_FILES = {"en", "pt", "ro", "bg"}; + + private static CitizensCMD plugin; + + private static CommandHandler commandHandler = null; + private static LangHandler lang = null; + private static DataHandler dataHandler = null; + private static CooldownHandler cooldownHandler = null; + private static PermissionsManager permissionsManager = null; + private static Economy economy = null; + + private static boolean papi = false; + private static boolean updateStatus = false; + private static boolean shift = false; + private static String newVersion; + private static DisplayFormat displayFormat; + + private static HashMap waitingList; + + public void onEnable() { + + plugin = this; + + commandHandler = new CommandHandler(); + commandHandler.enable(); + + if (!hasCitizens()) { + info(color(TAG + "&cCitizens &7is needed for this plugin to work!")); + info(color(TAG + "&cCitizens.jar &7is not installed on the server!")); + info(color(TAG + "&cDisabling CitizensCMD...")); + getServer().getPluginManager().disablePlugin(this); + return; + } + + new Metrics(this); + + info(color(TAG + "&3Citizens&cCMD &8&o" + getDescription().getVersion() + " &8By &3Mateus Moreira &c@LichtHund")); + + permissionsManager = new PermissionsManager(); + + dataHandler = new DataHandler(); + dataHandler.initialize(); + + cooldownHandler = new CooldownHandler(); + Bukkit.getScheduler().scheduleSyncDelayedTask(this, () -> cooldownHandler.initialize(), 30L); + + saveDefaultConfig(); + registerCommands(); + registerEvents(); + + registerLangs(); + setLang(getConfig().getString("lang")); + + if (hasPAPI()) { + switch (lang.getLanguage()) { + case "en": + info(color(TAG + "&7Using &aPlaceholderAPI&7!")); + break; + case "pt": + info(color(TAG + "&7Usando &aPlaceholderAPI&7!")); + break; + case "ro": + info(color(TAG + "&7Folositi &aPlaceholderAPI&7!")); + break; + case "bg": + info(color(TAG + "&7Използвайки &aPlaceholderAPI&7!")); + break; + } + papi = true; + } + + if (setupEconomy()) { + switch (lang.getLanguage()) { + case "en": + info(color(TAG + "&7Using &aVult&7!")); + break; + case "pt": + info(color(TAG + "&7Usando &aVult&7!")); + break; + case "ro": + info(color(TAG + "&7Folositi &aVult&7!")); + break; + case "bg": + info(color(TAG + "&7Използвайки &aVult&7!")); + break; + } + } + + waitingList = new HashMap<>(); + + if (getConfig().contains("cooldonw-time-display")) { + switch (getConfig().getString("cooldonw-time-display").toLowerCase()) { + case "short": + displayFormat = DisplayFormat.SHORT; + break; + case "medium": + displayFormat = DisplayFormat.MEDIUM; + break; + case "full": + displayFormat = DisplayFormat.FULL; + break; + default: + displayFormat = DisplayFormat.MEDIUM; + } + } else + displayFormat = DisplayFormat.MEDIUM; + + if (upCheck()) { + SpigotUpdater updater = new SpigotUpdater(this, 30224); + try { + // If there's an update, tell the user that they can update + if (updater.checkForUpdates()) { + updateStatus = true; + newVersion = updater.getLatestVersion(); + switch (lang.getLanguage()) { + case "en": + info(color(TAG + "&cA new version of CitizensCMD is now available:")); + break; + case "pt": + info(color(TAG + "&cA new version of CitizensCMD is now available:")); + break; + case "ro": + info(color(TAG + "&cO noua versiune a CitizensCMD este acum valabila:")); + break; + case "bg": + info(color(TAG + "&cНалична е нова версия на CitizensCMD:")); + break; + } + info(color(TAG + "&b&o" + updater.getResourceURL())); + } + } catch (Exception e) { + // If it can't check for an update, tell the user and throw an error. + info("Could not check for updates! Stacktrace:"); + e.printStackTrace(); + } + } + + new UpdateScheduler().runTaskTimerAsynchronously(this, 72000L, 72000L); + new CooldownScheduler().runTaskTimerAsynchronously(this, 36000L, 36000L); + } + + @Override + public void onDisable() { + commandHandler.disable(); + cooldownHandler.saveToFile(); + } + + + /** + * Checks if Citizens is installed or not on the server + * + * @return Returns true if Citizens is found and false if not + */ + private boolean hasCitizens() { + return Bukkit.getPluginManager().isPluginEnabled("Citizens"); + } + + /** + * Checks if PAPI is installed or not on the server + * + * @return Returns true if PAPI is found and false if not + */ + private boolean hasPAPI() { + return Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI"); + } + + /** + * Registers all the commands to be used + */ + private void registerCommands() { + getCommand("npcmd").setExecutor(commandHandler); + Stream.of(new CMDHelp(), new CMDAdd(), new CMDCooldown(), new CMDList(), new CMDReload(), new CMDRemove(), new CMDEdit(), new CMDPrice()).forEach(commandHandler::register); + } + + /** + * Registers all the events to be used + */ + private void registerEvents() { + PluginManager pm = getServer().getPluginManager(); + pm.registerEvents(new UpdateEvent(), this); + pm.registerEvents(new NPCListener(), this); + } + + /** + * Sets up the economy if Vault is present + * + * @return returns true or false depending on if Vault is or not present + */ + private boolean setupEconomy() { + if (getServer().getPluginManager().getPlugin("Vault") == null) { + return false; + } + RegisteredServiceProvider registeredServiceProvider = getServer().getServicesManager().getRegistration(Economy.class); + if (registeredServiceProvider == null) { + return false; + } + economy = registeredServiceProvider.getProvider(); + shift = getConfig().getBoolean("shift-confirm"); + return economy != null; + } + + /** + * Gets the plugin instance + * + * @return Returns instance of the plugin + */ + public static CitizensCMD getPlugin() { + return plugin; + } + + /** + * Creates all the language files + */ + private void registerLangs() { + File langFile; + + for (String registeredLangFile : REGISTERED_LANG_FILES) { + langFile = new File(CitizensCMD.getPlugin().getDataFolder(), "lang/" + registeredLangFile + ".yml"); + + if (!langFile.exists()) + CitizensCMD.getPlugin().saveResource("lang/" + registeredLangFile + ".yml", false); + } + + } + + /** + * Sets the language that is supposed to be used + */ + public void setLang(String language) { + switch (language.toLowerCase()) { + case "en": + case "eng": + case "english": + lang = new LangHandler("en"); + break; + + case "pt": + case "port": + case "portuguese": + lang = new LangHandler("pt"); + break; + + case "ro": + case "roma": + case "romanian": + lang = new LangHandler("ro"); + break; + + case "bg": + case "bulg": + case "bulgarian": + lang = new LangHandler("bg"); + break; + + default: + lang = new LangHandler("en"); + break; + } + lang.initialize(); + } + + /** + * Gets the language that is selected on the config + * + * @return returns the language + */ + public LangHandler getLang() { + return lang; + } + + /** + * Gets if or not should alert player of new update on join + * + * @return Returns update status + */ + public boolean getUpdateStatus() { + return updateStatus; + } + + /** + * Sets new update status from scheduler + * + * @param newUpdateStatus New boolean with the update status; + */ + public void setUpdateStatus(boolean newUpdateStatus) { + CitizensCMD.updateStatus = newUpdateStatus; + } + + /** + * Gets String with new version + * + * @return the new version + */ + public String getNewVersion() { + return newVersion; + } + + /** + * Sets the new version string + * + * @param newVersion the new version to be set + */ + public void setNewVersion(String newVersion) { + CitizensCMD.newVersion = newVersion; + } + + /** + * Gets the NPC data to be used in other classes without needing to open the file + * + * @return returns the DataHandler class + */ + public DataHandler getDataHandler() { + return dataHandler; + } + + /** + * Gets the cooldown handler to check for cooldown informations + * + * @return Returns the cooldown handler + */ + public CooldownHandler getCooldownHandler() { + return cooldownHandler; + } + + /** + * Gets the permission manager to set and unset permission + * + * @return the permission manager class + */ + public PermissionsManager getPermissionsManager() { + return permissionsManager; + } + + /** + * Gets the economy to be used + * + * @return Returns the economy + */ + public static Economy getEconomy() { + return economy; + } + + /** + * Gets the hashmap with the players waiting to confirm the NPC payment + * + * @return returns the list of players + */ + public HashMap getWaitingList() { + return waitingList; + } + + /** + * Checks if player needs to shift or not to confirm payment + * + * @return Returns the boolean of whether or not players should shift + */ + public boolean shouldShift() { + return shift; + } + + /** + * Sets the new shifting rule + * + * @param shift The new shifting rule + */ + public void setShift(boolean shift) { + CitizensCMD.shift = shift; + } + + /** + * Checks is PAPI is present or not + * + * @return Returns true if PAPI is being used + */ + public boolean papiEnabled() { + return papi; + } + + /** + * Gets the display format to be used + * + * @return Returns either SHORT, MEDIUM OR FULL + */ + public DisplayFormat getDisplayFormat() { + return displayFormat; + } + + /** + * Sets the new display format when reloading + * + * @param displayFormat The new display format + */ + public void setDisplayFormat(DisplayFormat displayFormat) { + CitizensCMD.displayFormat = displayFormat; + } +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/Listeners/NPCListener.java b/src/main/java/me/mattmoreira/citizenscmd/Listeners/NPCListener.java new file mode 100644 index 0000000..a86b613 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/Listeners/NPCListener.java @@ -0,0 +1,281 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.Listeners; + +import me.clip.placeholderapi.PlaceholderAPI; +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.schedulers.ConfirmScheduler; +import me.mattmoreira.citizenscmd.utility.EnumTypes; +import me.mattmoreira.citizenscmd.utility.Path; +import net.citizensnpcs.api.event.NPCLeftClickEvent; +import net.citizensnpcs.api.event.NPCRemoveEvent; +import net.citizensnpcs.api.event.NPCRightClickEvent; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static me.mattmoreira.citizenscmd.utility.TimeUtil.getFormattedTime; + +public class NPCListener implements Listener { + + public NPCListener() { + Bukkit.getMessenger().registerOutgoingPluginChannel(CitizensCMD.getPlugin(), "BungeeCord"); + } + + @EventHandler + public void onRightClick(NPCRightClickEvent event) { + int npc = event.getNPC().getId(); + Player player = event.getClicker(); + + if (!player.hasPermission("citizenscmd.use")) return; + + if (!CitizensCMD.getPlugin().getWaitingList().containsKey(player.getUniqueId().toString() + "." + npc)) { + if (!player.hasPermission("citizenscmd.bypass")) { + if (CitizensCMD.getPlugin().getCooldownHandler().onCooldown(npc, player.getUniqueId().toString())) { + String cooldownMessage; + if (CitizensCMD.getPlugin().getDataHandler().getNPCCooldown(npc) == -1) + cooldownMessage = CitizensCMD.getPlugin().getLang().getMessage(Path.ONE_TIME_CLICK); + else + cooldownMessage = CitizensCMD.getPlugin().getLang().getMessage(Path.ON_COOLDOWN); + player.sendMessage(cooldownMessage.replace("{time}", getFormattedTime(CitizensCMD.getPlugin().getCooldownHandler().getTimeLeft(npc, player.getUniqueId().toString()), CitizensCMD.getPlugin().getDisplayFormat()))); + return; + } + } + + if (CitizensCMD.getPlugin().getDataHandler().hasNoCommands(npc, EnumTypes.ClickType.RIGHT)) return; + } + + double price = CitizensCMD.getPlugin().getDataHandler().getPrice(npc); + + if (price > 0.0) { + if (CitizensCMD.getEconomy() != null) { + + if (!CitizensCMD.getPlugin().getWaitingList().containsKey(player.getUniqueId().toString() + "." + npc)) { + String messageConfirm = CitizensCMD.getPlugin().getLang().getMessage(Path.PAY_CONFIRM); + if (!CitizensCMD.getPlugin().shouldShift()) + messageConfirm = messageConfirm.replace("{shift}", ""); + else + messageConfirm = messageConfirm.replace("{shift}", "Shift "); + messageConfirm = messageConfirm.replace("{price}", String.valueOf(price)); + player.sendMessage(messageConfirm); + CitizensCMD.getPlugin().getWaitingList().put(player.getUniqueId().toString() + "." + npc, true); + new ConfirmScheduler(player, npc).runTaskLaterAsynchronously(CitizensCMD.getPlugin(), 300L); + return; + } + + if (CitizensCMD.getPlugin().shouldShift() && !player.isSneaking()) return; + + if (CitizensCMD.getEconomy().getBalance(player) < price) { + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.PAY_NO_MONEY)); + return; + } + + CitizensCMD.getPlugin().getWaitingList().remove(player.getUniqueId().toString() + "." + npc); + CitizensCMD.getEconomy().withdrawPlayer(player, price); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.PAY_COMPLETED).replace("{price}", String.valueOf(price))); + + } + } + + List permissions = new ArrayList<>(); + List commands = new ArrayList<>(); + + for (String list : CitizensCMD.getPlugin().getDataHandler().getClickCommandsData(npc, EnumTypes.ClickType.RIGHT)) { + Pattern pattern = Pattern.compile("\\[([^]]*)] ([^]]*)"); + Matcher matcher = pattern.matcher(list); + if (matcher.find()) { + permissions.add(matcher.group(1)); + String command = matcher.group(2); + if (command.contains("%p%")) + command = command.replace("%p%", player.getName()); + if (command.contains("%player%")) + command = command.replace("%player%", player.getName()); + if (CitizensCMD.getPlugin().papiEnabled()) + commands.add(PlaceholderAPI.setPlaceholders((OfflinePlayer) player, command)); + else + commands.add(command); + } + } + + if (permissions.size() != commands.size()) return; + + for (int i = 0; i < permissions.size(); i++) { + final int loopFinalPosition = i; + Bukkit.getScheduler().runTask(CitizensCMD.getPlugin(), () -> { + switch (permissions.get(loopFinalPosition).toLowerCase()) { + + case "console": + CitizensCMD.getPlugin().getServer().dispatchCommand(CitizensCMD.getPlugin().getServer().getConsoleSender(), commands.get(loopFinalPosition)); + break; + + case "none": + player.chat("/" + commands.get(loopFinalPosition)); + break; + + case "server": + changeServer(player, commands.get(loopFinalPosition)); + break; + + default: + CitizensCMD.getPlugin().getPermissionsManager().setPermission(player, permissions.get(loopFinalPosition)); + player.chat("/" + commands.get(loopFinalPosition)); + CitizensCMD.getPlugin().getPermissionsManager().unsetPermission(player, permissions.get(loopFinalPosition)); + } + }); + } + + if (!player.hasPermission("citizenscmd.bypass")) + CitizensCMD.getPlugin().getCooldownHandler().addInteraction(npc, player.getUniqueId().toString(), System.nanoTime()); + + } + + @EventHandler + public void onLeftClick(NPCLeftClickEvent event) { + int npc = event.getNPC().getId(); + Player player = event.getClicker(); + + if (!player.hasPermission("citizenscmd.use")) return; + + if (!CitizensCMD.getPlugin().getWaitingList().containsKey(player.getUniqueId().toString() + "." + npc)) { + if (!player.hasPermission("citizenscmd.bypass")) { + if (CitizensCMD.getPlugin().getCooldownHandler().onCooldown(npc, player.getUniqueId().toString())) { + String cooldownMessage; + if (CitizensCMD.getPlugin().getDataHandler().getNPCCooldown(npc) == -1) + cooldownMessage = CitizensCMD.getPlugin().getLang().getMessage(Path.ONE_TIME_CLICK); + else + cooldownMessage = CitizensCMD.getPlugin().getLang().getMessage(Path.ON_COOLDOWN); + player.sendMessage(cooldownMessage.replace("{time}", getFormattedTime(CitizensCMD.getPlugin().getCooldownHandler().getTimeLeft(npc, player.getUniqueId().toString()), CitizensCMD.getPlugin().getDisplayFormat()))); + return; + } + } + + if (CitizensCMD.getPlugin().getDataHandler().hasNoCommands(npc, EnumTypes.ClickType.LEFT)) return; + } + + double price = CitizensCMD.getPlugin().getDataHandler().getPrice(npc); + + if (price > 0.0) { + if (CitizensCMD.getEconomy() != null) { + + if (!CitizensCMD.getPlugin().getWaitingList().containsKey(player.getUniqueId().toString() + "." + npc)) { + String messageConfirm = CitizensCMD.getPlugin().getLang().getMessage(Path.PAY_CONFIRM); + if (!CitizensCMD.getPlugin().shouldShift()) + messageConfirm = messageConfirm.replace("{shift}", ""); + else + messageConfirm = messageConfirm.replace("{shift}", "Shift "); + messageConfirm = messageConfirm.replace("{price}", String.valueOf(price)); + player.sendMessage(messageConfirm); + CitizensCMD.getPlugin().getWaitingList().put(player.getUniqueId().toString() + "." + npc, true); + new ConfirmScheduler(player, npc).runTaskLaterAsynchronously(CitizensCMD.getPlugin(), 300L); + return; + } + + if (CitizensCMD.getPlugin().shouldShift() && !player.isSneaking()) return; + + CitizensCMD.getPlugin().getWaitingList().remove(player.getUniqueId().toString() + "." + npc); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.PAY_CANCELED)); + + } + } + + List permissions = new ArrayList<>(); + List commands = new ArrayList<>(); + + for (String list : CitizensCMD.getPlugin().getDataHandler().getClickCommandsData(npc, EnumTypes.ClickType.LEFT)) { + Pattern pattern = Pattern.compile("\\[([^]]*)] ([^]]*)"); + Matcher matcher = pattern.matcher(list); + if (matcher.find()) { + permissions.add(matcher.group(1)); + String command = matcher.group(2); + if (command.contains("%p%")) + command = command.replace("%p%", player.getName()); + if (command.contains("%player%")) + command = command.replace("%player%", player.getName()); + if (CitizensCMD.getPlugin().papiEnabled()) + commands.add(PlaceholderAPI.setPlaceholders((OfflinePlayer) player, command)); + else + commands.add(command); + } + } + + if (permissions.size() != commands.size()) return; + + for (int i = 0; i < permissions.size(); i++) { + final int loopFinalPosition = i; + Bukkit.getScheduler().runTask(CitizensCMD.getPlugin(), () -> { + switch (permissions.get(loopFinalPosition).toLowerCase()) { + + case "console": + CitizensCMD.getPlugin().getServer().dispatchCommand(CitizensCMD.getPlugin().getServer().getConsoleSender(), commands.get(loopFinalPosition)); + break; + + case "none": + player.chat("/" + commands.get(loopFinalPosition)); + break; + + case "server": + changeServer(player, commands.get(loopFinalPosition)); + break; + + default: + CitizensCMD.getPlugin().getPermissionsManager().setPermission(player, permissions.get(loopFinalPosition)); + player.chat("/" + commands.get(loopFinalPosition)); + CitizensCMD.getPlugin().getPermissionsManager().unsetPermission(player, permissions.get(loopFinalPosition)); + } + }); + } + + if (!player.hasPermission("citizenscmd.bypass")) + CitizensCMD.getPlugin().getCooldownHandler().addInteraction(npc, player.getUniqueId().toString(), System.nanoTime()); + } + + @EventHandler + public void onRemoveNPC(NPCRemoveEvent event) { + CitizensCMD.getPlugin().getDataHandler().removeNPCData(event.getNPC().getId()); + } + + /** + * Bungee cord connection method + * + * @param player The player to be sent to the server + * @param server the server name + */ + private void changeServer(Player player, String server) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream); + try { + dataOutputStream.writeUTF("Connect"); + dataOutputStream.writeUTF(server); + } catch (IOException e) { + e.printStackTrace(); + } + player.sendPluginMessage(CitizensCMD.getPlugin(), "BungeeCord", byteArrayOutputStream.toByteArray()); + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/Listeners/UpdateEvent.java b/src/main/java/me/mattmoreira/citizenscmd/Listeners/UpdateEvent.java new file mode 100644 index 0000000..1a16b3d --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/Listeners/UpdateEvent.java @@ -0,0 +1,43 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.Listeners; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.utility.Path; +import me.rayzr522.jsonmessage.JSONMessage; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +import static me.mattmoreira.citizenscmd.utility.Util.HEADER; +import static me.mattmoreira.citizenscmd.utility.Util.color; + +public class UpdateEvent implements Listener { + + @EventHandler (priority = EventPriority.NORMAL) + public void onPlayerJoin(PlayerJoinEvent event) { + if (CitizensCMD.getPlugin().getUpdateStatus() && event.getPlayer().hasPermission("citizenscmd.update")) { + JSONMessage.create(color(HEADER)).send(event.getPlayer()); + JSONMessage.create(color(CitizensCMD.getPlugin().getLang().getUncoloredMessage(Path.NEW_VERSION) + CitizensCMD.getPlugin().getNewVersion())).send(event.getPlayer()); + JSONMessage.create(color(CitizensCMD.getPlugin().getLang().getUncoloredMessage(Path.DOWNLOAD_AT) + " spigotmc.org/resources/citizens-CMD.30224/")).openURL("https://spigotmc.org/resources/citizens-CMD.30224/").send(event.getPlayer()); + } + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/commands/CMDAdd.java b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDAdd.java new file mode 100644 index 0000000..48bc1bc --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDAdd.java @@ -0,0 +1,68 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.commands; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.commands.base.CommandBase; +import org.bukkit.entity.Player; + +import java.util.Arrays; + +import static me.mattmoreira.citizenscmd.utility.Util.getSelectedNpcId; +import static me.mattmoreira.citizenscmd.utility.Util.npcNotSelected; + +public class CMDAdd extends CommandBase { + + public CMDAdd() { + super("add", "citizenscmd.add", false, null, 2, 512); + } + + /** + * Adds a command to an NPC via ingame command + * + * @param player Gets the player to check for which NPC is selected and send messages + * @param args Gets the command to be added to the NPC + */ + @Override + public void execute(Player player, String[] args) { + + if (npcNotSelected(player)) return; + + String permission = args[0]; + boolean left = false; + + StringBuilder stringBuilder = new StringBuilder(); + String[] commandsArray = Arrays.copyOfRange(args, 1, args.length); + commandsArray[0] = commandsArray[0].replace("/", ""); + + for (int i = 0; i < commandsArray.length; i++) { + if (commandsArray[i].equalsIgnoreCase("-l")) { + left = true; + break; + } + if (i == commandsArray.length - 1) stringBuilder.append(commandsArray[i]); + else stringBuilder.append(commandsArray[i]).append(" "); + } + + boolean finalLeft = left; + + CitizensCMD.getPlugin().getDataHandler().addCommand(getSelectedNpcId(player), permission, stringBuilder.toString().trim(), player, finalLeft); + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/commands/CMDCooldown.java b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDCooldown.java new file mode 100644 index 0000000..6bc42af --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDCooldown.java @@ -0,0 +1,48 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.commands; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.commands.base.CommandBase; +import me.mattmoreira.citizenscmd.utility.Path; +import org.bukkit.entity.Player; + +import static me.mattmoreira.citizenscmd.utility.Util.*; + +public class CMDCooldown extends CommandBase { + + public CMDCooldown() { + super("cooldown", "citizenscmd.cooldown", false, new String[]{"cd"}, 1, 1); + } + + @Override + public void execute(Player player, String[] args) { + + if (npcNotSelected(player)) return; + + if (notInteger(args[0])) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.INVALID_COOLDOWN)); + return; + } + + CitizensCMD.getPlugin().getDataHandler().setCooldown(getSelectedNpcId(player), Integer.valueOf(args[0]), player); + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/commands/CMDEdit.java b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDEdit.java new file mode 100644 index 0000000..57cb493 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDEdit.java @@ -0,0 +1,117 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.commands; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.commands.base.CommandBase; +import me.mattmoreira.citizenscmd.utility.EnumTypes; +import me.mattmoreira.citizenscmd.utility.Path; +import org.bukkit.entity.Player; + +import java.util.Arrays; + +import static me.mattmoreira.citizenscmd.utility.Util.*; + +public class CMDEdit extends CommandBase { + + public CMDEdit() { + super("edit", "citizenscmd.edit", false, null, 4, 512); + } + + @Override + public void execute(Player player, String[] args) { + + if (npcNotSelected(player)) return; + + if (notInteger(args[2])) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.INVALID_ID_NUMBER)); + return; + } + + int commandID = Integer.parseInt(args[2]); + int npc = getSelectedNpcId(player); + EnumTypes.ClickType click; + EnumTypes.EditType type; + + switch (args[0].toLowerCase()) { + case "cmd": + type = EnumTypes.EditType.CMD; + break; + case "perm": + if (args.length > 4) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.INVALID_PERMISSION)); + return; + } + type = EnumTypes.EditType.PERM; + break; + default: + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.INVALID_ARGUMENTS)); + return; + } + + switch (args[1].toLowerCase()) { + case "left": + int leftCommandSize = CitizensCMD.getPlugin().getDataHandler().getClickCommandsData(npc, EnumTypes.ClickType.LEFT).size(); + if (leftCommandSize == 0) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.NO_COMMANDS)); + return; + } + if (commandID < 1 || commandID > leftCommandSize) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.INVALID_ID_NUMBER)); + return; + } + click = EnumTypes.ClickType.LEFT; + break; + case "right": + int rightCommandSize = CitizensCMD.getPlugin().getDataHandler().getClickCommandsData(npc, EnumTypes.ClickType.RIGHT).size(); + if (rightCommandSize == 0) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.NO_COMMANDS)); + return; + } + if (commandID < 1 || commandID > rightCommandSize) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.INVALID_ID_NUMBER)); + return; + } + click = EnumTypes.ClickType.RIGHT; + break; + default: + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.INVALID_CLICK_TYPE)); + return; + } + + StringBuilder stringBuilder = new StringBuilder(); + String[] commandsArray = Arrays.copyOfRange(args, 3, args.length); + commandsArray[0] = commandsArray[0].replace("/", ""); + + for (int i = 0; i < commandsArray.length; i++) { + if (i == commandsArray.length - 1) stringBuilder.append(commandsArray[i]); + else stringBuilder.append(commandsArray[i]).append(" "); + } + + CitizensCMD.getPlugin().getDataHandler().edit(npc, commandID, click, type, stringBuilder.toString().trim(), player); + } +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/commands/CMDHelp.java b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDHelp.java new file mode 100644 index 0000000..bd05865 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDHelp.java @@ -0,0 +1,54 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.commands; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.commands.base.CommandBase; +import me.mattmoreira.citizenscmd.utility.Path; +import me.rayzr522.jsonmessage.JSONMessage; +import org.bukkit.entity.Player; + +import static me.mattmoreira.citizenscmd.utility.Util.HEADER; +import static me.mattmoreira.citizenscmd.utility.Util.color; + +/** + * Thank you GlareMasters for creating this class as an example! + */ +public class CMDHelp extends CommandBase { + + public CMDHelp() { + super("help", "citizenscmd.npcmd", false, null, 0, 0); + } + + @Override + public void execute(Player player, String[] args) { + JSONMessage.create(color(HEADER)).send(player); + JSONMessage.create(color(CitizensCMD.getPlugin().getLang().getUncoloredMessage(Path.HELP_VERSION) + " &c&o" + CitizensCMD.getPlugin().getDescription().getVersion())).send(player); + JSONMessage.create(color(CitizensCMD.getPlugin().getLang().getUncoloredMessage(Path.HELP_INFO))).send(player); + JSONMessage.create(color("&3/npcmd &cadd &b &6 &d[-l]")).suggestCommand("/npcmd add ").tooltip(color(CitizensCMD.getPlugin().getLang().getUncoloredMessage(Path.HELP_DESCRIPTION_ADD) + "\n" + CitizensCMD.getPlugin().getLang().getUncoloredMessage(Path.HELP_EXAMPLE) + "\n&3&o/npcmd &c&oadd &b&ossentials.heal &6&oheal")).send(player); + JSONMessage.create(color("&3/npcmd &ccooldown &6

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.commands; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.commands.base.CommandBase; +import me.mattmoreira.citizenscmd.utility.EnumTypes; +import me.mattmoreira.citizenscmd.utility.Path; +import me.rayzr522.jsonmessage.JSONMessage; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +import static me.mattmoreira.citizenscmd.utility.Util.*; + +public class CMDList extends CommandBase { + + public CMDList() { + super("list", "citizescmd.list", false, new String[]{"l"}, 0, 0); + } + + @Override + public void execute(Player player, String[] args) { + + if (npcNotSelected(player)) return; + + int npc = getSelectedNpcId(player); + + List leftCommands = CitizensCMD.getPlugin().getDataHandler().getClickCommandsData(npc, EnumTypes.ClickType.LEFT) != null ? CitizensCMD.getPlugin().getDataHandler().getClickCommandsData(npc, EnumTypes.ClickType.LEFT) : new ArrayList<>(); + List rightCommands = CitizensCMD.getPlugin().getDataHandler().getClickCommandsData(npc, EnumTypes.ClickType.RIGHT) != null ? CitizensCMD.getPlugin().getDataHandler().getClickCommandsData(npc, EnumTypes.ClickType.RIGHT) : new ArrayList<>(); + + player.sendMessage(color(HEADER)); + JSONMessage.create(color(CitizensCMD.getPlugin().getLang().getUncoloredMessage(Path.LIST_COOLDOWN) + CitizensCMD.getPlugin().getDataHandler().getNPCCooldown(npc))).tooltip(CitizensCMD.getPlugin().getLang().getMessage(Path.LIST_TOOLTIP)).suggestCommand("/npcmd cooldown ").send(player); + JSONMessage.create(color(CitizensCMD.getPlugin().getLang().getUncoloredMessage(Path.LIST_PRICE) + CitizensCMD.getPlugin().getDataHandler().getPrice(npc))).tooltip(CitizensCMD.getPlugin().getLang().getMessage(Path.LIST_TOOLTIP)).suggestCommand("/npcmd price ").send(player); + player.sendMessage(""); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.LIST_COUNT_RIGHT).replace("{count}", String.valueOf(rightCommands.size()))); + + int rightCount = 1; + for (String command : rightCommands) { + JSONMessage.create(color("&c" + rightCount + " &7- &7" + command.replace("[", "&8[&c").replace("]", "&8]&b"))).suggestCommand("/npcmd edit cmd right " + rightCount + " ").tooltip(CitizensCMD.getPlugin().getLang().getMessage(Path.LIST_TOOLTIP)).send(player); + rightCount++; + } + + player.sendMessage(""); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.LIST_COUNT_LEFT).replace("{count}", String.valueOf(leftCommands.size()))); + + int leftCount = 1; + for (String command : leftCommands) { + JSONMessage.create(color("&c" + leftCount + " &7- &7" + command.replace("[", "&8[&c").replace("]", "&8]&b"))).suggestCommand("/npcmd edit cmd left " + leftCount + " ").tooltip(CitizensCMD.getPlugin().getLang().getMessage(Path.LIST_TOOLTIP)).send(player); + leftCount++; + } + } + +} \ No newline at end of file diff --git a/src/main/java/me/mattmoreira/citizenscmd/commands/CMDPrice.java b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDPrice.java new file mode 100644 index 0000000..4b47dad --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDPrice.java @@ -0,0 +1,48 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.commands; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.commands.base.CommandBase; +import me.mattmoreira.citizenscmd.utility.Path; +import org.bukkit.entity.Player; + +import static me.mattmoreira.citizenscmd.utility.Util.*; + +public class CMDPrice extends CommandBase { + + public CMDPrice() { + super("price", "citizenscmd.price", false, new String[]{"cd"}, 1, 1); + } + + @Override + public void execute(Player player, String[] args) { + + if (npcNotSelected(player)) return; + + if (notDouble(args[0])) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.INVALID_PRICE)); + return; + } + + CitizensCMD.getPlugin().getDataHandler().setPrice(getSelectedNpcId(player), Double.valueOf(args[0]), player); + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/commands/CMDReload.java b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDReload.java new file mode 100644 index 0000000..27fe40d --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDReload.java @@ -0,0 +1,103 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.commands; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.commands.base.CommandBase; +import me.mattmoreira.citizenscmd.utility.DisplayFormat; +import me.mattmoreira.citizenscmd.utility.Path; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import static me.mattmoreira.citizenscmd.utility.Util.HEADER; +import static me.mattmoreira.citizenscmd.utility.Util.color; + +public class CMDReload extends CommandBase { + + public CMDReload() { + super("reload", "citizenscmd.reload", true, null, 0, 0); + } + + @Override + public void execute(Player player, String[] args) { + CitizensCMD.getPlugin().reloadConfig(); + CitizensCMD.getPlugin().saveConfig(); + CitizensCMD.getPlugin().setLang(CitizensCMD.getPlugin().getConfig().getString("lang")); + + if (CitizensCMD.getPlugin().getConfig().contains("cooldonw-time-display")) { + switch (CitizensCMD.getPlugin().getConfig().getString("cooldonw-time-display").toLowerCase()) { + case "short": + CitizensCMD.getPlugin().setDisplayFormat(DisplayFormat.SHORT); + break; + case "medium": + CitizensCMD.getPlugin().setDisplayFormat(DisplayFormat.MEDIUM); + break; + case "full": + CitizensCMD.getPlugin().setDisplayFormat(DisplayFormat.FULL); + break; + default: + CitizensCMD.getPlugin().setDisplayFormat(DisplayFormat.MEDIUM); + } + } else + CitizensCMD.getPlugin().setDisplayFormat(DisplayFormat.MEDIUM); + + if (CitizensCMD.getEconomy() != null) + CitizensCMD.getPlugin().setShift(CitizensCMD.getPlugin().getConfig().getBoolean("shift-confirm")); + + CitizensCMD.getPlugin().getDataHandler().reload(); + CitizensCMD.getPlugin().getCooldownHandler().reload(); + + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.RELOAD)); + } + + @Override + public void execute(CommandSender sender, String[] args) { + CitizensCMD.getPlugin().reloadConfig(); + CitizensCMD.getPlugin().saveConfig(); + CitizensCMD.getPlugin().setLang(CitizensCMD.getPlugin().getConfig().getString("lang")); + + if (CitizensCMD.getPlugin().getConfig().contains("cooldonw-time-display")) { + switch (CitizensCMD.getPlugin().getConfig().getString("cooldonw-time-display").toLowerCase()) { + case "short": + CitizensCMD.getPlugin().setDisplayFormat(DisplayFormat.SHORT); + break; + case "medium": + CitizensCMD.getPlugin().setDisplayFormat(DisplayFormat.MEDIUM); + break; + case "full": + CitizensCMD.getPlugin().setDisplayFormat(DisplayFormat.FULL); + break; + default: + CitizensCMD.getPlugin().setDisplayFormat(DisplayFormat.MEDIUM); + } + } else + CitizensCMD.getPlugin().setDisplayFormat(DisplayFormat.MEDIUM); + + if (CitizensCMD.getEconomy() != null) + CitizensCMD.getPlugin().setShift(CitizensCMD.getPlugin().getConfig().getBoolean("shift-confirm")); + + CitizensCMD.getPlugin().getDataHandler().reload(); + CitizensCMD.getPlugin().getCooldownHandler().reload(); + + sender.sendMessage(color(HEADER)); + sender.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.RELOAD)); + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/commands/CMDRemove.java b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDRemove.java new file mode 100644 index 0000000..7e27887 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/commands/CMDRemove.java @@ -0,0 +1,88 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.commands; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.commands.base.CommandBase; +import me.mattmoreira.citizenscmd.utility.EnumTypes; +import me.mattmoreira.citizenscmd.utility.Path; +import org.bukkit.entity.Player; + +import static me.mattmoreira.citizenscmd.utility.Util.*; + +public class CMDRemove extends CommandBase { + + public CMDRemove() { + super("remove", "citizenscmd.remove", false, new String[]{"delete", "del", "rem"}, 2, 2); + } + + @Override + public void execute(Player player, String[] args) { + + if (npcNotSelected(player)) return; + + if (notInteger(args[1])) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.INVALID_ID_NUMBER)); + return; + } + + int commandID = Integer.parseInt(args[1]); + int npc = getSelectedNpcId(player); + EnumTypes.ClickType click; + + switch (args[0]) { + case "left": + int leftCommandSize = CitizensCMD.getPlugin().getDataHandler().getClickCommandsData(npc, EnumTypes.ClickType.LEFT).size(); + if (leftCommandSize == 0) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.NO_COMMANDS)); + return; + } + if (commandID < 1 || commandID > leftCommandSize) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.INVALID_ID_NUMBER)); + return; + } + click = EnumTypes.ClickType.LEFT; + break; + case "right": + int rightCommandSize = CitizensCMD.getPlugin().getDataHandler().getClickCommandsData(npc, EnumTypes.ClickType.RIGHT).size(); + if (rightCommandSize == 0) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.NO_COMMANDS)); + return; + } + if (commandID < 0 || commandID > rightCommandSize) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.INVALID_ID_NUMBER)); + return; + } + click = EnumTypes.ClickType.RIGHT; + break; + default: + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.INVALID_CLICK_TYPE)); + return; + } + + CitizensCMD.getPlugin().getDataHandler().removeCommand(npc, commandID, click, player); + + } +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/commands/base/CommandBase.java b/src/main/java/me/mattmoreira/citizenscmd/commands/base/CommandBase.java new file mode 100644 index 0000000..4e16fba --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/commands/base/CommandBase.java @@ -0,0 +1,87 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.commands.base; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Thank you GlareMasters for creating this class! + */ +public abstract class CommandBase { + + private String name; + private String permission; + + private boolean allowConsole; + + private List aliases; + + private int minimumArguments; + private int maximumArguments; + + protected CommandBase(String name, String permission, boolean allowConsole, + String[] aliases, int minimumArguments, int maximumArguments) { + this.name = name; + this.permission = permission; + + this.allowConsole = allowConsole; + + this.aliases = aliases == null ? new ArrayList<>() : Arrays.asList(aliases); + + this.minimumArguments = minimumArguments; + this.maximumArguments = maximumArguments; + } + + public void execute(CommandSender sender, String[] args) { + throw new UnsupportedOperationException("Method not implemented"); + } + + public void execute(Player sender, String[] args) { + throw new UnsupportedOperationException("Method not implemented"); + } + + public String getName() { + return name; + } + + public String getPermission() { + return permission; + } + + public boolean allowConsole() { + return allowConsole; + } + + public List getAliases() { + return aliases; + } + + public int getMinimumArguments() { + return minimumArguments; + } + + public int getMaximumArguments() { + return maximumArguments; + } +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/commands/base/CommandHandler.java b/src/main/java/me/mattmoreira/citizenscmd/commands/base/CommandHandler.java new file mode 100644 index 0000000..b2025bd --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/commands/base/CommandHandler.java @@ -0,0 +1,218 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.commands.base; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.utility.IHandler; +import me.mattmoreira.citizenscmd.utility.Path; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static me.mattmoreira.citizenscmd.utility.Util.*; + +/** + * Thank you GlareMasters for creating this class! + */ +public class CommandHandler implements CommandExecutor, TabCompleter, IHandler { + + private List commands; + + @Override + public void enable() { + commands = new ArrayList<>(); + } + + @Override + public void disable() { + commands.clear(); + commands = null; + } + + public void register(CommandBase command) { + commands.add(command); + } + + @Override + public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { + if (!cmd.getName().equalsIgnoreCase("npcmd")) { + return true; + } + + if (args.length == 0 || args[0].isEmpty()) { + if (sender.hasPermission("citizenscmd.npcmd")) + if (sender instanceof Player) + getCommand("help").execute((Player) sender, args); + return true; + } + + for (CommandBase command : commands) { + if (!command.getName().equalsIgnoreCase(args[0]) && !command.getAliases() + .contains(args[0].toLowerCase())) { + continue; + } + + if (!command.allowConsole() && !(sender instanceof Player)) { + sender.sendMessage(color(HEADER)); + sender.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.CONSOLE_NOT_ALLOWED)); + return true; + } + + if (!sender.hasPermission(command.getPermission())) { + sender.sendMessage(color(HEADER)); + sender.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.NO_PERMISSION)); + return true; + } + + args = Arrays.copyOfRange(args, 1, args.length); + + if ((command.getMinimumArguments() != -1 && command.getMinimumArguments() > args.length) + || (command.getMaximumArguments() != -1 + && command.getMaximumArguments() < args.length)) { + sender.sendMessage(color(HEADER)); + sender.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.WRONG_USAGE)); + return true; + } + + if (command.allowConsole()) { + if (sender instanceof Player) + command.execute((Player) sender, args); + else + command.execute(sender, args); + return true; + } else { + command.execute((Player) sender, args); + return true; + } + } + sender.sendMessage(color(HEADER)); + sender.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.WRONG_USAGE)); + return true; + } + + private CommandBase getCommand(String name) { + return commands.stream().filter( + command -> command.getName() != null && command.getName().equalsIgnoreCase(name)) + .findFirst().orElse(null); + } + + public List getCommands() { + return commands; + } + + @Override + public List onTabComplete(CommandSender sender, Command cmd, String commandLabel, + String[] args) { + if (cmd.getName().equalsIgnoreCase("npcmd")) { + if (args.length == 1) { + List commandNames = new ArrayList<>(); + + if (!args[0].equals("")) { + for (String commandName : commands.stream().map(CommandBase::getName) + .collect(Collectors.toList())) { + if (!commandName.startsWith(args[0].toLowerCase())) continue; + commandNames.add(commandName); + } + } else { + commandNames = + commands.stream().map(CommandBase::getName) + .collect(Collectors.toList()); + } + + Collections.sort(commandNames); + + return commandNames; + + } else { + String subCMD = args[0].toLowerCase(); + switch (subCMD) { + case "add": + if (args.length == 2) return getCommandNames(subCMD, args, 1, (Player) sender); + break; + + case "remove": + if (npcNotSelectedNM((Player) sender)) break; + if (args.length == 2) return getCommandNames(subCMD, args, 1, (Player) sender); + if (args.length == 3) { + if (args[1].equalsIgnoreCase("left")) + return getCommandNames(subCMD, args, 2, (Player) sender); + else if (args[1].equalsIgnoreCase("right")) + return getCommandNames(subCMD, args, 3, (Player) sender); + } + break; + + case "edit": + if (npcNotSelectedNM((Player) sender)) break; + if (args.length == 2) return getCommandNames(subCMD, args, 1, (Player) sender); + if (args.length == 3) return getCommandNames(subCMD, args, 2, (Player) sender); + if (args.length == 4) { + if (args[2].equalsIgnoreCase("left")) + return getCommandNames(subCMD, args, 3, (Player) sender); + else if (args[2].equalsIgnoreCase("right")) + return getCommandNames(subCMD, args, 4, (Player) sender); + } + if (args.length == 5) { + if (args[1].equalsIgnoreCase("perm")) + return getCommandNames(subCMD, args, 5, (Player) sender); + } + break; + } + + } + } + + return null; + } + + /** + * Gets the subcomands to tab complete + * + * @param subCMD Gets the sub command, example, add, list, etc + * @param args Arguments from the command + * @param arg Number of arguments to get the correct from the getTabCompleteArgs() + * @return Returns list with Strings to the tab complete + */ + private List getCommandNames(String subCMD, String[] args, int arg, Player player) { + List commandNames = new ArrayList<>(); + String[][] argsComplete = getTabCompleteArgs(subCMD, player); + + if (!args[arg - 1].equals("")) { + for (String commandName : argsComplete[arg - 1]) { + if (arg + 1 > args.length) break; + if (!commandName.startsWith(args[arg].toLowerCase())) continue; + commandNames.add(commandName); + } + } else { + commandNames = Arrays.asList(argsComplete[arg - 1]); + } + + Collections.sort(commandNames); + + return commandNames; + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/files/CooldownHandler.java b/src/main/java/me/mattmoreira/citizenscmd/files/CooldownHandler.java new file mode 100644 index 0000000..93088c2 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/files/CooldownHandler.java @@ -0,0 +1,166 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.files; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + +import static me.mattmoreira.citizenscmd.utility.Util.*; + +public class CooldownHandler { + + private static File cooldownsFile; + private static File dir; + + private static FileConfiguration cooldownsConfigurator; + + private static HashMap cooldownData; + + /** + * Createst the basic of the class and starts the HashMap + */ + public void initialize() { + File pluginFolder = CitizensCMD.getPlugin().getDataFolder(); + dir = new File(pluginFolder + "/data"); + cooldownsFile = new File(dir.getPath(), "cooldowns.yml"); + cooldownsConfigurator = new YamlConfiguration(); + + cooldownData = new HashMap<>(); + + createBasics(); + cacheData(); + } + + + /** + * Creates files and folders + */ + private void createBasics() { + if (!dir.exists()) dir.mkdirs(); + + if (!cooldownsFile.exists()) { + try { + cooldownsFile.createNewFile(); + } catch (IOException e) { + info(color("&cError creating cooldowns file..")); + } + } + } + + /** + * Puts the data from the file in cache + */ + private void cacheData() { + try { + cooldownsConfigurator.load(cooldownsFile); + + if (!cooldownsConfigurator.contains("cooldown-data")) return; + + HashMap cachedDataFromSaves = CitizensCMD.getPlugin().getDataHandler().getCachedCooldownByID(); + + for (String parent : cooldownsConfigurator.getConfigurationSection("cooldown-data").getKeys(false)) { + for (String child : cooldownsConfigurator.getConfigurationSection("cooldown-data." + parent).getKeys(false)) { + for (String npc : cachedDataFromSaves.keySet()) { + if (npc.equalsIgnoreCase(parent) && ((getSecondsDifference(cooldownsConfigurator.getLong("cooldown-data." + parent + "." + child)) < cachedDataFromSaves.get(npc)) || cachedDataFromSaves.get(npc) == -1)) + cooldownData.put("cooldown-data." + parent + "." + child, cooldownsConfigurator.getLong("cooldown-data." + parent + "." + child)); + + } + } + } + } catch (IOException | InvalidConfigurationException e) { + e.printStackTrace(); + } + } + + /** + * Saves cached data to file + */ + public void saveToFile() { + try { + createBasics(); + cooldownsConfigurator.load(cooldownsFile); + + cooldownsConfigurator.set("cooldown-data", null); + + for (String path : cooldownData.keySet()) { + cooldownsConfigurator.set(path, cooldownData.get(path)); + } + + cooldownsConfigurator.save(cooldownsFile); + } catch (IOException | InvalidConfigurationException e) { + e.printStackTrace(); + } + } + + /** + * Adds an interaction, when ever a player clicks on the NPC + * + * @param npc the NPC id + * @param uuid The player UUID + * @param time the time it was clicked from System.nanoTime(); + */ + public void addInteraction(int npc, String uuid, long time) { + if (cooldownData.containsKey("cooldown-data.npc-" + npc + "." + uuid)) + cooldownData.replace("cooldown-data.npc-" + npc + "." + uuid, time); + else + cooldownData.put("cooldown-data.npc-" + npc + "." + uuid, time); + } + + /** + * Get's the time left on cooldown + * + * @param npc The NPC id to check + * @param uuid The player uuid + * @return returns in seconds the time left + */ + public int getTimeLeft(int npc, String uuid) { + return CitizensCMD.getPlugin().getDataHandler().getNPCCooldown(npc) - getSecondsDifference(cooldownData.get("cooldown-data.npc-" + npc + "." + uuid)); + } + + /** + * Checks if the NPC is on cooldown or not + * + * @param npc The NPC id + * @param uuid The player uuid + * @return returns true if on cooldown and false if not + */ + public boolean onCooldown(int npc, String uuid) { + if (cooldownData.containsKey("cooldown-data.npc-" + npc + "." + uuid)) { + if (CitizensCMD.getPlugin().getDataHandler().getNPCCooldown(npc) == -1) + return true; + else + return getSecondsDifference(cooldownData.get("cooldown-data.npc-" + npc + "." + uuid)) < CitizensCMD.getPlugin().getDataHandler().getNPCCooldown(npc); + } + return false; + } + + /** + * Reloads the cooldowns + */ + public void reload() { + saveToFile(); + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/files/DataHandler.java b/src/main/java/me/mattmoreira/citizenscmd/files/DataHandler.java new file mode 100644 index 0000000..0ba5204 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/files/DataHandler.java @@ -0,0 +1,412 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.files; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.utility.EnumTypes; +import me.mattmoreira.citizenscmd.utility.Path; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import static me.mattmoreira.citizenscmd.utility.Util.*; + +public class DataHandler { + + private static File savesFile; + private static File dir; + + private static FileConfiguration dataConfigurator; + + private HashMap data; + + /** + * Creates file and folder + */ + public void initialize() { + File pluginFolder = CitizensCMD.getPlugin().getDataFolder(); + dir = new File(pluginFolder + "/data"); + savesFile = new File(dir.getPath(), "saves.yml"); + dataConfigurator = new YamlConfiguration(); + + data = new HashMap<>(); + + createBasics(); + cacheData(); + } + + /** + * Creates files and folders + */ + private void createBasics() { + if (!dir.exists()) dir.mkdirs(); + + if (!savesFile.exists()) { + try { + savesFile.createNewFile(); + } catch (IOException e) { + info(color("&cError creating saves file..")); + } + } + } + + /** + * Caches the data from the file + */ + private void cacheData() { + new Thread(() -> { + + try { + dataConfigurator.load(savesFile); + + if (!dataConfigurator.contains("npc-data")) return; + + for (String parent : dataConfigurator.getConfigurationSection("npc-data").getKeys(false)) { + for (String child : dataConfigurator.getConfigurationSection("npc-data." + parent).getKeys(false)) { + switch (child.toLowerCase()) { + case "cooldown": + data.put("npc-data." + parent + "." + child, dataConfigurator.getInt("npc-data." + parent + "." + child)); + break; + + case "right-click-commands": + case "left-click-commands": + data.put("npc-data." + parent + "." + child, dataConfigurator.getStringList("npc-data." + parent + "." + child)); + break; + + case "price": + data.put("npc-data." + parent + "." + child, dataConfigurator.getDouble("npc-data." + parent + "." + child)); + break; + } + + } + } + + } catch (IOException | InvalidConfigurationException e) { + e.printStackTrace(); + } + + }).start(); + } + + /** + * Clears the data from the cache + */ + private void clearCache() { + data.clear(); + } + + /** + * Adds a new command to the NPC + * + * @param npc The NPC id + * @param permission The permission to access the command + * @param command The command + * @param player The player who run the command + * @param left If the command should be added to the left or right click + */ + public void addCommand(int npc, String permission, String command, Player player, boolean left) { + new Thread(() -> { + try { + createBasics(); + dataConfigurator.load(savesFile); + + List commandList = data.containsKey("npc-data.npc-" + npc + ".right-click-commands") ? (List) data.get("npc-data.npc-" + npc + ".right-click-commands") : new ArrayList<>(); + List commandListLeft = data.containsKey("npc-data.npc-" + npc + ".left-click-commands") ? (List) data.get("npc-data.npc-" + npc + ".left-click-commands") : new ArrayList<>(); + + if (!data.containsKey("npc-data.npc-" + npc + ".cooldown")) { + data.put("npc-data.npc-" + npc + ".cooldown", getDefaultCooldown()); + dataConfigurator.set("npc-data.npc-" + npc + ".cooldown", getDefaultCooldown()); + } + + if (left) commandListLeft.add("[" + permission + "] " + command); + else commandList.add("[" + permission + "] " + command); + + if (data.containsKey("npc-data.npc-" + npc + ".right-click-commands")) + data.replace("npc-data.npc-" + npc + ".right-click-commands", commandList); + else + data.put("npc-data.npc-" + npc + ".right-click-commands", commandList); + dataConfigurator.set("npc-data.npc-" + npc + ".right-click-commands", commandList); + + if (data.containsKey("npc-data.npc-" + npc + ".left-click-commands")) + data.replace("npc-data.npc-" + npc + ".left-click-commands", commandListLeft); + else + data.put("npc-data.npc-" + npc + ".left-click-commands", commandListLeft); + dataConfigurator.set("npc-data.npc-" + npc + ".left-click-commands", commandListLeft); + + if (!data.containsKey("npc-data.npc-" + npc + ".price")) { + data.put("npc-data.npc-" + npc + ".price", 0); + dataConfigurator.set("npc-data.npc-" + npc + ".price", 0); + } + + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.NPC_ADDED)); + + dataConfigurator.save(savesFile); + } catch (IOException | InvalidConfigurationException e) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.NPC_ADD_FAIL)); + } + }).start(); + } + + /** + * Sets the cooldown of the NPC command + * + * @param npc The NPC id + * @param cooldown The cooldown in seconds to be added + * @param player The player who run the command + */ + public void setCooldown(int npc, int cooldown, Player player) { + new Thread(() -> { + try { + createBasics(); + dataConfigurator.load(savesFile); + + dataConfigurator.set("npc-data.npc-" + npc + ".cooldown", cooldown); + + data.replace("npc-data.npc-" + npc + ".cooldown", cooldown); + + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.NPC_COOLDOWN_SET)); + + dataConfigurator.save(savesFile); + } catch (IOException | InvalidConfigurationException e) { + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.NPC_COOLDOWN_SET_ERROR)); + } + }).start(); + } + + /** + * Sets the price of the NPC command + * + * @param npc The NPC id + * @param price The price in seconds to be added + * @param player The player who run the command + */ + public void setPrice(int npc, double price, Player player) { + new Thread(() -> { + try { + createBasics(); + dataConfigurator.load(savesFile); + + dataConfigurator.set("npc-data.npc-" + npc + ".price", price); + + data.replace("npc-data.npc-" + npc + ".price", price); + + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.NPC_PRICE_SET)); + + dataConfigurator.save(savesFile); + } catch (IOException | InvalidConfigurationException e) { + e.printStackTrace(); + } + }).start(); + } + + /** + * Gets the click commands from the saves.yml + * + * @param npc The NPC id + * @param click The string with left or right + * @return Returns String list with commands + */ + public List getClickCommandsData(int npc, EnumTypes.ClickType click) { + return (List) data.get("npc-data.npc-" + npc + "." + click.toString().toLowerCase() + "-click-commands"); + } + + /** + * Gets the number of commands to tab complete + * + * @param npc The NPC id + * @param click The type of click, either left or right + * @return Returns arrays with strings to show on tab completion event + */ + public String[] getCompleteCommandsNumbers(int npc, EnumTypes.ClickType click) { + List commandList = (List) data.get("npc-data.npc-" + npc + "." + click.toString().toLowerCase() + "-click-commands"); + String commandSet[] = new String[commandList.size()]; + for (int i = 0; i < commandList.size(); i++) + commandSet[i] = "" + (i + 1); + return commandSet; + } + + /** + * Checks if the npc has any command in it + * + * @param npc The NPC id + * @param click The type of click either left or right + * @return Returns true if has and false if not + */ + public boolean hasNoCommands(int npc, EnumTypes.ClickType click) { + if (data.containsKey("npc-data.npc-" + npc + "." + click.toString().toLowerCase() + "-click-commands")) + return ((List) data.get("npc-data.npc-" + npc + "." + click.toString().toLowerCase() + "-click-commands")).isEmpty(); + return true; + } + + /** + * Gets the cooldown of the NPC + * + * @param npc the NPC id + * @return Returns the NPC cooldown + */ + public int getNPCCooldown(int npc) { + return data.containsKey("npc-data.npc-" + npc + ".cooldown") ? (int) data.get("npc-data.npc-" + npc + ".cooldown") : 0; + } + + /** + * Gets the price of the NPC + * + * @param npc The NPC id + * @return Returns the NPC price + */ + public double getPrice(int npc) { + return data.containsKey("npc-data.npc-" + npc + ".price") ? (double) data.get("npc-data.npc-" + npc + ".price") : 0.0; + } + + /** + * Removes a command from an NPC + * + * @param npc The NPC id + * @param commandID The command id + * @param click The click type, either left or right + * @param player The player to send the message to + */ + public void removeCommand(int npc, int commandID, EnumTypes.ClickType click, Player player) { + new Thread(() -> { + try { + createBasics(); + dataConfigurator.load(savesFile); + + List commands = getClickCommandsData(npc, click); + + commands.remove(commandID - 1); + + data.replace("npc-data.npc-" + npc + "." + click.toString().toLowerCase() + "-click-commands", commands); + dataConfigurator.set("npc-data.npc-" + npc + "." + click.toString().toLowerCase() + "-click-commands", commands); + + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.REMOVED_COMMAND)); + + dataConfigurator.save(savesFile); + } catch (IOException | InvalidConfigurationException e) { + e.printStackTrace(); + } + }).start(); + } + + /** + * Edits a command or permission from the NPC + * + * @param npc The NPC id + * @param commandID The command id + * @param click The click type either, left or right + * @param type The type to edit, either CMD or PERM + * @param newValue the new value for either the command or the permission + * @param player The player to send messages + */ + public void edit(int npc, int commandID, EnumTypes.ClickType click, EnumTypes.EditType type, String newValue, Player player) { + new Thread(() -> { + try { + createBasics(); + dataConfigurator.load(savesFile); + + List commandsData = getClickCommandsData(npc, click); + + String typeText = ""; + + switch (type) { + case CMD: + String tempCommand = commandsData.get(commandID - 1); + tempCommand = tempCommand.replaceAll(" ([^]]*)", " " + newValue); + commandsData.set(commandID - 1, tempCommand); + typeText = "command"; + break; + case PERM: + String tempPerm = commandsData.get(commandID - 1); + tempPerm = tempPerm.replaceAll("\\[([^]]*)]", "[" + newValue + "]"); + commandsData.set(commandID - 1, tempPerm); + typeText = "permission"; + break; + } + + data.replace("npc-data.npc-" + npc + "." + click.toString().toLowerCase() + "-click-commands", commandsData); + dataConfigurator.set("npc-data.npc-" + npc + "." + click.toString().toLowerCase() + "-click-commands", commandsData); + + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.EDITED_COMMAND).replace("{type}", typeText)); + + dataConfigurator.save(savesFile); + } catch (IOException | InvalidConfigurationException e) { + e.printStackTrace(); + } + }).start(); + } + + /** + * Removes the NPC data from the file + * + * @param npc the NPC id + */ + public void removeNPCData(int npc) { + new Thread(() -> { + try { + createBasics(); + dataConfigurator.load(savesFile); + + if (dataConfigurator.contains("npc-data.npc-" + npc)) + dataConfigurator.set("npc-data.npc-" + npc, null); + + clearCache(); + cacheData(); + + dataConfigurator.save(savesFile); + } catch (IOException | InvalidConfigurationException e) { + e.printStackTrace(); + } + }).start(); + } + + /** + * Gets the cached cooldowns of all NPCs to cache only the cooldowns that matter + * + * @return The cached cooldowns + */ + HashMap getCachedCooldownByID() { + HashMap cachedData = new HashMap<>(); + + for (String key : data.keySet()) { + String components[] = key.split("\\."); + if (components[2].equalsIgnoreCase("cooldown")) + cachedData.put(components[1], (Integer) data.get(key)); + } + return cachedData; + } + + public void reload() { + cacheData(); + initialize(); + } +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/files/LangHandler.java b/src/main/java/me/mattmoreira/citizenscmd/files/LangHandler.java new file mode 100644 index 0000000..9d8cfd6 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/files/LangHandler.java @@ -0,0 +1,124 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.files; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + +import static me.mattmoreira.citizenscmd.utility.Util.*; + +public class LangHandler { + + private String lang; + + private HashMap messages; + + public LangHandler(String lang) { + this.lang = lang; + } + + /** + * Send message to the console saying this is the language selected + */ + public void initialize() { + switch (lang) { + case "en": + info(color(TAG + "&7Using &aEnglish &7messages!")); + break; + + case "pt": + info(color(TAG + "&7Usando mensagens em Portugues!")); + break; + + case "ro": + info(color(TAG + "&7Folositi mesajele in Limba &aRomana&7!")); + break; + + case "bg": + info(color(TAG + "&7Използване на &aбългарски &7език!")); + break; + } + + messages = new HashMap<>(); + cacheMessage(); + } + + /** + * Caches all messages into a HashMap for easier access + */ + private void cacheMessage() { + new Thread(() -> { + File langFile; + FileConfiguration langConf; + + try { + langFile = new File(CitizensCMD.getPlugin().getDataFolder(), "lang/" + lang + ".yml"); + langConf = new YamlConfiguration(); + + if (!langFile.exists()) CitizensCMD.getPlugin().saveResource("lang/" + lang + ".yml", false); + + langConf.load(langFile); + + for (String parent : langConf.getConfigurationSection("messages").getKeys(false)) { + for (String child : langConf.getConfigurationSection("messages." + parent).getKeys(false)) + messages.put("messages." + parent + "." + child, langConf.getString("messages." + parent + "." + child)); + } + + } catch (IOException | InvalidConfigurationException e) { + e.printStackTrace(); + } + }).start(); + } + + /** + * Gets message from the lang file + * + * @param path String with the path to the message + * @return Returns String with colored message from file + */ + public String getMessage(String path) { + return color(messages.get(path)); + } + + /** + * Gets message from the lang file without color + * + * @param path String with the path to the message + * @return Returns String with message from file + */ + public String getUncoloredMessage(String path) { + return messages.get(path); + } + + /** + * Gets the selected language + * + * @return Returns the language being used + */ + public String getLanguage() { + return lang; + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/metrics/Metrics.java b/src/main/java/me/mattmoreira/citizenscmd/metrics/Metrics.java new file mode 100644 index 0000000..b31526c --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/metrics/Metrics.java @@ -0,0 +1,661 @@ +package me.mattmoreira.citizenscmd.metrics; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.ServicePriority; +import org.bukkit.plugin.java.JavaPlugin; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import javax.net.ssl.HttpsURLConnection; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.zip.GZIPOutputStream; + +/** + * bStats collects some data for plugin authors. + * + * Check out https://bStats.org/ to learn more about bStats! + */ +public class Metrics { + + static { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D + final String defaultPackage = new String( + new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); + final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure nobody just copy & pastes the example and use the wrong package names + if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + // The version of this bStats class + public static final int B_STATS_VERSION = 1; + + // The url to which the data is sent + private static final String URL = "https://bStats.org/submitData/bukkit"; + + // Should failed requests be logged? + private static boolean logFailedRequests; + + // The uuid of the server + private static String serverUUID; + + // The plugin + private final JavaPlugin plugin; + + // A list with all custom charts + private final List charts = new ArrayList<>(); + + /** + * Class constructor. + * + * @param plugin The plugin which stats should be submitted. + */ + public Metrics(JavaPlugin plugin) { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null!"); + } + this.plugin = plugin; + + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + + // Check if the config file exists + if (!config.isSet("serverUuid")) { + + // Add default values + config.addDefault("enabled", true); + // Every server gets it's unique random id. + config.addDefault("serverUuid", UUID.randomUUID().toString()); + // Should failed request be logged? + config.addDefault("logFailedRequests", false); + + // Inform the server owners about bStats + config.options().header( + "bStats collects some data for plugin authors like how many servers are using their plugins.\n" + + "To honor their work, you should not disable it.\n" + + "This has nearly no effect on the server performance!\n" + + "Check out https://bStats.org/ to learn more :)" + ).copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { } + } + + // Load the data + serverUUID = config.getString("serverUuid"); + logFailedRequests = config.getBoolean("logFailedRequests", false); + if (config.getBoolean("enabled", true)) { + boolean found = false; + // Search for all other bStats Metrics classes to see if we are the first one + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + found = true; // We aren't the first + break; + } catch (NoSuchFieldException ignored) { } + } + // Register our service + Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal); + if (!found) { + // We are the first! + startSubmitting(); + } + } + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + if (chart == null) { + throw new IllegalArgumentException("Chart cannot be null!"); + } + charts.add(chart); + } + + /** + * Starts the Scheduler which submits our data every 30 minutes. + */ + private void startSubmitting() { + final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + if (!plugin.isEnabled()) { // Plugin was disabled + timer.cancel(); + return; + } + // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler + // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) + Bukkit.getScheduler().runTask(plugin, new Runnable() { + @Override + public void run() { + submitData(); + } + }); + } + }, 1000*60*5, 1000*60*30); + // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start + // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! + // WARNING: Just don't do it! + } + + /** + * Gets the plugin specific data. + * This method is called using Reflection. + * + * @return The plugin specific data. + */ + public JSONObject getPluginData() { + JSONObject data = new JSONObject(); + + String pluginName = plugin.getDescription().getName(); + String pluginVersion = plugin.getDescription().getVersion(); + + data.put("pluginName", pluginName); // Append the name of the plugin + data.put("pluginVersion", pluginVersion); // Append the version of the plugin + JSONArray customCharts = new JSONArray(); + for (CustomChart customChart : charts) { + // Add the data of the custom charts + JSONObject chart = customChart.getRequestJsonObject(); + if (chart == null) { // If the chart is null, we skip it + continue; + } + customCharts.add(chart); + } + data.put("customCharts", customCharts); + + return data; + } + + /** + * Gets the server specific data. + * + * @return The server specific data. + */ + private JSONObject getServerData() { + // Minecraft specific data + int playerAmount; + try { + // Around MC 1.8 the return type was changed to a collection from an array, + // This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed + } + int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; + String bukkitVersion = org.bukkit.Bukkit.getVersion(); + bukkitVersion = bukkitVersion.substring(bukkitVersion.indexOf("MC: ") + 4, bukkitVersion.length() - 1); + + // OS/Java specific data + String javaVersion = System.getProperty("java.version"); + String osName = System.getProperty("os.name"); + String osArch = System.getProperty("os.arch"); + String osVersion = System.getProperty("os.version"); + int coreCount = Runtime.getRuntime().availableProcessors(); + + JSONObject data = new JSONObject(); + + data.put("serverUUID", serverUUID); + + data.put("playerAmount", playerAmount); + data.put("onlineMode", onlineMode); + data.put("bukkitVersion", bukkitVersion); + + data.put("javaVersion", javaVersion); + data.put("osName", osName); + data.put("osArch", osArch); + data.put("osVersion", osVersion); + data.put("coreCount", coreCount); + + return data; + } + + /** + * Collects the data and sends it afterwards. + */ + private void submitData() { + final JSONObject data = getServerData(); + + JSONArray pluginData = new JSONArray(); + // Search for all other bStats Metrics classes to get their plugin data + for (Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); // Our identifier :) + + for (RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) { + try { + pluginData.add(provider.getService().getMethod("getPluginData").invoke(provider.getProvider())); + } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { } + } + } catch (NoSuchFieldException ignored) { } + } + + data.put("plugins", pluginData); + + // Create a new thread for the connection to the bStats server + new Thread(new Runnable() { + @Override + public void run() { + try { + // Send the data + sendData(data); + } catch (Exception e) { + // Something went wrong! :( + if (logFailedRequests) { + plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); + } + } + } + }).start(); + } + + /** + * Sends the data to the bStats server. + * + * @param data The data to send. + * @throws Exception If the request failed. + */ + private static void sendData(JSONObject data) throws Exception { + if (data == null) { + throw new IllegalArgumentException("Data cannot be null!"); + } + if (Bukkit.isPrimaryThread()) { + throw new IllegalAccessException("This method must not be called from the main thread!"); + } + HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); + + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + + // Add headers + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format + connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); + + // Send data + connection.setDoOutput(true); + DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream()); + outputStream.write(compressedData); + outputStream.flush(); + outputStream.close(); + + connection.getInputStream().close(); // We don't care about the response - Just send our data :) + } + + /** + * Gzips the given String. + * + * @param str The string to gzip. + * @return The gzipped String. + * @throws IOException If the compression failed. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + GZIPOutputStream gzip = new GZIPOutputStream(outputStream); + gzip.write(str.getBytes("UTF-8")); + gzip.close(); + return outputStream.toByteArray(); + } + + /** + * Represents a custom chart. + */ + public static abstract class CustomChart { + + // The id of the chart + final String chartId; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + */ + CustomChart(String chartId) { + if (chartId == null || chartId.isEmpty()) { + throw new IllegalArgumentException("ChartId cannot be null or empty!"); + } + this.chartId = chartId; + } + + private JSONObject getRequestJsonObject() { + JSONObject chart = new JSONObject(); + chart.put("chartId", chartId); + try { + JSONObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + chart.put("data", data); + } catch (Throwable t) { + if (logFailedRequests) { + Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t); + } + return null; + } + return chart; + } + + protected abstract JSONObject getChartData() throws Exception; + + } + + /** + * Represents a custom simple pie. + */ + public static class SimplePie extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + data.put("value", value); + return data; + } + } + + /** + * Represents a custom advanced pie. + */ + public static class AdvancedPie extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; // Skip this invalid + } + allSkipped = false; + values.put(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + } + + /** + * Represents a custom drilldown pie. + */ + public static class DrilldownPie extends CustomChart { + + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JSONObject value = new JSONObject(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + value.put(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + values.put(entryValues.getKey(), value); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + } + + /** + * Represents a custom single line chart. + */ + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + data.put("value", value); + return data; + } + + } + + /** + * Represents a custom multi line chart. + */ + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; // Skip this invalid + } + allSkipped = false; + values.put(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + + } + + /** + * Represents a custom simple bar chart. + */ + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + JSONArray categoryValues = new JSONArray(); + categoryValues.add(entry.getValue()); + values.put(entry.getKey(), categoryValues); + } + data.put("values", values); + return data; + } + + } + + /** + * Represents a custom advanced bar chart. + */ + public static class AdvancedBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JSONObject getChartData() throws Exception { + JSONObject data = new JSONObject(); + JSONObject values = new JSONObject(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + continue; // Skip this invalid + } + allSkipped = false; + JSONArray categoryValues = new JSONArray(); + for (int categoryValue : entry.getValue()) { + categoryValues.add(categoryValue); + } + values.put(entry.getKey(), categoryValues); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + data.put("values", values); + return data; + } + + } +} \ No newline at end of file diff --git a/src/main/java/me/mattmoreira/citizenscmd/permissions/PermissionsManager.java b/src/main/java/me/mattmoreira/citizenscmd/permissions/PermissionsManager.java new file mode 100644 index 0000000..e843349 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/permissions/PermissionsManager.java @@ -0,0 +1,60 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.permissions; + + +import me.mattmoreira.citizenscmd.CitizensCMD; +import org.bukkit.entity.Player; +import org.bukkit.permissions.PermissionAttachment; + +import java.util.HashMap; +import java.util.UUID; + +public class PermissionsManager { + + private HashMap permissionsData; + + public PermissionsManager() { + permissionsData = new HashMap<>(); + } + + /** + * Sets the permission to a player + * + * @param player The player to have the permission set + * @param permission The permission node + */ + public void setPermission(Player player, String permission) { + PermissionAttachment permissionAttachment = player.addAttachment(CitizensCMD.getPlugin()); + permissionsData.put(player.getUniqueId(), permissionAttachment); + PermissionAttachment permissionAttachment1 = permissionsData.get(player.getUniqueId()); + permissionAttachment1.setPermission(permission, true); + } + + /** + * Removes the permission from a player + * + * @param player The player to remove the permission + * @param permission The permission node to be removed + */ + public void unsetPermission(Player player, String permission) { + permissionsData.get(player.getUniqueId()).unsetPermission(permission); + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/schedulers/ConfirmScheduler.java b/src/main/java/me/mattmoreira/citizenscmd/schedulers/ConfirmScheduler.java new file mode 100644 index 0000000..4ee6e05 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/schedulers/ConfirmScheduler.java @@ -0,0 +1,47 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.schedulers; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.utility.Path; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +public class ConfirmScheduler extends BukkitRunnable { + + private Player player; + private int npc; + + public ConfirmScheduler(Player player, int npc) { + this.player = player; + this.npc = npc; + } + + /** + * Removes the data from the player in case it hasn't click on the NPC to confirm the payment + */ + @Override + public void run() { + if (CitizensCMD.getPlugin().getWaitingList().containsKey(player.getUniqueId().toString() + "." + npc)) { + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.PAY_CANCELED)); + CitizensCMD.getPlugin().getWaitingList().remove(player.getUniqueId().toString() + "." + npc); + } + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/schedulers/CooldownScheduler.java b/src/main/java/me/mattmoreira/citizenscmd/schedulers/CooldownScheduler.java new file mode 100644 index 0000000..b3c515b --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/schedulers/CooldownScheduler.java @@ -0,0 +1,34 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.schedulers; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import org.bukkit.scheduler.BukkitRunnable; + +public class CooldownScheduler extends BukkitRunnable { + + /** + * Saves the cached cooldowns on file every 30 minutes + */ + @Override + public void run() { + CitizensCMD.getPlugin().getCooldownHandler().saveToFile(); + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/schedulers/UpdateScheduler.java b/src/main/java/me/mattmoreira/citizenscmd/schedulers/UpdateScheduler.java new file mode 100644 index 0000000..b4516aa --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/schedulers/UpdateScheduler.java @@ -0,0 +1,42 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.schedulers; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import me.mattmoreira.citizenscmd.updater.SpigotUpdater; +import org.bukkit.scheduler.BukkitRunnable; + +public class UpdateScheduler extends BukkitRunnable { + + /** + * Checks for updates every hour and tells the player on join + */ + @Override + public void run() { + SpigotUpdater updater = new SpigotUpdater(CitizensCMD.getPlugin(), 30224); + try { + if (updater.checkForUpdates()) { + CitizensCMD.getPlugin().setUpdateStatus(true); + CitizensCMD.getPlugin().setNewVersion(updater.getLatestVersion()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/updater/SpigotUpdater.java b/src/main/java/me/mattmoreira/citizenscmd/updater/SpigotUpdater.java new file mode 100644 index 0000000..0061395 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/updater/SpigotUpdater.java @@ -0,0 +1,86 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.updater; + +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +/** + * Created by GlareMasters on 5/30/2018. + */ +public class SpigotUpdater { + + private int project; + private URL checkURL; + private String newVersion; + private JavaPlugin plugin; + + public SpigotUpdater(JavaPlugin plugin, int projectID) { + this.plugin = plugin; + this.newVersion = plugin.getDescription().getVersion(); + this.project = projectID; + try { + this.checkURL = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + projectID); + } catch (MalformedURLException e) { + System.out.println("Could not check for plugin update."); + } + } + + public JavaPlugin getPlugin() { + return plugin; + } + + /** + * Check latest plugin version + * + * @return latest version + * @throws Exception I/O Exception + */ + public String getLatestVersion() throws Exception { + URLConnection con = checkURL.openConnection(); + this.newVersion = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine(); + return newVersion; + } + + /** + * Get the URL of the plugin + * + * @return URL of plugin + */ + public String getResourceURL() { + return "https://www.spigotmc.org/resources/" + project; + } + + /** + * Check for updates + * + * @return if plugin version is the latest plugin version + * @throws Exception I/O Exception + */ + public boolean checkForUpdates() throws Exception { + URLConnection con = checkURL.openConnection(); + this.newVersion = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine(); + return !plugin.getDescription().getVersion().equals(newVersion); + } +} \ No newline at end of file diff --git a/src/main/java/me/mattmoreira/citizenscmd/utility/DisplayFormat.java b/src/main/java/me/mattmoreira/citizenscmd/utility/DisplayFormat.java new file mode 100644 index 0000000..6df8365 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/utility/DisplayFormat.java @@ -0,0 +1,25 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.utility; + +public enum DisplayFormat { + SHORT, + MEDIUM, + FULL +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/utility/EnumTypes.java b/src/main/java/me/mattmoreira/citizenscmd/utility/EnumTypes.java new file mode 100644 index 0000000..9844443 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/utility/EnumTypes.java @@ -0,0 +1,33 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.utility; + +public class EnumTypes { + + public enum ClickType { + LEFT, + RIGHT + } + + public enum EditType { + PERM, + CMD + } + +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/utility/IHandler.java b/src/main/java/me/mattmoreira/citizenscmd/utility/IHandler.java new file mode 100644 index 0000000..66b3837 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/utility/IHandler.java @@ -0,0 +1,30 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.utility; + +/** + * Created by GlareMasters on 5/30/2018. + */ +public interface IHandler { + + void enable(); + + void disable(); + +} \ No newline at end of file diff --git a/src/main/java/me/mattmoreira/citizenscmd/utility/Path.java b/src/main/java/me/mattmoreira/citizenscmd/utility/Path.java new file mode 100644 index 0000000..063b65d --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/utility/Path.java @@ -0,0 +1,101 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.utility; + +public class Path { + + /** + * COMMANDS + */ + private static final String MAIN_PATH_COMMANDS = "messages.commands."; + + public static final String NPC_ADDED = MAIN_PATH_COMMANDS + "npc-add-command-added"; + public static final String NPC_ADD_FAIL = MAIN_PATH_COMMANDS + "npc-add-command-failed"; + public static final String NPC_COOLDOWN_SET = MAIN_PATH_COMMANDS + "npc-cooldown-set"; + public static final String NPC_COOLDOWN_SET_ERROR = MAIN_PATH_COMMANDS + "npc-cooldown-error"; + public static final String NPC_PRICE_SET = MAIN_PATH_COMMANDS + "npc-price-set"; + public static final String LIST_COUNT_RIGHT = MAIN_PATH_COMMANDS + "list-commnads-counter-right"; + public static final String LIST_COUNT_LEFT = MAIN_PATH_COMMANDS + "list-commnads-counter-left"; + public static final String LIST_TOOLTIP = MAIN_PATH_COMMANDS + "list-tooltip"; + public static final String LIST_COOLDOWN = MAIN_PATH_COMMANDS + "list-cooldown"; + public static final String LIST_PRICE = MAIN_PATH_COMMANDS + "list-price"; + public static final String RELOAD = MAIN_PATH_COMMANDS + "reload-command"; + public static final String REMOVED_COMMAND = MAIN_PATH_COMMANDS + "removed-command"; + public static final String EDITED_COMMAND = MAIN_PATH_COMMANDS + "edit-command"; + + /** + * WARNINGS + */ + private static final String MAIN_PATH_WARNINGS = "messages.warnings."; + + static final String NO_NPC = MAIN_PATH_WARNINGS + "no-npc-selected"; + public static final String INVALID_COOLDOWN = MAIN_PATH_WARNINGS + "invalid-cooldown"; + public static final String INVALID_PRICE = MAIN_PATH_WARNINGS + "invalid-price"; + public static final String INVALID_ID_NUMBER = MAIN_PATH_WARNINGS + "invalid-id"; + public static final String INVALID_CLICK_TYPE = MAIN_PATH_WARNINGS + "invalid-click-type"; + public static final String NO_COMMANDS = MAIN_PATH_WARNINGS + "no-commands"; + public static final String INVALID_ARGUMENTS = MAIN_PATH_WARNINGS + "invalid-arguments"; + public static final String INVALID_PERMISSION = MAIN_PATH_WARNINGS + "invalid-permission"; + public static final String CONSOLE_NOT_ALLOWED = MAIN_PATH_WARNINGS + "console-not-allowed"; + public static final String NO_PERMISSION = MAIN_PATH_WARNINGS + "no-permission"; + public static final String WRONG_USAGE = MAIN_PATH_WARNINGS + "wrong-usage"; + public static final String NEW_VERSION = MAIN_PATH_WARNINGS + "new-version"; + public static final String DOWNLOAD_AT = MAIN_PATH_WARNINGS + "download-at"; + + /** + * NPCS + */ + private static final String MAIN_PATH_NPCS = "messages.npc."; + + public static final String ON_COOLDOWN = MAIN_PATH_NPCS + "on-cooldown"; + public static final String ONE_TIME_CLICK = MAIN_PATH_NPCS + "one-time-click"; + public static final String PAY_CONFIRM = MAIN_PATH_NPCS + "pay-confirm"; + public static final String PAY_CANCELED = MAIN_PATH_NPCS + "pay-canceled"; + public static final String PAY_NO_MONEY = MAIN_PATH_NPCS + "pay-no-money"; + public static final String PAY_COMPLETED = MAIN_PATH_NPCS + "pay-completed"; + + /** + * Help + */ + private static final String MAIN_PATH_HELP = "messages.help."; + + public static final String HELP_VERSION = MAIN_PATH_HELP + "version"; + public static final String HELP_INFO = MAIN_PATH_HELP + "info"; + public static final String HELP_EXAMPLE = MAIN_PATH_HELP + "example"; + public static final String HELP_DESCRIPTION_ADD = MAIN_PATH_HELP + "description-add"; + public static final String HELP_DESCRIPTION_COOLDOWN = MAIN_PATH_HELP + "description-cooldown"; + public static final String HELP_DESCRIPTION_PRICE = MAIN_PATH_HELP + "description-price"; + public static final String HELP_DESCRIPTION_LIST = MAIN_PATH_HELP + "description-list"; + public static final String HELP_DESCRIPTION_EDIT = MAIN_PATH_HELP + "description-edit"; + public static final String HELP_DESCRIPTION_REMOVE = MAIN_PATH_HELP + "description-remove"; + public static final String HELP_DESCRIPTION_RELOAD = MAIN_PATH_HELP + "description-reload"; + + /** + * Time format + */ + private static final String MAIN_PATH_TIME_FORMAT = "messages.time-format."; + + static final String SECONDS = MAIN_PATH_TIME_FORMAT + "seconds"; + static final String MINUTES = MAIN_PATH_TIME_FORMAT + "minutes"; + static final String HOURS = MAIN_PATH_TIME_FORMAT + "hours"; + static final String DAYS = MAIN_PATH_TIME_FORMAT + "days"; + + +} + diff --git a/src/main/java/me/mattmoreira/citizenscmd/utility/TimeUtil.java b/src/main/java/me/mattmoreira/citizenscmd/utility/TimeUtil.java new file mode 100644 index 0000000..1c0db59 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/utility/TimeUtil.java @@ -0,0 +1,177 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * A special thanks to @ExtendedClip for letting me use and modify this class from PlaceholderAPI + */ + +package me.mattmoreira.citizenscmd.utility; + +import me.mattmoreira.citizenscmd.CitizensCMD; + +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TimeUtil { + + private static String dayFormat; + private static String hourFormat; + private static String minuteFormat; + private static String secondFormat; + + /** + * Gets formatted time from seconds + * + * @param seconds The time in seconds to be converted + * @return String with the time like "2d 2h 2m 2s" + */ + public static String getFormattedTime(int seconds, DisplayFormat format) { + + String messagesString[] = new String[4]; + messagesString[0] = CitizensCMD.getPlugin().getLang().getMessage(Path.SECONDS); + messagesString[1] = CitizensCMD.getPlugin().getLang().getMessage(Path.MINUTES); + messagesString[2] = CitizensCMD.getPlugin().getLang().getMessage(Path.HOURS); + messagesString[3] = CitizensCMD.getPlugin().getLang().getMessage(Path.DAYS); + + String shorts[] = new String[4]; + String mediums[] = new String[4]; + String fulls[] = new String[4]; + + Pattern pattern = Pattern.compile("\\[([^]]*)], \\[([^]]*)], \\[([^]]*)]"); + for (int i = 0; i < messagesString.length; i++) { + Matcher matcher = pattern.matcher(messagesString[i]); + if (matcher.find()) { + shorts[i] = matcher.group(1); + mediums[i] = matcher.group(2); + fulls[i] = matcher.group(3); + } + } + + switch (format) { + case SHORT: + dayFormat = shorts[3]; + hourFormat = shorts[2]; + minuteFormat = shorts[1]; + secondFormat = shorts[0]; + break; + case MEDIUM: + dayFormat = " " + mediums[3]; + hourFormat = " " + mediums[2]; + minuteFormat = " " + mediums[1]; + secondFormat = " " + mediums[0]; + break; + case FULL: + dayFormat = " " + fulls[3]; + hourFormat = " " + fulls[2]; + minuteFormat = " " + fulls[1]; + secondFormat = " " + fulls[0]; + break; + } + + if (seconds < 60) { + if (seconds == 1 && !format.equals(DisplayFormat.SHORT)) + return seconds + secondFormat.substring(0, secondFormat.length() - 1); + return seconds + secondFormat; + } + + int minutes = (int) TimeUnit.SECONDS.toMinutes(seconds); + int secondsLeft = seconds - (int) TimeUnit.MINUTES.toSeconds(minutes); + + if (minutes < 60) { + if (minutes == 1 && !format.equals(DisplayFormat.SHORT)) { + if (secondsLeft > 0) { + if (secondsLeft == 1 && !format.equals(DisplayFormat.SHORT)) + return String.valueOf(minutes + minuteFormat.substring(0, secondFormat.length() - 1) + " " + secondsLeft + secondFormat.substring(0, secondFormat.length() - 1)); + return String.valueOf(minutes + minuteFormat.substring(0, secondFormat.length() - 1) + " " + secondsLeft + secondFormat); + } else + return String.valueOf(minutes + minuteFormat.substring(0, secondFormat.length() - 1)); + } else { + if (secondsLeft > 0) { + if (secondsLeft == 1 && !format.equals(DisplayFormat.SHORT)) + return String.valueOf(minutes + minuteFormat + " " + secondsLeft + secondFormat.substring(0, secondFormat.length() - 1)); + return String.valueOf(minutes + minuteFormat + " " + secondsLeft + secondFormat); + } else + return String.valueOf(minutes + minuteFormat); + } + } + + if (minutes < 1440) { + int hours = (int) TimeUnit.MINUTES.toHours(minutes); + String time; + if (hours == 1 && !format.equals(DisplayFormat.SHORT)) + time = hours + hourFormat.substring(0, hourFormat.length() - 1); + else + time = hours + hourFormat; + int leftOver = minutes - (int) TimeUnit.HOURS.toMinutes(hours); + + if (leftOver >= 1) { + if (leftOver == 1 && !format.equals(DisplayFormat.SHORT)) + time += " " + leftOver + minuteFormat.substring(0, minuteFormat.length() - 1); + else + time += " " + leftOver + minuteFormat; + } + + if (secondsLeft > 0) + if (secondsLeft == 1 && !format.equals(DisplayFormat.SHORT)) + time += " " + secondsLeft + secondFormat.substring(0, secondFormat.length() - 1); + else + time += " " + secondsLeft + secondFormat; + + return time; + } + + int days = (int) TimeUnit.MINUTES.toDays(minutes); + String time; + if (days == 1 && !format.equals(DisplayFormat.SHORT)) + time = days + dayFormat.substring(0, dayFormat.length() - 1); + else + time = days + dayFormat; + int leftOver = minutes - (int) TimeUnit.DAYS.toMinutes(days); + + if (leftOver >= 1) { + if (leftOver < 60) { + if (leftOver == 1 && !format.equals(DisplayFormat.SHORT)) + time += " " + leftOver + minuteFormat.substring(0, minuteFormat.length() - 1); + else + time += " " + leftOver + minuteFormat; + } else { + int hours = (int) TimeUnit.MINUTES.toHours(leftOver); + if (hours == 1 && !format.equals(DisplayFormat.SHORT)) + time += " " + hours + hourFormat.substring(0, hourFormat.length() - 1); + else + time += " " + hours + hourFormat; + int minsLeft = leftOver - (int) TimeUnit.HOURS.toMinutes(hours); + if (minsLeft == 1 && !format.equals(DisplayFormat.SHORT)) + time += " " + minsLeft + minuteFormat.substring(0, minuteFormat.length() - 1); + else + time += " " + minsLeft + minuteFormat; + } + } + + if (secondsLeft > 0) { + if (secondsLeft == 1 && !format.equals(DisplayFormat.SHORT)) + time += " " + secondsLeft + secondFormat.substring(0, secondFormat.length() - 1); + else + time += " " + secondsLeft + secondFormat; + } + + return time; + + } +} diff --git a/src/main/java/me/mattmoreira/citizenscmd/utility/Util.java b/src/main/java/me/mattmoreira/citizenscmd/utility/Util.java new file mode 100644 index 0000000..fa50fb4 --- /dev/null +++ b/src/main/java/me/mattmoreira/citizenscmd/utility/Util.java @@ -0,0 +1,171 @@ +/** + * CitizensCMD - Add-on for Citizens + * Copyright (C) 2018 Mateus Moreira + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.mattmoreira.citizenscmd.utility; + +import me.mattmoreira.citizenscmd.CitizensCMD; +import net.citizensnpcs.api.CitizensAPI; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import java.util.concurrent.TimeUnit; + +public class Util { + + /** + * String with CitizensCMD default header and tag + */ + public static final String HEADER = "&c&m-&6&m-&e&m-&a&m-&b&m-&3&l CitizensCMD &b&m-&a&m-&e&m-&6&m-&c&m-"; + public static final String TAG = "&f[&3Citizens&cCMD&f]&r "; + + /** + * @param str String to check if it is a number or not + * @return Returns true if it is a number false if it is a string or contains any non numeric character + */ + public static boolean notInteger(String str) { + try { + Integer.parseInt(str); + } catch (NumberFormatException | NullPointerException e) { + return true; + } + return false; + } + + /** + * @param str String to check if it is a double number or not + * @return Returns true if it is a number false if it is a string or contains any non numeric character + */ + public static boolean notDouble(String str) { + try { + Double.parseDouble(str); + } catch (NumberFormatException | NullPointerException e) { + return true; + } + return false; + } + + /** + * Checks if player has or not selected an NPC + * + * @param player The player to check if it has any NPC selected or not + * @return Returns true if has an NPC selected and false if not + */ + public static boolean npcNotSelected(Player player) { + if (CitizensAPI.getDefaultNPCSelector().getSelected(player) != null) return false; + + player.sendMessage(color(HEADER)); + player.sendMessage(CitizensCMD.getPlugin().getLang().getMessage(Path.NO_NPC)); + return true; + } + + /** + * Checks if player has or not selected an NPC + * + * @param player The player to check if it has any NPC selected or not + * @return Returns true if has an NPC selected and false if not + */ + public static boolean npcNotSelectedNM(Player player) { + return CitizensAPI.getDefaultNPCSelector().getSelected(player) == null; + } + + /** + * Gets the NPC id + * + * @param player To get the id of the NPC the player has selected + * @return Returns the id of the NPC + */ + public static int getSelectedNpcId(Player player) { + return CitizensAPI.getDefaultNPCSelector().getSelected(player).getId(); + } + + /** + * Checks whether or not it should check for updates + * + * @return Returns true if CheckUpdates is true on the config and false if not + */ + public static boolean upCheck() { + return CitizensCMD.getPlugin().getConfig().getBoolean("check-updates"); + } + + /** + * Utility to use color codes easierly + * + * @param msg The message String + * @return returns the string with color + */ + public static String color(String msg) { + return ChatColor.translateAlternateColorCodes('&', msg); + } + + /** + * Simplified way for sending console messages + * + * @param msg the message to be sent to the console + */ + public static void info(String msg) { + Bukkit.getServer().getConsoleSender().sendMessage(msg); + } + + /** + * Gets default cooldown set on the config + * + * @return returns the seconds from the config + */ + public static int getDefaultCooldown() { + return CitizensCMD.getPlugin().getConfig().getInt("default-cooldown"); + } + + /** + * Gets arguments from each command for the tab completion + * + * @return Returns 2d string array with arguments for tab completion + */ + public static String[][] getTabCompleteArgs(String subCMD, Player player) { + String[][] argComplete = new String[5][]; + + switch (subCMD.toLowerCase()) { + case "add": + argComplete[0] = new String[]{"console", "none", "permission", "server"}; + break; + case "remove": + argComplete[0] = new String[]{"left", "right"}; + argComplete[1] = CitizensCMD.getPlugin().getDataHandler().getCompleteCommandsNumbers(getSelectedNpcId(player), EnumTypes.ClickType.LEFT); + argComplete[2] = CitizensCMD.getPlugin().getDataHandler().getCompleteCommandsNumbers(getSelectedNpcId(player), EnumTypes.ClickType.RIGHT); + break; + case "edit": + argComplete[0] = new String[]{"perm", "cmd"}; + argComplete[1] = new String[]{"left", "right"}; + argComplete[2] = CitizensCMD.getPlugin().getDataHandler().getCompleteCommandsNumbers(getSelectedNpcId(player), EnumTypes.ClickType.LEFT); + argComplete[3] = CitizensCMD.getPlugin().getDataHandler().getCompleteCommandsNumbers(getSelectedNpcId(player), EnumTypes.ClickType.RIGHT); + argComplete[4] = new String[]{"console", "none", "permission", "server"}; + } + return argComplete; + } + + /** + * Gets the difference in seconds between times + * + * @param storedTime the stored time to compare + * @return returns the difference in seconds + */ + public static int getSecondsDifference(long storedTime) { + return (int) TimeUnit.SECONDS.convert((System.nanoTime() - storedTime), TimeUnit.NANOSECONDS); + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..79f9014 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,18 @@ +# Citizens CMD Plugin by Mateus Moreira +# @LichtHund +# Version ${project.version} +# +# Enables Checking for update. +check-updates: true +# +# Available languages EN, PT +lang: en +# +# The default npc cooldown in seconds +default-cooldown: 0 +# +# When using a NPC with price, true means that to confirm the use the player needs to seek or press shift +shift-confirm: true +# +# Select cooldown display format, SHORT = 3m 3s | MEDIUM = 3 min 3 sec | FULL - 3 minutes 3 seconds +cooldonw-time-display: MEDIUM \ No newline at end of file diff --git a/src/main/resources/lang/bg.yml b/src/main/resources/lang/bg.yml new file mode 100644 index 0000000..418d38b --- /dev/null +++ b/src/main/resources/lang/bg.yml @@ -0,0 +1,62 @@ +# Citizens CMD Plugin by Mateus Moreira +# @LichtHund +# Весия ${project.version} +# +# Променете толкова, колкото смятате за нужно. +# Внивавайте при премахването на Placeholder-и! +# Някой Placeholder-и могат да не работят при премахване +# Cooldown placeholder-а може да бъде премахнат, без последствия +messages: + commands: + npc-add-command-added: "&aУспешно добавихте команда към NPC-то!" + npc-add-command-failed: "&cДобавянето на команда не бе успешно!" + npc-cooldown-set: "&aВремето за изчакване бе променено успешно!" + npc-cooldown-error: "&cПояви се грешка при променянето за времето за изчакване!" + npc-price-set: "&aЦената бе променена успешно!" + list-commnads-counter-right: "&c&o{count} &7&o- Команди с Десен Клик:" + list-commnads-counter-left: "&c&o{count} &7&o- Команди с Ляв Клик:" + list-cooldown: "&7Време за изчакване: &c" + list-price: "&7Цена: &c" + list-tooltip: "&7Кликни за да промениш!" + reload-command: "&aВсичко файлове бяха презаредени успешно!" + removed-command: "&aКомандата бе премахната успешно!" + edit-command: "&a{type} бе променен/а успешно!" + warnings: + no-npc-selected: "&cИзбери NPC първо!" + invalid-cooldown: "&cВремето за изчакване трябва да бъде число!" + invalid-price: "&cЦената трябва да бъде число!" + invalid-id: "&cМоля, задайте валидо ID на команда!" + invalid-click-type: "&cТрябва да избереш ляв или десен!" + no-commands: "&cНяма команди в това NPC!" + invalid-arguments: "&cТрябва да избереш CMD или PERM!" + invalid-permission: "&cНе трябва да има място между правата." + console-not-allowed: "&cТази команда може да бъде използвана само в игра!" + no-permission: "&cНямате право да използвате тази команда!" + wrong-usage: "&cГрешен начин на употреба! &7/npcmd &cза информация!" + new-version: "&7Нова версия: &cv" + download-at: "&7Свали от" + npc: + on-cooldown: "&7Моля изчакайте &c{time} &7преди да използвате това NPC отново!" + one-time-click: "&7Това NPC е за еднократна употреба!" + pay-confirm: "&7За да използвате това NPC трябва да платите &a{price}$&7!\n&a{shift}Десен бутон за потвърждение &7или &c{shift}Ляв бутон за отмяна\n&8Това действие ще бъде прекъснато след &c15 &8секундки!" + pay-canceled: "&cПлащането бе отменено!" + pay-no-money: "&cНямаш достатъчно пари, за да извършиш това действие!" + pay-completed: "&a{price}$ Бяха взети от твоята сметка!" + help: + version: "&7&oВерсия:" + info: "&7Задръжте върху команда за помощ и пример!" + example: "&8Пример:" + description-add: "&7За да добавите команда на NPC." + description-cooldown: "&7Задава времето за изчакване на ляв/десен клик." + description-price: "&7Задава цена за използване на NPC." + description-list: "&7Показва спъсък с командите на NPC." + description-edit: "&7Променя команда или права." + description-remove: "&7Премахва команда от NPC." + description-reload: "&7Презарежда всички файлове." +# ВАЖНО!! +# НЕ ПРОМЕНЯЙТЕ МОДЕЛА, ОСТАВЕТЕ СКОБИТЕ "[]," ПРОМЕНЕТЕ САМО ТЕКСТА В ТЯХ + time-format: + seconds: "[С], [Сек], [Секунди]" + minutes: "[М], [Мин], [Минути]" + hours: "[Ч], [Часа], [Часа]" + days: "[Д], [Дни], [Дена]" \ No newline at end of file diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml new file mode 100644 index 0000000..e56dd48 --- /dev/null +++ b/src/main/resources/lang/en.yml @@ -0,0 +1,63 @@ +# Citizens CMD Plugin by Mateus Moreira +# @LichtHund +# Version ${project.version} +# +# Change as much as you need. +# Remove placeholders with caution! +# Some placeholders can be removed but might not work correctly +# Cooldown placeholder is safe to be deleted +messages: + commands: + npc-add-command-added: "&aYou have successfully added a command to the NPC!" + npc-add-command-failed: "&cFailed to add command to the NPC!" + npc-cooldown-set: "&aYou have successfully set the cooldown!" + npc-cooldown-error: "&cAn error occurred while setting the cooldown!" + npc-price-set: "&aYou have successfully set the price!" + list-commnads-counter-right: "&c&o{count} &7&o- Right click commands:" + list-commnads-counter-left: "&c&o{count} &7&o- Left click commands:" + list-cooldown: "&7Cooldown: &c" + list-price: "&7Price: &c" + list-tooltip: "&7Click to edit!" + reload-command: "&aAll files have been reloaded successfully!" + removed-command: "&aThe command was removed successfully!" + edit-command: "&aThe {type} was edited successfully!" + warnings: + no-npc-selected: "&cYou must have an NPC selected to execute that command!" + invalid-cooldown: "&cThe cooldown must be a number!" + invalid-price: "&cThe price must be a number!" + invalid-id: "&cPlease introduce a valid command ID!" + invalid-click-type: "&cYou must select either left or right!" + no-commands: "&cThere is no more commands in this NPC!" + invalid-arguments: "&cYou must select either CMD or PERM!" + invalid-permission: "&cPermissions can't contain spaces!" + console-not-allowed: "&cThis command cannot be executed from the console, only ingame!" + no-permission: "&cYou don't have permissions to perform this command!" + wrong-usage: "&cWrong usage of the command! &7/npcmd &cfor help!" + new-version: "&7New version available: &cv" + download-at: "&7Download at" + npc: + on-cooldown: "&7Please wait &c{time} &7before using this NPC again!" + one-time-click: "&7This NPC only allows one use!" + pay-confirm: "&7To use this NPC you must pay &a{price}$&7!\n&a{shift}Right click to confirm &7or &c{shift}Left click to cancel\n&8This operation will be canceled in &c15 &8seconds!" + pay-canceled: "&cPayment canceled!" + pay-no-money: "&cYou don't have enough money to do this!" + pay-completed: "&a{price}$ has been taken from your account!" + help: + version: "&7&oVersion:" + info: "&7Hover a command for more info and example!" + example: "&8Example:" + description-add: "&7Adds commands to an NPC." + description-cooldown: "&7Sets the NPC click cooldown, in seconds." + description-price: "&7Sets the price to use the NPC." + description-list: "&7Displays list of commands for the current NPC." + description-edit: "&7Edits a specific command or permission." + description-remove: "&7Removes a command from the NPC." + description-reload: "&7Reloads all the files." +# IMPORTANT!! +# DO NOT CHANGE THIS PATTERN, KEEP THE "[]," CHANGE ONLY THE TEXT INSIDE + time-format: + seconds: "[s], [secs], [seconds]" + minutes: "[m], [mins], [minutes]" + hours: "[h], [hours], [hours]" + days: "[d], [days], [days]" + diff --git a/src/main/resources/lang/pt.yml b/src/main/resources/lang/pt.yml new file mode 100644 index 0000000..1c86c50 --- /dev/null +++ b/src/main/resources/lang/pt.yml @@ -0,0 +1,5 @@ +messages: + commands: + command1: "" + warnings: + no-npc-selected: "&ctenho que traduzir depois mas aborrece!" \ No newline at end of file diff --git a/src/main/resources/lang/ro.yml b/src/main/resources/lang/ro.yml new file mode 100644 index 0000000..856df78 --- /dev/null +++ b/src/main/resources/lang/ro.yml @@ -0,0 +1,62 @@ +# Plugin-ul Citizens CMD creat de catre Mateus Moreira +# @LichtHund +# Versiune ${project.version} +# +# Schimbati cat aveti nevoie. +# Indepartati placeholder-ele cu precautie! +# Unele placeholdere pot fi indepartate, dar este posibil ca acestea sa nu functioneze corect +# Placeholder-ul pentru cooldown poate fi indepartat +messages: + commands: + npc-add-command-added: "&aAti adaugat cu succes o comanda acestui NPC!" + npc-add-command-failed: "&cAdaugarea comenzi acestui NPC a esuat!" + npc-cooldown-set: "&aAti setat cu succes cooldown-ul!" + npc-cooldown-error: "&cA aparut o eroare la setarea cooldown-ului!" + npc-price-set: "&aAti setat pretul cu succes!" + list-commnads-counter-right: "&c&o{count} &7&o- Comenzile cu click dreapta:" + list-commnads-counter-left: "&c&o{count} &7&o- Comenzile cu click stanga:" + list-cooldown: "&7Cooldown: &c" + list-price: "&7Pret: &c" + list-tooltip: "&7Click pentru a edita!" + reload-command: "&aToate fisierele au fost reincarcate cu succes!" + removed-command: "&aComanda a fost eliminata cu succes!" + edit-command: "&a{type} a fost editat cu succes!" + warnings: + no-npc-selected: "&cTrebuie sa ai un NPC selectat pentru a executa aceasta comanda!" + invalid-cooldown: "&cCooldown-ul trebuie sa fie un numar!" + invalid-price: "&cPretul trebuie sa fie un numar!" + invalid-id: "&cVa rugam introduceti un ID valid!" + invalid-click-type: "&cTrebuie sa selectatie fie stanga, fie dreapta!" + no-commands: "&cNu exista comenzi pentru NPC!" + invalid-arguments: "&cTrebuie sa selectati fie CMD, fie PERM!" + invalid-permission: "&cPermisiunile nu pot contine spatiu!" + console-not-allowed: "&cAceasta comanda nu poate fi executata din consola, doar din joc!" + no-permission: "&cNu aveti permisiunea de a executa aceasta comanda!" + wrong-usage: "&cUtilizare gresita a comenzi! &7/npcmd &cpentru ajutor!" + new-version: "&7Versiune noua valabila: &cv" + download-at: "&7Descarcati-o la" + npc: + on-cooldown: "&7Va rugam asteptati &c{time} &7inainte de a folosi acest NPC din nou!" + one-time-click: "&7This NPC only allows one use!" + pay-confirm: "&7Pentru a folosi acest NPC trebuie sa platiti &a{price}$&7!\n&a{shift}Click dreapta pentru a confirma &7sau &c{shift}Click stanga pentru a anula\n&8Aceasta operatiune va fi anulata in &c15 &8secunde!" + pay-canceled: "&cPlata anulata!" + pay-no-money: "&cNu aveti destui bani pentru a face asta!" + pay-completed: "&a{price}$ au fost adaugati in contul dvs!" + help: + version: "&7&oVersiune:" + info: "&7Plasati mouse-ul peste o comanda pentru mai multe informatii si exemple!" + example: "&8Exemplu:" + description-add: "&7Adaugati comenzi la un NPC." + description-cooldown: "&7Setati cooldown-ul pentru folosirea NPC-ului, in secunde." + description-price: "&7Setati pretul pentru folosirea NPC-ului." + description-list: "&7Afisati lista de comenzi a NPC-ului curent." + description-edit: "&7Editati o anumita comands sau permisiune." + description-remove: "&7Stergeti o comanda a NPC-ului." + description-reload: "&7Reincarcati toate fisierele." +# IMPORTANT!! +# NU MODIFICATI ACEST MODEL, PASTRATI "[]," SI MODIFICATI DOAR TEXTUL DIN INTERIOR + time-format: + seconds: "[s], [sec], [secunde]" + minutes: "[m], [min], [minute]" + hours: "[h], [ore], [ore]" + days: "[z], [zile], [zile]" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..7a6796b --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,52 @@ +# Citizens CMD Plugin by Mateus Moreira aka iPSYKO +# @LichtHund + +main: me.mattmoreira.citizenscmd.CitizensCMD +version: ${project.version} +name: CitizensCMD +author: Mateus Moreira +softdepend: [Citizens, PlaceholderAPI, Vault] +api-version: 1.13 + +commands: + npcmd: + description: Performs all npcmd commands. + npcmd help: + description: Displays help + npcmd add: + description: Adds a new command to the NPC + npcmd cooldown: + description: Sets the cooldown for the NPC + npcmd price: + description: Sets the price for the NPC + npcmd list: + description: Gets the list of commands + npcmd reload: + description: Reloads config, saves and cooldown + npcmd remove: + description: Removes command + npcmd edit: + description: Edits a command or permission + +permissions: + citizenscmd.use: + description: Allows player to click NPC. + default: true + citizenscmd.help: + default: op + citizenscmd.add: + default: op + citizenscmd.list: + default: op + citizenscmd.cooldown: + default: op + citizenscmd.price: + default: op + citizenscmd.reload: + default: op + citizenscmd.remove: + default: op + citizenscmd.edit: + default: op + citizenscmd.bypass: + default: false \ No newline at end of file