diff --git a/.gitignore b/.gitignore
index 96ef862..90b6399 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,6 @@
target/
.idea/
+*.secret
+*.db
+nbactions.xml
+stargate.iml
diff --git a/Jenkinsfile b/Jenkinsfile
deleted file mode 100644
index 2e16cba..0000000
--- a/Jenkinsfile
+++ /dev/null
@@ -1,33 +0,0 @@
-pipeline {
- agent any
- tools {
- jdk 'JDK17'
- }
- stages {
- stage('Build') {
- steps {
- echo 'Building...'
- sh 'mvn clean & mvn validate & mvn compile'
- }
- }
- stage('Test') {
- steps {
- echo 'Testing...'
- sh 'mvn test'
- }
- }
- stage('Verify') {
- steps {
- echo 'Verifying...'
- sh 'mvn verify -Dmaven.test.skip=true'
- }
- }
- stage('Deploy') {
- steps {
- echo 'Deploying...'
- sh 'mvn deploy -Dmaven.install.skip=true -Dmaven.test.skip=true'
- archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true
- }
- }
- }
-}
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 3d90694..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,674 +0,0 @@
- 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
-.
\ No newline at end of file
diff --git a/README.md b/README.md
index 5d4f412..d6777e9 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,23 @@
+> **Documentation may be found** [here](https://sgrewritten.org/legacywiki)
+> **Support is available via** [discord](https://sgrewritten.org/discord)**.**
+
+> **THIS IS A LEGACY-BASED BRANCH: IT IS SUPPORTED, BUT NOT ACTIVELY UPDATED**
+> This branch expands upon Drakia's original 2013 codebase, with fixes as needed.
+> In the near future, this branch will be superseded by [SGR](https://github.com/stargate-rewritten/Stargate-Bukkit) (a
+> complete rewrite).
+
# Description
-Create gates that allow for instant-teleportation between large distances. Gates can be always-open or triggered; they
-can share a network or be split into clusters; they can be hidden on a network or accessible to everybody.
+The Original, and still the best, MineCraft transportation solution!
Intuitively and organically facilitates instant
+transportation across large distances!
+Highly capable, simple to use, with robust network capabilities and extensive customisability!
- **Player permissions** -- let players build their own networks.
- **Vault economy support** -- can add costs for create, destroy and use.
-- **Ability to create custom gate configurations**. Four different default gate configurations are available.
+- **Ability to create custom gate configurations**. -- Four different default gate configurations are available.
+- **Ability to include #Tags in gate designs**. (Ability to include material lists as valid options within a format)
- **Message customization**
-- **Multiple built-in languages** (de, en, es, fr, hu, it, ja, nb-no, nl, nn-no, pt-br, ru, zh_cn)
+- **Multiple built-in languages** (cs, de, en, es, fr, hu, it, ja, nb, nl, nn, pt, ru, uk, zh)
- **Teleport across worlds or servers** (BungeeCord supported)
- **Vehicle teleportation** -- teleport minecarts, boats, horses, pigs and striders
- **Leashed teleportation** -- teleport any creature in a leash with the player
@@ -18,28 +28,42 @@ can share a network or be split into clusters; they can be hidden on a network o
- **Color customization** -- Stargate signs can be colored in many ways. Colors can be set globally, or on a per sign
type basis
- **RGB and dye support** -- Signs can use RGB colors (using hex codes) as their main and highlighting colors, and can
- also be dyed on a per-sign basis
+ also be dyed on a per-sign basis.
## Background
-This was originally TheDgtl's Bukkit port of the Stargate plugin for hMod by Dinnerbone. This is a fork
-of [PseudoKnight's fork](https://github.com/PseudoKnight/Stargate-Bukkit). This fork's main purpose is to create a clean
-version of Stargate compliant with Spigot 1.17, even if it means changing the entire project's previous structure.
+- This plugin was originally TheDgtl's Bukkit port of the Stargate plugin for hMod by Dinnerbone.
+- After this plugin was dropped by TheDgtl, PseudoKnight began maintaining it for modern versions of Spigot (adding
+ support for UUIDs & Material Strings).
+- EpicKnarvik97 forked that version to clean up the code, added leash support, and improved vehicle support.
+- LockedCraft and LittleBigBug also forked that version to add underwater and tag support, as well as a few bug fixes.
+- This version is a combination of all the forks above, maintained by the Stargate Rewritten project.
+- This branch is currently in a maintenance-only mode; a total rewrite is forthcoming.
## License
-Stargate is licensed under the GNU Lesser General Public License Version 3.0. This includes every source and resource
-file. See the HEADER file for a more detailed license description.
+Stargate is licensed under the GNU Lesser General Public License Version 3.0.
This includes every source and
+resource
+file; see the LICENSE file for more information.
## Migration
-This plugin should be compatible with configurations from the Stargate plugin all the way back. The nethergate.gate
-file, the endgate.gate file and the watergate.gate file will be overwritten if they exist. Take a backup of the files
-and overwrite the files after the first startup if you want to keep your custom gates.
+This plugin should be fully compatible all known versions StarGate forks, with the following exceptions:
-If you have legacy gate files using the old numeric material ids, you need to change them to the new format manually.
-Use F3 + H to see material ids. Use them exactly as written after "minecraft:". The configuration will be updated to a
-more easily readable format, but the old configuration will be saved in case you want to change back right away.
+- Any version from outside the bukkit ecosystem
+- Any version of SGR (version numbers 1.0.0.0+)
+- Any configurations with outdated material names (i.e. numIDs)
+
+**Note that this plugin's default gate files** __**AND ANY PRESENT CUSTOM .GATEs**__ **will be overwritten by the
+import!**
+If you wish to keep any such files, take a backup of your "gates" folder!
+
+Legacy gate files filled with outdated material IDs will need to be manually updated.
+A list of old materials and their conversions may be
+found [here](https://github.com/CryptoMorin/XSeries/blob/master/src/main/java/com/cryptomorin/xseries/XMaterial.java)
+.
+A list of modern, valid, material names may be
+found [here](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html).
Permissions have had a few changes, so you should check the permissions section for any differences since you set up
permissions.
@@ -50,77 +74,85 @@ server.
# Permissions
-```
-stargate.use -- Allow use of all Stargates linking to any world in any network (Override ALL network/world permissions. Set to false to use network/world specific permissions)
- stargate.world -- Allow use of Stargates linking to any world
- stargate.world.{world} -- Allow use of Stargates with a destination in {world}. Set to false to disallow use.
- stargate.network -- Allow use of Stargates on all networks
- stargate.network.{network} -- Allow use of all Stargates in {network}. Set to false to disallow use.
- stargate.server -- Allow use of Stargates going to all servers
- stargate.server.{server} -- Allow usee of all Stargates going to {server}. Set to false to disallow use.
-
-stargate.option -- Allow use of all options
- stargate.option.hidden -- Allow use of 'H'idden
- stargate.option.alwayson -- Allow use of 'A'lways-On
- stargate.option.private -- Allow use of 'P'rivate
- stargate.option.free -- Allow use of 'F'ree
- stargate.option.backwards -- Allow use of 'B'ackwards
- stargate.option.show -- Allow use of 'S'how
- stargate.option.nonetwork -- Allow use of 'N'oNetwork
- stargate.option.random -- Allow use of 'R'andom stargates
- stargate.option.silent -- Allow use of S'i'lent stargates
- stargate.option.nosign -- Allow use of 'E' (No sign)
-
-stargate.create -- Allow creating Stargates on any network (Override all create permissions)
- stargate.create.personal -- Allow creating Stargates on network {playername}
- stargate.create.network -- Allow creating Stargates on any network
- stargate.create.network.{networkname} -- Allow creating Stargates on network {networkname}. Set to false to disallow creation on {networkname}
- stargate.create.gate -- Allow creation using any gate layout
- stargate.create.gate.{gatefile} -- Allow creation using only {gatefile} gates
+## Easy setup permission groups
-stargate.destroy -- Allow destruction of Stargates on any network (Orderride all destroy permissions)
- stargate.destroy.personal -- Allow destruction of Stargates owned by the player only
- stargate.destroy.network -- Allow destruction of Stargates on any network
- stargate.destroy.network.{networkname} -- Allow destruction of Stargates on network {networkname}. Set to false to disallow destruction of {networkname}
+Note: These permission groups inherit from each other (builder has player's permissions and admin has builder's
+permissions), so you only need the most permissive one.
-stargate.free -- Allow free use/creation/destruction of Stargates
- stargate.free.use -- Allow free use of Stargates
- stargate.free.create -- Allow free creation of Stargates
- stargate.free.destroy -- Allow free destruction of Stargates
-
-stargate.admin -- Allow all admin features (Hidden/Private bypass, BungeeCord, Reload, Config)
- stargate.admin.private -- Allow use of Private gates not owned by user
- stargate.admin.hidden -- Allow access to Hidden gates not ownerd by user
- stargate.admin.bungee -- Allow the creation of BungeeCord stargates (U option)
- stargate.admin.reload -- Allow use of the reload command
- stargate.admin.config -- Allows the player to change config values from the chat
- stargate.admin.dye -- Allows this player to change the dye of any stargate's sign
-```
+| Node | Default | Description |
+|------------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| stargate.group.player | True | Allows using all non-private/non-personal Stargates and creating personal Stargates using the default nethergate format. |
+| stargate.group.builder | False | Allows creating and destroying all types of Stargates anywhere with any option (except BungeeCord). |
+| stargate.group.admin | Op | Allows admin stuff like creating BungeeCord gates, reloading, changing the configuration, dying any Stargate's sign and accessing private and hidden Stargates. |
+| stargate.* | False | Gives all Stargate-related permissions |
-## Default Permissions
+## Individual nodes
-```
-stargate.use -- Everyone
-stargate.create -- Op
-stargate.destroy -- Op
-stargate.option -- Op
-stargate.free -- Op
-stargate.admin -- Op
-```
+
+ The full list of permission nodes may be found below: (Click to expand)
+
+Note: `-` is used to show inheritance, such as `stargate.use` being a parent of `stargate.world`, `stargate.network`,
+and `stargate.server`, thus giving all permissions of the indented items following the unindented node.
+
+| Node | Description |
+|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| stargate.use | Allow use of all Stargates linking to any world in any network (Override ALL network/world permissions. Set to false to use network/world specific permissions) |
+| - stargate.world | Allow use of Stargates linking to any world |
+| -- stargate.world.{world} | Allow use of Stargates with a destination in {world}. Set to false to disallow use. |
+| - stargate.network | Allow use of Stargates on all networks |
+| -- stargate.network.{network} | Allow use of all Stargates in {network}. Set to false to disallow use. |
+| - stargate.server | Allow use of Stargates going to all servers |
+| -- stargate.server.{server} | Allow usee of all Stargates going to {server}. Set to false to disallow use. |
+| | |
+| stargate.option | Allow use of all options |
+| - stargate.option.hidden | Allow use of 'H'idden |
+| - stargate.option.alwayson | Allow use of 'A'lways-On |
+| - stargate.option.private | Allow use of 'P'rivate |
+| - stargate.option.free | Allow use of 'F'ree |
+| - stargate.option.backwards | Allow use of 'B'ackwards |
+| - stargate.option.show | Allow use of 'S'how |
+| - stargate.option.nonetwork | Allow use of 'N'oNetwork |
+| - stargate.option.random | Allow use of 'R'andom stargates |
+| - stargate.option.quiet | Allow use of 'Q'uiet stargates |
+| - stargate.option.nosign | Allow use of 'V' (No sign) |
+| | |
+| stargate.create | Allow creating Stargates on any network (Override all create permissions) |
+| - stargate.create.personal | Allow creating Stargates on network {playername} |
+| - stargate.create.network | Allow creating Stargates on any network |
+| -- stargate.create.network.{networkname} | Allow creating Stargates on network {networkname}. Set to false to disallow creation on {networkname} |
+| - stargate.create.gate | Allow creation using any gate layout |
+| -- stargate.create.gate.{gatefile} | Allow creation using only {gatefile} gates |
+| | |
+| stargate.destroy | Allow destruction of Stargates on any network (Overrides all destroy permissions) |
+| - stargate.destroy.personal | Allow destruction of Stargates owned by the player only |
+| - stargate.destroy.network | Allow destruction of Stargates on any network |
+| -- stargate.destroy.network.{networkname} | Allow destruction of Stargates on network {networkname}. Set to false to disallow destruction of {networkname} |
+| | |
+| stargate.free | Allow free use/creation/destruction of Stargates |
+| - stargate.free.use | Allow free use of Stargates |
+| - stargate.free.create | Allow free creation of Stargates |
+| - stargate.free.destroy | Allow free destruction of Stargates |
+| | |
+| stargate.admin | Allow all admin features (Hidden/Private bypass, BungeeCord, Reload, Config) |
+| - stargate.admin.private | Allow use of Private gates not owned by user |
+| - stargate.admin.hidden | Allow access to Hidden gates not owned by the user |
+| - stargate.admin.bungee | Allow the creation of BungeeCord stargates (U option) |
+| - stargate.admin.reload | Allow use of the reload command |
+| - stargate.admin.config | Allows the player to change config values from the chat |
+| - stargate.admin.dye | Allows this player to change the dye of any stargate's sign |
+
+
# Instructions
## Building a gate:
-There are currently three default gate configurations. They all use the same structure as a standard nether portal. One
-gate is using obsidian blocks, one is using end bricks and the last uses sea lanterns. Only the sea lantern one can be
-used underwater. You must put a sign on one of the blocks in the middle of the layout to activate the portal (see next
-section). See the Custom Gate Layout section to learn how to add custom gates.
+This a default gate configuration. See the Custom Gate Layout section for more options, and how to redesign this.
```
OO
- O O - These are Obsidian blocks, End bricks or Sea Lanterns. You need 10.
- O O - Place a sign on either of these two middle blocks.
+ O O - These are Obsidian blocks (End Bricks and Sea Lanterns also work). You need 10.
+ ■ ■ - Place a sign on either of these two blocks.
O O
OO
```
@@ -128,25 +160,23 @@ section). See the Custom Gate Layout section to learn how to add custom gates.
### Sign Layout:
- Line 1: Gate Name (Max 13 characters)
-- Line 2: Destination Name \[Optional] (Max 13 characters, used for fixed-gates only)
-- Line 3: Network name \[Optional] (Max 13 characters)
-- Line 4: Options \[Optional] :
- - 'A' for always-on fixed gate
- - 'H' for hidden networked gate
- - 'P' for a private gate
- - 'F' for a free gate
- - 'B' is for a backwards facing gate (You will exit the back)
- - 'S' is for showing an always-on gate in the network list
- - 'N' is for hiding the network name
- - 'R' is for random gates. These follow standard permissions of gates, but have a random exit location every time a
- player enters. (Implicitly always on)
- - 'U' is for a gate connecting to another through bungee (Implicitly always on)
- - 'I' is for a silent gate, which does not output anything to the chat while teleporting. Increases immersion
- - 'E' is for a gate without a sign. Only for fixed stargates
+- Line 2: Destination Name [Optional] (Max 13 characters, used for fixed-gates only)
+- Line 3: Network name [Optional] (Max 13 characters)
+- Line 4: Options [Optional] :
+ - `A` is for an **A**lways-on fixed gate
+ - `H` is for a **H**idden networked gate
+ - `P` is for a **P**rivate gate
+ - `F` is for a **F**ree gate
+ - `B` is for a **B**ackwards facing gate (which exit you at the back)
+ - `S` is for **S**howing an always-on gate in the network list
+ - `N` is for a **N**o network gate (the network name is hidden from the sign)
+ - `R` is for a **R**andom gate (implicitly always on; sends players to a random exit)
+ - `U` is for a b**U**ngee gate (connecting to another servers via bungeecord)
+ - `Q` is for a **Q**uiet gate (it will not output anything to chat when teleporting)
+ - `V` is for an in**V**isible gate (it will appear without a sign)
-The options are the single letter, not the word. So to make a private hidden gate, your 4th line would be 'PH'. The
-&\[0-9a-f] color codes are not counted in the character limit, thus allowing a 13-character name with an additional 2
-characters used for the color code.
+The options are the single letter, not the word. So to make a private hidden gate, your 4th line would be 'PH'.
+Note that colour characters (if enabled) are not counted towards the character limit.
#### Gate networks:
@@ -154,7 +184,7 @@ characters used for the color code.
- You can specify (and create) your own network on the third line of the sign when making a new gate.
- Gates on one network will not see gates on the second network, and vice versa.
- Gates on different worlds, but in the same network, will see each other.
-- If the gate is a bungee gate, the network name should be the name of the server as displayed when typing /servers
+- Notwithstanding the above, the network for BungeeCord gates will always be the name of its destination /server
#### Fixed gates:
@@ -162,26 +192,39 @@ characters used for the color code.
- Fixed gates can be linked to other fixed gates, or normal gates. A normal gate cannot open a portal to a fixed gate,
however.
- To create a fixed gate, specify a destination on the second line of the stargate sign.
-- Set the 4th line of the stargate sign to "A" to enable an always-open fixed gate.
-- A bungee gate is always automatically a fixed gate
+- Set the 4th line of the stargate sign to `A` to enable an always-open fixed gate.
+- Gates with the U or R flags are fixed gates by definition.
#### Hidden Gates:
- Hidden gates are like normal gates, but only show on the destination list of other gates under certain conditions.
-- A hidden gate is only visible to the creator of the gate, or somebody with the stargate.hidden permission.
-- Set the 4th line of the stargate sign to 'H' to make it a hidden gate.
+- A hidden gate is only visible to the creator of the gate or somebody with the stargate.hidden permission.
+- Set the 4th line of the stargate sign to `H` to make it a hidden gate.
+
+#### Force Shown Gates:
+
+- Gates with the `A`, `R`, or `U` gates do not show up on networks by default.
+- To force such gates to show up on network lists, add the `S` flag to the sign's 4th line.
+
+#### Random Gates:
+
+- Random gates are similar to Always-On gates, but do not have a fixed exit;
+ - They instead randomly select an exit from the list of gates on their network.
+- Marking a gate as 'R' will automatically make that gate always-on.
+- 'R' gates ignore any gate with the 'R', 'A', and/or 'S' flag(s) when choosing their exit.
## Using a gate:
-- Right-click the sign to choose a destination.
-- Right-click the button to open up a portal.
+- Right-click the sign to choose a destination (not needed for Fixed gates, undefined gates).
+- Right-click the activator to open up a portal.
- Step through.
-# Custom Gate Layout
+## Custom Gate Layouts
-You can create as many gate formats as you want, the gate layouts are stored in `plugins/Stargate/gates/`.
-The .gate file must be laid out a specific way, the first lines will be config information, and after a blank line you
-will lay out the gate format. Here is the default nethergate.gate file:
+You may create as many gate formats as you wish through the use of .gate files within your `gates` folder.
+
+The .gate file follows a specific format, with config lines at the top, and the gate layout/design below it.
+For example, take the default nether.gate file shown below:
```
portal-open=NETHER_PORTAL
@@ -193,53 +236,56 @@ destroycost=0
toowner=false
X=OBSIDIAN
-=OBSIDIAN
-
- XX
+ XX
X..X
-..-
X*.X
XX
```
-The keys `portal-open` and `portal-closed` are used to define the material in the gate when it is open or closed. The
-material for `portal-closed` can be most things, including solid blocks. Some materials may act weirdly though. The
-material for `portal-open` can be any block the player can partially enter, even things like `GLOW_LICHEN`.
-`NETHER_PORTAL`, `END_GATEWAY` and `END_PORTAL` all work.
+### Keys
-The `usecost`, `createcost` and `destroycost` keys can be used to set an economy price for gates of this type, different
-from the cost defined in the config. With economy enabled, all gates without these values set will use the values from
-the config. If you want to have different costs for different portals, you must create different gate types and set
-different costs for each one. The `toowner` key can be used to set whether funds withdrawn for using portals with this
-gate type should go to the portal's owner.
+#### Materials
-The key `button` is used to define the type of button that is generated for this gate. It can be a button (of any type),
-a type of wall coral (dead or alive), a type of shulker box or a chest.
+> Note that MATERIAL NAMES (such as `OBSIDIAN`) can be
+> found [here](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html).
+> As of version 0.10.7.0, TAGS (such as `#WOOL`) can be
+> found [here](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Tag.html).
-`X` and `-` are used to define block types for the layout (Any single-character can be used, such as `#`).
-In the gate format, you can see we use `X` to show where obsidian must be, `-` where the controls (Button/sign) are.
+- `portal-open` and `portal-closed` are used to specify
+ the [materials](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html) the portal's iris will use when
+ active/inactive respectively.
+ - Note that portal-open should be a *traversable* material, such as those
+ listed [here](https://sgrewritten.org/traversables).
+- Notwithstanding `#`, any single character may be used to represent any material (for example, `X` as a representation
+ of `OBSIDIAN`).
+- `-` is a special character: it represents the material to be used for behind your portal's control blocks (activator +
+ sign).
+- `button` is used to define what is used for the gate's *activator*. It may be any type of button, wall coral, or
+ container.
+- All materials can use a single tag or material, or a comma-separated list of tags, materials or both (#WOOL,Obsidian).
+ Upon generating a button, or opening/closing a Stargate, a random possible material is chosen. When validating, any
+ material/tag specified in the comma-separated list is considered valid.
-For more complex gate designs, it is possible to add more materials. If you add something like a=GLOWSTONE, `a` can then
-be used in the gate layout, just as `X` is used. See the `squarenetherglowstonegate.gate` file for an example.
-
-You will also notice a `*` in the gate layout, this is the "exit point" of the gate, the block at which the player will
-teleport in front of.
-
-## Buttons
-
-The actual buttons cannot be used underwater, but all the other items in the button list can be.
- The entire list of button types is as follows: (Click to expand)
+ The full list of valid activator types may be found below: (Click to expand)
```
-STONE_BUTTON
+Any kind of button (automatically updated):
+
OAK_BUTTON
SPRUCE_BUTTON
BIRCH_BUTTON
JUNGLE_BUTTON
ACACIA_BUTTON
DARK_OAK_BUTTON
+MANGROVE_BUTTON
+CHERRY_BUTTON
+PALE_OAK_BUTTON
+BAMBOO_BUTTON
CRIMSON_BUTTON
WARPED_BUTTON
+STONE_BUTTON
POLISHED_BLACKSTONE_BUTTON
CHEST
@@ -276,339 +322,498 @@ DEAD_HORN_CORAL_WALL_FAN
-## Underwater Portals
+#### Economy
-There is a default gate type for underwater gates. There are no real restrictions on underwater gate materials, except
-normal buttons cannot be used since they'd fall off. Using wall coral fans work much better, though `CHEST` and
-`SHULKER_BOX` works too.
+> These values require `useEconomy` to be true.
-Using `AIR` for a closed underwater gate looks weird, so `WATER` might be better. If using `AIR` for the closed gate,
-you need to make sure it actually contains air when creating it. For partially submerged portals, like ones used for
-boat teleportation, you need to keep water away from the portal entrance/opening until it's been created.
+- `useCost` defines the cost players are charged when using an existing portal.
+- `createCost` defines the cost players are charged when constructing a new portal.
+- `destroyCost` defines the cost players are charged when breaking an existing portal.
+- `toOwner` specifies the money's destination: if true, it will go to the player who made (owns) the gate; if false, the
+ money will be deleted.
-## Economy Support:
+### Structure
-The latest version of Stargate has support for Vault. Gate creation, destruction and use can all have different costs
-associated with them. You can also define per-gate layout costs. The default cost is assigned in the config.yml file,
-while the per-gate costs re defined in the .gate files. To define a certain cost to a gate just add these lines to your
-.gate file:
+#### Standard Custom Gates
+
+##### Basic formatting:
+
+Following a blank line after your keys section, you may specify your gate layout:
Simply lay out the portal as it
+will appear in your world, with every character representing a block.
```
- createCost: 5 -- Will cost 5 currency to create
- destroyCost: 5 -- Will clost 5 currency to destroy (negative to get back the spent money)
- useCost: 5 -- Will cost 5 currency to use the stargate
- toOwner: true -- Will send any fees to the gate's owner
+X=OBSIDIAN
+-=OBSIDIAN
+ XX
+X..X
+-..-
+X*.X
+ XX
+```
+
+This example is a standard nether portal.
+
+Any single character symbol (except for `#`) may represent any material
+In this case, `X` and `-` point to OBSIDIAN.
+
`-` is a special material character that specifies where the control blocks will be placed (i.e. sign & button)
+.
In this case, it is also `OBSIDIAN`.
+
+Other special characters include the following:
+
+- Spaces/blank characters (` `) will not be checked, and as such, represent any block.
+- Periods (`.`) represent the portal's *iris* (i.e. the part that opens and closes)
+- An asterix (`*`) represents the portals' "exit point" (i.e. the block the player will teleport in front of).
+
+##### Underwater Portals
+
+Gates may be constructed underwater in much the same manner as they may be constructed above the surface.
+There are, however, a few considerations for underwater portals:
+
+```
+portal-open=KELP_PLANT
+portal-closed=WATER
+button=BRAIN_CORAL_WALL_FAN
+toowner=false
+X=SEA_LANTERN
+-=SEA_LANTERN
+ XX
+X..X
+-..-
+X*.X
+ XX
+```
+
+- Buttons can not be waterlogged, and as such, are not ideal: wall coral fans are an ideal substitute.
+ - Containers (such as `CHEST` and `SHULKER_BOX`) are also valid alternatives.
+- `AIR` is generally a poor `portal-closed` material for underwater portals, since such portals are difficult to
+ construct and are visually problematic.
+ - `WATER` and other underwater [traversables](https://sgrewritten.org/traversables) work much better.
+
+##### Advanced format
+
+Gates are not limited to the shape of a standard nether portal -- they can be thousands of blocks big!
+In this case, a simple 5x5 square has been used as a gate.
+
+Gates are also not limited to [materials](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html) (such
+as `OBSIDIAN`); they may also use [tags](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Tag.html) (such
+as `#WOOL`), or a comma-separated list (such as `OBSIDIAN,#WOOL`).
+Note that all tags must be prefaced with a hashtag (`#`), as in `#WOOL`.
+
+```
+portal-open=WATER
+portal-closed=AIR
+X=#WOOL
+-=#WOOL
+XXXXX
+X...X
+-...-
+X.*.X
+XXXXX
+```
+
+Any block that is included within a given tag may be used to construct the portal.
+
+Furthermore, it is important to note that gates may have multiple materials in their frame, as shown below:
+
+```
+portal-open=NETHER_PORTAL
+portal-closed=AIR
+button=OAK_BUTTON
+toowner=false
+X=OBSIDIAN
+-=GLOWSTONE
+A=GLOWSTONE
+ XAX
+X...X
+-...-
+X.*.X
+ XAX
```
# Configuration
-```
-language - The language to use (Included languages: en, de, es, fr, hu, it, ja, nb-no, nl, nn-no, pt-br, ru, zh_cn)
-adminUpdateAlert - Whether to alert admins about an available update when joining the server
-folders:
- portalFolder - The folder your portal databases are saved in
- gateFolder - The folder containing your .gate files
-gates:
- maxGatesEachNetwork - If non-zero, will define the maximum amount of gates allowed on any network.
- defaultGateNetwork - The default gate network
- exitVelocity - The velocity to give players exiting stargates, relative to the entry velocity (1 = same as entry velocity)
- cosmetic:
- rememberDestination - Whether to set the first destination as the last used destination for all gates
- sortNetworkDestinations - If true, network lists will be sorted alphabetically.
- mainSignColor - This allows you to specify the color of the gate signs. Use a color code such as WHITE,BLACK,YELLOW or a hex color code such as '#ed76d9'. You need quotes around hex color codes.
- highlightSignColor - This allows you to specify the color of the sign markings. Use a color code such as WHITE,BLACK,YELLOW or a hex color code such as '#ed76d9'. You need quotes around hex color codes.
- perSignColors: - A list of per-sign color specifications. Format: "SIGN_TYPE:mainColor,highlight_color". The SIGN_TYPE is OAK for an oak sign, DARK_OAK for a dark oak sign and so on. The colors can be "default" to use the color specified in "mainSignColor" or "highlightSignColor", "inverted" to use the inverse color of the default color, a normal color such as BLACK,WHITE,YELLOW or a hex color code such as #ed76d9.
- integrity:
- destroyedByExplosion - Whether to destroy a stargate with explosions, or stop an explosion if it contains a gates controls.
- verifyPortals - Whether or not all the non-sign blocks are checked to match the gate layout when an old stargate is loaded at startup.
- protectEntrance - If true, will protect from users breaking gate entrance blocks (This is more resource intensive than the usual check, and should only be enabled for servers that use solid open/close blocks)
- functionality:
- enableBungee - Enable this for BungeeCord support. This allows portals across Bungee servers.
- handleVehicles - Whether or not to handle vehicles going through gates. Set to false to disallow vehicles (Manned or not) going through gates.
- handleEmptyVehicles - Whether or not to handle empty vehicles going through gates (chest/hopper/tnt/furnace minecarts included).
- handleCreatureTransportation - Whether or not to handle players that transport creatures by sending vehicles (minecarts, boats) through gates.
- handleNonPlayerVehicles - Whether or not to handle vehicles with a passenger which is not a player going through gates (pigs, horses, villagers, creepers, etc.). handleCreatureTransportation must be enabled.
- handleLeashedCreatures - Whether or not to handle creatures leashed by a player going through gates. Set to false to disallow leashed creatures going through gates.
- enableCraftBookRemoveOnEjectFix - Whether to enable a fix that causes loss of NBT data, but allows vehicle teleportation to work when CraftBook's remove minecart/boat on eject setting is enabled
-economy:
- useEconomy - Whether or not to enable Economy using Vault (must have the Vault plugin)
- createCost - The cost to create a stargate
- destroyCost - The cost to destroy a stargate (Can be negative for a "refund"
- useCost - The cost to use a stargate
- toOwner - Whether the money from gate-use goes to the owner or nobody
- chargeFreeDestination - Enable to make players pay for teleportation even if the destination is free
- freeGatesColored - Enable to make gates that won't cost the player money show up as green
- freeGatesColor - This allows you to specify the color of the markings and name of free stargates
-debugging:
- debug - Whether to show massive debug output
- permissionDebug - Whether to show massive permission debug output
-advanced:
- waitForPlayerAfterTeleportDelay - The amount of ticks to wait before adding a player as passenger of a vehicle. On slow servers, a value of 6 is required to avoid client glitches after teleporting on a vehicle.
-```
+| Node | Default | Description |
+|----------------------------------|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| language | en | The language to use (Included languages: cs, de, en, es, fr, hu, it, ja, nb, nl, nn, pt, ru, uk, zh). |
+| adminUpdateAlert | true | Whether to alert admins about an available update when joining the server. |
+| dynmap | | |
+| .enableDynmap | true | Should StarGate enable integration with Dynmap? This will show StarGates on your map. |
+| .dynmapIconsHiddenByDefault | false | Should StarGate icons be hidden by default? (must users manually enable their checkbox?) |
+| gates | | |
+| .maxGatesEachNetwork | 0 | If non-zero, will define the maximum amount of gates allowed on any network. |
+| .defaultGateNetwork | central | The default network for any non-personal Stargate without an explicitly defined network. |
+| .exitVelocity | 0.1 | The velocity to give players exiting stargates, relative to the entry velocity (1 = same as entry velocity) |
+| gates.functionality | | |
+| .enableCraftBookRemoveOnEjectFix | false | Should the plugin sacrifice vehicle integrity in order to fix a CraftBook destroy on exit incompatibility? |
+| .enableBungee | false | Enable this for BungeeCord support. This allows portals across Bungee servers. |
+| .handleVehicles | true | Whether or not to handle vehicles going through gates. Set to false to disallow vehicles (Manned or not) going through gates. |
+| .handleEmptyVehicles | true | Whether or not to handle empty vehicles going through gates (chest/hopper/tnt/furnace minecarts included). |
+| .handleCreatureTransportation | true | Whether to handle players that transport creatures by sending vehicles (minecarts, boats) through gates. |
+| .handleNonPlayerVehicles | true | Whether or not to handle vehicles with a passenger which is not a player going through gates (pigs, horses, villagers, creepers, etc.). handleCreatureTransportation must be enabled. |
+| .handleLeashedCreatures | true | Whether or not to handle creatures leashed by a player going through gates. Set to false to disallow leashed creatures going through gates. |
+| gates.integrity | | |
+| .destroyedByExplosion | false | Whether to destroy a stargate with explosions, or stop an explosion if it contains a gates controls. |
+| .verifyPortals | false | Whether or not all the non-sign blocks are checked to match the gate layout when an old stargate is loaded at startup. |
+| .protectEntrance | false | If true, will protect from users breaking gate entrance blocks (This is more resource intensive than the usual check, and should only be enabled for servers that use solid open/close blocks) |
+| .controlUpdateDelay | 3 | The amount of ticks to wait between each Stargate control block update after startup. Increase this if Stargate loads too many chunks during startup. |
+| gates.cosmetic | | |
+| .rememberDestination | false | Whether the topmost name on a sign's destinations should be the most recently used destination. |
+| .sortNetworkDestinations | false | If true, network lists will be sorted alphabetically. |
+| .mainSignColor | BLACK | This allows you to specify the color of the gate signs. Use a color code such as WHITE,BLACK,YELLOW or a hex color code such as '#ed76d9'. You need quotes around hex color codes. |
+| .highlightSignColor | WHITE | This allows you to specify the color of the sign markings. Use a color code such as WHITE,BLACK,YELLOW or a hex color code such as '#ed76d9'. You need quotes around hex color codes. |
+| .perSignColors | \[List] | A list of per-sign color specifications. Format: "SIGN_TYPE:mainColor,highlight_color". The SIGN_TYPE is OAK for an oak sign, DARK_OAK for a dark oak sign and so on. The colors can be "default" to use the color specified in "mainSignColor" or "highlightSignColor", "inverted" to use the inverse color of the default color, a normal color such as BLACK,WHITE,YELLOW or a hex color code such as #ed76d9. |
+| economy | | |
+| .freeGatesColored | false | Enable to make gates that won't cost the player money show up as green |
+| .freeGatesColor | DARK_GREEN | This allows you to specify the color of the markings and name of free stargates |
+| .useEconomy | false | Whether or not to enable Economy using Vault (must have the Vault plugin) |
+| .createCost | 0 | The cost to create a stargate |
+| .destroyCost | 0 | The cost to destroy a stargate (Can be negative for a "refund") |
+| .useCost | 0 | The cost to use a stargate |
+| .toOwner | false | Whether the money from gate-use goes to the owner or nobody |
+| .chargeFreeDestination | true | Enable to make players pay for teleportation even if the destination is free |
+| .taxAccount | '' | The tax account to use if the server uses a closed economy. |
+| folders | | |
+| .portalFolder | plugins/Stargate/portals/ | The folder your portal databases are saved in |
+| .gateFolder | plugins/Stargate/gates/ | The folder containing your .gate files |
+| debugging | | |
+| .debug | false | Whether to show massive debug output |
+| .permissionDebug | false | Whether to show massive permission debug output |
+| advanced | | |
+| .waitForPlayerAfterTeleportDelay | 6 | The amount of ticks to wait before adding a player as passenger of a vehicle. On slow servers, a value of 6 is required to avoid client glitches after teleporting on a vehicle. |
# Message Customization
-It is possible to customize all the messages Stargate displays, including the \[Stargate] prefix. You can find the
-strings in plugins/Stargate/lang/chosenLanguage.txt.
+It is possible to customize all the messages Stargate displays, including the \[Stargate] prefix.
You may find these
+strings in `plugins/Stargate/lang/chosenLanguage.txt`.
-If a string is removed, or left blank, it will default to the default english string. There are some special cases
-regarding messages. When you see %variableName%, you need to keep this part in your string, as it will be replaced with
-relevant values.
+If a string is removed, or left blank, it will default to the default english string.
There are some special cases
+Please note that %variableName% should be kept, as it will be replaced with a relevant value.
-The full list of strings is as follows:
+
+ The full list of strings may be found below: (Click to expand)
-```
-prefix=[Stargate]
-teleportMsg=Teleported
-destroyMsg=Gate Destroyed
-invalidMsg=Invalid Destination
-blockMsg=Destination Blocked
-destEmpty=Destination List Empty
-denyMsg=Access Denied
-reloaded=Stargate Reloaded
+| Path | Text |
+|-----------------------|--------------------------------------------------------------------|
+| prefix | \[Stargate] |
+| teleportMsg | Teleported |
+| destroyMsg | Gate Destroyed |
+| invalidMsg | Invalid Destination |
+| blockMsg | Destination Blocked |
+| destEmpty | Destination List Empty |
+| denyMsg | Access Denied |
+| reloaded | Stargate Reloaded |
+| | |
+| ecoDeduct | Deducted %cost% |
+| ecoRefund | Refunded %cost% |
+| ecoObtain | Obtained %cost% from Stargate %portal% |
+| ecoInFunds | Insufficient Funds |
+| ecoLoadError | Vault was loaded, but no economy plugin could be hooked into |
+| vaultLoadError | Economy is enabled but Vault could not be loaded. Economy disabled |
+| vaultLoaded | Vault v%version% found |
+| | |
+| createMsg | Gate Created |
+| createNetDeny | You do not have access to that network |
+| createGateDeny | You do not have access to that gate layout |
+| createPersonal | Creating gate on personal network |
+| createNameLength | Name too short or too long. |
+| createExists | A gate by that name already exists |
+| createFull | This network is full |
+| createWorldDeny | You do not have access to that world |
+| createConflict | Gate conflicts with existing gate |
+| | |
+| signRightClick | Right click |
+| signToUse | to use gate |
+| signRandom | Random |
+| signDisconnected | Disconnected |
+| signInvalidGate | Invalid gate |
+| | |
+| bungeeDisabled | BungeeCord support is disabled. |
+| bungeeDeny | You do not have permission to create BungeeCord gates. |
+| bungeeEmpty | BungeeCord gates require both a destination and network. |
+| bungeeSign | Teleport to |
+| | |
+| portalInfoTitle | \[STARGATE INFO] |
+| portalInfoName | Name: %name% |
+| portalInfoDestination | Destination: %destination% |
+| portalInfoNetwork | Network: %network% |
+| portalInfoServer | Server: %server% |
-ecoDeduct=Deducted %cost%
-ecoRefund=Refunded %cost%
-ecoObtain=Obtained %cost% from Stargate %portal%
-ecoInFunds=Insufficient Funds
-ecoLoadError=Vault was loaded, but no economy plugin could be hooked into
-vaultLoadError=Economy is enabled but Vault could not be loaded. Economy disabled
-vaultLoaded=Vault v%version% found
+
-createMsg=Gate Created
-createNetDeny=You do not have access to that network
-createGateDeny=You do not have access to that gate layout
-createPersonal=Creating gate on personal network
-createNameLength=Name too short or too long.
-createExists=A gate by that name already exists
-createFull=This network is full
-createWorldDeny=You do not have access to that world
-createConflict=Gate conflicts with existing gate
-
-signRightClick=Right click
-signToUse=to use gate
-signRandom=Random
-signDisconnected=Disconnected
-signInvalidGate=Invalid gate
-
-bungeeDisabled=BungeeCord support is disabled.
-bungeeDeny=You do not have permission to create BungeeCord gates.
-bungeeEmpty=BungeeCord gates require both a destination and network.
-bungeeSign=Teleport to
-
-portalInfoTitle=[STARGATE INFO]
-portalInfoName=Name: %name%
-portalInfoDestination=Destination: %destination%
-portalInfoNetwork=Network: %network%
-portalInfoServer=Server: %server%
-```
+> **PLEASE NOTE**: This method of localisation is slated to change in the upcoming rewrite!
If stargate does not
+> currently support your language, please submit a translation [here](https://sgrewritten.org/translate)!
# Changes
+#### \[Version 0.11.5.11] Unified Legacy Fork
+
+- Removes legacy sign drawing code, as the check for whether a server supported the sign sides kept failing for some
+ users.
+- Fixes some problems regarding the startup validation of Stargates, which caused valid Stargates to be disabled when
+ the verification option was enabled.
+
+#### \[Version 0.11.5.10] Unified Legacy Fork
+
+- Fixed a problem with material tag support
+- Made serveral optimisations to significantly improve performance on servers with high playercounts.
+
+#### \[Version 0.11.5.9] Unified Legacy Fork
+
+- Hotfix for the previous release, which accidently broke backwards compatibility for older servers (1.17-1.19).
+
+#### \[Version 0.11.5.8] Unified Legacy Fork
+
+- Cleaned up handling of invalid gate files during both migration and startup.
+- Backported the rewrite's translation system to legacy: to add new localisations, please
+ use [this page](https://sgrewritten.org/translate).
+- Updated various dependencies.
+- Optimisations in the migrator as to mitigate issues associated with importing large past deployments.
+- Improved handling of some potential error states involving Floodgate and Geyser.
+
+#### \[Version 0.11.5.7] Unified Legacy Fork
+
+- Added support for multiple materials and tags (comma separated).
+- Fixed an issue wherein dynmap crashes would cascade to Stargate
+- Backported the Rewrite's workaround for unexpected `END_GATEWAY` behaviour impacting geyser players.
+- Materials and tags are now handled agnostically; buttons and other generations are now less aggressive.
+
+#### \[Version 0.11.5.6] Unified Legacy Fork
+
+- Fixed a potential stack trace experienced when disabling Dynmap
+- Fixed some problems related to negative economy transactions.
+- Fixed an exception occuring when negative yaw values are encountered.
+- Updated the about command and added a debug command.
+
+#### \[Version 0.11.5.5] Unified Legacy Fork
+
+- Hotfix for a compatibility issue preventing the plugin from working on most pre-1.20 server jars.
+
+#### \[Version 0.11.5.4] Unified Legacy Fork
+
+- Fix for a problem which could cause activators to generate at invalid locations.
+- Minor documentation clarification.
+- Added support for MineCraft version 1.20
+
+#### \[Version 0.11.5.3] Unified Legacy Fork
+
+- Hotfix for an issue wherein the gate folder failed to populate on fresh installations.
+
+#### \[Version 0.11.5.2] Unified Legacy Fork
+
+- Improved handling of incompatible server environments (i.e. CraftBukkit)
+- Significantly improved an internal system responsible for yaml migrations.
+- Imported the LCLO fork's configuration comments.
+- Fixed a problem that caused the update checker to produce false positives.
+- Added support for Tax Accounts (part of Towny Closed Economies)
+
+#### \[Version 0.11.5.1] UNIFIED LEGACY FORK
+
+- Merged the fork into the [SG Rewritten Project](https://sgrewritten.org)
+- *This fork is now the maintained legacy branch of the Stargate Rewritten Project*.
+ - This plugin will be superseded in the near future by Stargate Rewritten,
a collaborative effort to wholly
+ rewrite and reimagine Drakia's code base.
+- Changed the `E` flag to `V`, to improve consistency for the rewrite.
+- Reworked the readme and changed some shortcuts
+
+#### \[Version 0.10.X.X] LCLO fork
+
+- Reimplemented/merged
+ the [LCLO fork ecosystem](https://github.com/stargate-rewritten/Stargate-ESR/tree/ESR-1.13.2-1.16.5),
+ notably:
+ - Added material #tag support
+ - Expanded legacy migration support
+ - Changed MSV to 1.16
+ - Added a new default gate file
+ - Added bstats
+
+> **NOTE: The LCLO fork has its own changelog,
+found [here](https://github.com/stargate-rewritten/Stargate-ESR#version-01081-lclo-fork)!**
+> For brevity, the full list has been excluded from the below.
+> In general, it is safe to assume **FULL LCLO PARITY** as of this version.
+
#### \[Version 0.9.4.2] EpicKnarvik97 fork
-- Avoids a NullPointerException if Dynmap is present, but isn't properly loaded.
-- Avoids some potential NullPointerExceptions related to Dynmap integration
-- Fixes end portals hijacking BungeeCord teleportation
-- Fixes a problem where a player might not be properly teleported from an end portal Stargate in the end to the
- over-world.
+- Prevents improperly loaded dependencies from causing problems with SG.
+- Improved Dynmap integration and associated bug fixes.
+- Fixes for some issues surrounding end portals.
#### \[Version 0.9.4.1] EpicKnarvik97 fork
-- Reverts to Spigot API 1.18
-- Adds Dynmap integration
+- Adds integration with [Dynmap](https://www.spigotmc.org/resources/dynmap%C2%AE.274/)
#### \[Version 0.9.4.0] EpicKnarvik97 fork
-- Updates Stargate to 1.19
+- Minecraft version 1.19 support.
#### \[Version 0.9.3.7] EpicKnarvik97 fork
-- Adds the Japanese language file provided by spigot user furplag
+- Added a Japanese localisation courtesy of `furplag`.
+ *For more info translation status, please see [this](https://sgrewritten.org/translate)*.
#### \[Version 0.9.3.6] EpicKnarvik97 fork
-- Adds the simplified Chinese language file provided by spigot user YKDZ
+- Added a Chinese (simplified) localisation courtesy of `YKDZ`.
+ *For more info translation status, please see [this](https://sgrewritten.org/translate)*.
#### \[Version 0.9.3.5] EpicKnarvik97 fork
-- Fixes the wait for player delay being too low by default
-- Performs some minor code optimizations and restructuring
+- Fixed an issue that could result in invisible players following teleportation.
+- Made some minor optimisations and code refactors.
#### \[Version 0.9.3.4] EpicKnarvik97 fork
-- Includes passengers of passengers when teleporting entities
-- Fixes a bug which caused Stargate to use more CPU for no reason
-- Teleports boats/minecarts like other vehicles unless *enableCraftBookRemoveOnEjectFix* is enabled
-- Adds the *waitForPlayerAfterTeleportDelay* config option which allows changing the delay between vehicle teleportation
- and the player being teleported to the vehicle
-- Makes boats keep their wood type even when re-created
+- Entities will now teleport with any passengers they may have.
+- Significantly optimised the plugin's CPU usage.
+- Added an alternative transportation method to resolve a CraftBook incompatibility, and an associated config
+ toggle (`enableCraftBookRemoveOnEjectFix`).
+- Added a config option (`waitForPlayerAfterTeleportDelay`) to allow users to specify the delay between vehicle
+ teleportation and player teleportation.
#### \[Version 0.9.3.3] EpicKnarvik97 fork
-- Prevents Zombified Piglins from randomly spawning at Stargates
+- Prevents Zombified Piglins from spawning at stargates with `nether-portal` irises.
#### \[Version 0.9.3.2] EpicKnarvik97 fork
-- Adds a config option to set the exit velocity of any players exiting a stargate
-- Adjusts vehicle teleportation a bit to prevent passengers' exit rotation from being wrong
-- Improves the checking for buggy double-clicks on non-button blocks
+- The velocity multiplier applied to users exiting stargates may now be modified through a config option.
+- Fixes an issue where players could exit stargates with improper head rotation.
+- Fixes an issue where, in certain circumstances, double-clicks on frame (non-activator) blocks could activate a gate.
#### \[Version 0.9.3.1] EpicKnarvik97 fork
-- Ignores the type of air when checking if a stargate is valid
+- Fixed an issue wherein one would be unable to create a stargate due to the presence of nonstandard air.
#### \[Version 0.9.3.0] EpicKnarvik97 fork
-- Adds support for RGB colors (use hex color codes)
-- Adds support for dyed and glowing signs
-- Adds support for specifying sign colors per sign type
-- Adds a tab-completable config sub-command for easily changing per-sign colors
-- Allows a per-sign color to be set as the inverse of the default color of the given type
+- Adds full support for the new sign colour features:
+ - Sign colours may now be specified through the use of RGB colour codes.
+ - Signs may now be dyed and/or glow-inked
+ - Colours may now be specified per sign type.
+- Adds the "sg config" command to allow users to easily change a given sign's RGB colours.
+ - One new option for this is "inverse", which inverts the default colour for a specific sign.
#### \[Version 0.9.2.5] EpicKnarvik97 fork
-- Updates Java version to JDK 17
-- Updates Spigot API version to 1.18
+- Updated plugin to use Java 17
+- Adds support for MineCraft version 1.18
#### \[Version 0.9.2.4] EpicKnarvik97 fork
-- Adds update checking, which will display a notice in the console when updates are available
-- Adds an alert about an available update when an admin joins the server
-- Adds the adminUpdateAlert config option to allow the admin notices to be turned off
+- Adds update checker, which will (optionally) display a notice in console and admins whenever a new SG update is
+ available.
+- Adds a config toggle (`adminUpdateAlert`) to disable the above.
#### \[Version 0.9.2.3] EpicKnarvik97 fork
-- Fixes a typo which caused both colors to change into the highlightSignColor
+- Fixes an issue that resulted in `highlightSignColor` being used for all colours.
#### \[Version 0.9.2.2] EpicKnarvik97 fork
-- Prevents teleportation of a player holding creatures on a leash when handleLeashedCreatures is disabled, to prevent
- players accidentally losing the creatures during teleportation
-- Fixes a potential exception when a gate's open-block or closed-block is set to a material which isn't a block
-- Fixes a potential exception when a portal without a sign has an invalid gate type
-- Prevents loading of gate files using non-blocks as part of the border
-- Prevents a player smuggling another player through a restricted stargate by sitting on a creature held in a lead by
- the first player
+- Fixed an issue wherein`handleLeashedCreatures` could cause accidental creature losses when disabled.
+- Prevented several potential crashes relating to invalid block and gate types.
+- Fixed an issue wherein a players could smuggle each other through Private stargates.
#### \[Version 0.9.2.1] EpicKnarvik97 fork
-- Makes sure to only reload whatever is necessary when config values are changed using commands, instead of reloading
- the entire config file every time
-- Protects portals from block placement when protectEntrance is enabled
+- Improves the efficiency and stability of the reload command.
+- Adds a toggle (`protectEntrance`) to extend portal protection to the iris.
#### \[Version 0.9.2.0] EpicKnarvik97 fork
- Increases max length of names and networks to 13 characters
-- Excludes color codes from the counted character length to allow a colored, 13-character name
-- Makes portal names and networks case- and color-agnostic to prevent some confusion caused by typos or sloppy
- configuration
-- Makes the free gate color configurable, and renames freeGatesGreen to freeGatesColored
+- Excludes color codes from the counted character length to allow coloured names with up to 13 characters.
+- Fixes an issue wherein typos or mistaken capitalisation could result in the creation of duplicated portals.
+- Makes the free gate color configurable, and renames the `freeGatesGreen` toggle to `freeGatesColored`.
#### \[Version 0.9.1.2] EpicKnarvik97 fork
-- Allows a sneaking player to see information about a silent stargate with no sign
+- Players may now see information about stargates (especially V gates) by sneaking and right-clicking.
#### \[Version 0.9.1.1] EpicKnarvik97 fork
-- Makes sure to translate the `&` character to fix a bug causing portal signs to not be colored on some servers
+- Fixed a bug where sign colouring failed due to improper translation of the `&` symbol.
#### \[Version 0.9.1.0] EpicKnarvik97 fork
-- Rewrites config loading as a part of the changes required to implement config commands
-- This update adds commands to change all config values from the chat or the console, complete with tab completion
-- Adds a new permission "stargate.admin.config" which is required to edit config values from the chat
+- Refactors the configuration loading systems as to facilitate the below:
+- Added the `sg config` command, to allow for all config values to be changed in-game by users with permission.
+ - The relevant permission is `stargate.admin.config`.
#### \[Version 0.9.0.7] EpicKnarvik97 fork
-- Stops registering the sign as a lookup block for stargates without a sign
-- Only removes a stargate's button if it's actually a button-compatible block
-- Only displays portal info if not placing a block
+- Fixes an issue involving sign registration for V gates.
+- Prevents a situation that may result in an invalid button state.
+- Tweaks when portal information is displayed to prevent an inconvenient conflict with block placement.
#### \[Version 0.9.0.6] EpicKnarvik97 fork
-- Makes containers no longer open when used as buttons
-- Validates and updates stargate buttons when the plugin is loaded or reloaded
-- Adds an option to make a stargate silent (no text in chat when teleporting) for better immersion on RP servers
-- Makes buttons update and/or remove themselves when their location or material changes
-- Adds another default gate to show that it's possible to use any number of materials for a stargate's border
-- Adds an option for stargates without a sign. Right-clicking such a stargate will display gate information
-- Fixes a bug causing signs to be re-drawn after they're broken
-- Makes buttons and signs be replaced by water instead of air when underwater
-- Makes portal info shown when right-clicking a stargate fully customizable
+- Prevents containers used as buttons from displaying the opening animation.
+- Improved load-time gate and button validation.
+- Adds the `Q` flag (suppresses chat messages related to portal use -- perfect for RP servers!).
+- Prevents a bug where buttons could incorrect overwrite materials.
+- Adds an additional default gate as to explain multi-material stargates.
+- Adds the `V` flag (hides the stargate's sign -- right-clicking will display the relevant information in chat).
+ - This is presented as an alternative for the `B` flag.
+- Fixes a bug where, in certain circumstances, signs could become unbreakable.
+- Improves how waterlogging is handled.
+- Right-clicking a stargate's frame will now display information in chat.
#### \[Version 0.9.0.5] EpicKnarvik97 fork
-- Adds an option to stargate functionality to disable all teleportation of creatures
-- Adds an option to stargate functionality to disable all teleportation of empty minecarts
-- Adds an option to stargate functionality to disable teleportation of creatures if no player is present in the vehicle
-- Prevents a player in a vehicle from teleporting without the vehicle if vehicle teleportation is disabled
-- Prevents an infinite number of teleportation messages if vehicle teleportation is detected but denied
+- Adds configuration toggles for:
+ - Whether living non-player entities may be teleported.
+ - Whether vehicles may teleport without a player riding them.
+ - Whether vehicles may teleport living non-player entities if accompanied by a player rider.
+- Fixes a bug that could result in unauthorised teleportation.
+- Fixes a bug that, in certain circumstances, could result in chat spam.
#### \[Version 0.9.0.4] EpicKnarvik97 fork
-- Adds teleportation of leashed creatures. By default, any creature connected to a player by a lead will be teleported
- with the player through stargates, even if the player is in a vehicle. This behavior can be disabled in the config
- file.
+- Leashed entities will now teleport with their associated player, even when that player is in a vehicle!
+- Added a configuration toggle for this feature.
#### \[Version 0.9.0.3] EpicKnarvik97 fork
-- Adds a missing error message when a player in a vehicle cannot pay the teleportation fee
-- Adds UUID migration to automatically update player names to UUID when possible
+- An error message has been clarified as to better account for vehicles.
+- Players with legacy string IDs will now be automatically converted to modern UUIDs upon joining.
#### \[Version 0.9.0.2] EpicKnarvik97 fork
-- Fixes a bug causing Stargates using NETHER_PORTAL blocks to generate nether portals in the nether.
+- Fixes a bug that could result in unwanted portals to generate in the nether.
#### \[Version 0.9.0.1] EpicKnarvik97 fork
-- Adds the highlightSignColor option and renames the signColor option to mainSignColor
-- Fixes some inconsistencies in sign coloring by using the highlight color for all markings
-- Fixes the order in which configs are loaded to prevent an exception
-- Adds migrations for the config change
+- Added coloured highlight patterns to signs: `highlightSignColor` has been added, and `signColor` has been renamed
+ to `mainSignColor`.
+- Addressed some inconsistencies in sign coloring by using the highlight color for all markings
+- Fixed some issues pertaining to configuration handling and management.
#### \[Version 0.9.0.0] EpicKnarvik97 fork
-- Changes entire path structure to a more modern and maven-compliant one
-- Changes package structure to net.knarcraft.stargate.*
-- Moves language files into the resources folder
-- Fixes some bugs caused by language files not being read as UTF-8
-- Adds JavaDoc to a lot of the code
-- Adds Norwegian translation for both Norwegian languages
-- Adds missing dependency information to plugin.yml
-- Uses text from the language files in more places
-- Changes how backup language works, causing english strings to be shown if not available from the chosen language
-- Removes some pre-UUID code
-- Adds underwater portals
-- Makes it easier to add more default gates
-- Adds a new default gate which can be used underwater
-- Adds more items usable as buttons (corals, chest, shulker-box), which allows underwater portals
-- Splits a lot of the code into smaller objects
-- Moves duplicated code into helper classes
-- Re-implements vehicle teleportation
-- Makes boat teleportation work as expected, including being able to teleport with two passengers. This allows players
- to use boats to transport creatures through portals and to other areas, or even worlds
-- Makes it possible to teleport a player riding a living entity (a pig, a horse, a donkey, a zombie horse, a skeleton
- horse or a strider). It does not work for entities the player cannot control, such as llamas.
-- Makes both nether portals and end gateways work properly without causing mayhem
-- Replaces the modX and modZ stuff with yaw calculation to make it easier to understand
-- Comments all the code
-- Extracts portal options and portal-related locations to try and reduce size
-- Rewrites tons of code to make it more readable and manageable
-- Implements proper snowman snow blocking, and removes the "temporary" ignoreEntrances option
-- Adds a default gate using end stone bricks and end gateway for more default diversity
-- Makes portals using end portal blocks work as expected
-- Adds missing permissions to the readme
-- Adds missing permissions to plugin.yml and simplifies permission checks by specifying default values for child
- permissions
-- Renames stargate.reload to stargate.admin.reload to maintain consistency
-- Marks stargates which cannot be loaded because of the gate layout not having been loaded
-- Uses white for the "-" characters on the side of each stargate name when drawing signs to increase readability
-- Uses white to mark the selected destination when cycling through stargate destinations
+- Significantly refactored the legacy codebase for readability and quality.
+ - Added developer documentation.
+- Changed the package to net.knarcraft.stargate.*
+- Improved localisations and their handling.
+ - Added several new translations.
+- Fixed some encoding problems.
+- Added some missing dependencies, updated the project's plugin file.
+- Made underwater portals practical by reworking activator materials and adding support for waterlogging.
+- Updated the vehicle teleportation code to work in modern versions of the game, and addressed CVE-2021-43819.
+- Updated boat teleportation to account for multi-passenger vehicles.
+- Added support for passengers and leashed entities.
+- Fixed some issues surrounding block states and data (notably, nether portals and end gateways).
+- Overhauled the plugin's handling of movement.
+- Slightly improved the plugin's flatfile storage structure.
+- Improved portal protection, implemented many associated "TODOs"
+- Adds another default gate to illustrate multi-type designs.
+- Significantly improved the plugin's documentation via README
+- Properly implemented a load of missing permissions -- especially including handling of child nodes.
+- Renamed the stargate.reload node to stargate.admin.reload as to improve consistency
+- Improves the stability of Stargate's load-time portal handling.
+- Highlights destination selector brackets on signs ("-") as to improve readability.
- Uses dark red to mark portals which are inactive (missing destination or invalid gate type)
-- Re-draws signs on startup in case they change
-- Fixes some bugs preventing changing the portal-open block on the fly
-- Adds a translate-able string for when the plugin has been reloaded
+- Adds provision to re-draw incorrect signs.
+- Fixed a load of other miscellaneous bugs.
#### \[Version 0.8.0.3] PseudoKnight fork
@@ -1200,4 +1405,4 @@ portalInfoServer=Server: %server%
- Changed package to net.TheDgtl.*
- Everything now uses Blox instead of Block objects
-- Started on vehicle code, but it's still buggy
\ No newline at end of file
+- Started on vehicle code, but it's still buggy
diff --git a/pom.xml b/pom.xml
index 2e1bead..276595c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
net.knarcraft
Stargate
- 0.9.4.3-SNAPSHOT
+ 0.11.5.11
@@ -28,8 +28,8 @@
https://hub.spigotmc.org/nexus/content/groups/public/
- vault-repo
- https://nexus.hc.to/content/repositories/pub_releases
+ jitpack.io
+ https://jitpack.io
dynmap
@@ -39,67 +39,82 @@
papermc
https://repo.papermc.io/repository/maven-public/
-
-
- knarcraft-repo
- https://git.knarcraft.net/api/packages/EpicKnarvik97/maven
+ minebench-repo
+ https://repo.minebench.de/
-
- knarcraft-repo
- https://git.knarcraft.net/api/packages/EpicKnarvik97/maven
-
-
+
+ opencollab-snapshot
+ https://repo.opencollab.dev/main/
+
+
org.spigotmc
spigot-api
- 1.19.3-R0.1-SNAPSHOT
+ 1.21.8-R0.1-SNAPSHOT
provided
- net.milkbowl.vault
+ com.github.MilkBowl
VaultAPI
- 1.7
+ 1.7.1
provided
-
- org.junit.jupiter
- junit-jupiter-api
- 5.9.0
- test
-
-
- com.github.seeseemelk
- MockBukkit-v1.18
- 2.85.2
- test
-
org.jetbrains
annotations
- 23.0.0
+ 26.0.0
provided
-
- junit
- junit
- 4.13.2
- test
-
us.dynmap
dynmap-api
- 3.1-beta-2
+ 3.5
provided
net.knarcraft
knarlib
- 1.0-SNAPSHOT
+ 1.2.18
compile
+
+ org.bstats
+ bstats-bukkit
+ 3.0.2
+ compile
+
+
+ org.bstats
+ bstats-base
+ 3.0.2
+
+
+ de.themoep
+ minedown
+ 1.7.1-SNAPSHOT
+ compile
+
+
+ org.geysermc.geyser
+ api
+ 2.2.0-SNAPSHOT
+ provided
+
+
+ org.geysermc.floodgate
+ api
+ 2.2.2-SNAPSHOT
+ provided
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.11.4
+ test
+
@@ -116,7 +131,8 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.2.4
+ 3.4.1
+
package
@@ -125,7 +141,37 @@
false
+
+
+ org.bstats
+ net.knarcraft.stargate.lib.metrics
+
+
+ net.knarcraft.knarlib
+ net.knarcraft.stargate.lib.knarlib
+
+
+ de.themoep
+ net.knarcraft.stargate.lib.minedown
+
+
+ org.jetbrains.annotations
+ net.knarcraft.blacksmith.lib.annotations
+
+
+
+ de.themoep:minedown
+
+ de/themoep/minedown/**
+
+
+
+ org.bstats
+
+ org/bstats/**
+
+
net.knarcraft:knarlib
@@ -133,10 +179,10 @@
-
- *.MF
- *.yml
-
+ org.jetbrains:annotations
+
+ org/jetbrains/annotations/**
+
@@ -151,4 +197,4 @@
-
\ No newline at end of file
+
diff --git a/src/main/java/net/knarcraft/stargate/Stargate.java b/src/main/java/net/knarcraft/stargate/Stargate.java
index 2cb40b1..3a3dec8 100644
--- a/src/main/java/net/knarcraft/stargate/Stargate.java
+++ b/src/main/java/net/knarcraft/stargate/Stargate.java
@@ -1,14 +1,20 @@
package net.knarcraft.stargate;
+import net.knarcraft.knarlib.formatting.StringFormatter;
+import net.knarcraft.knarlib.formatting.Translator;
+import net.knarcraft.knarlib.plugin.ConfigCommentPlugin;
+import net.knarcraft.knarlib.util.ConfigHelper;
import net.knarcraft.knarlib.util.UpdateChecker;
import net.knarcraft.stargate.command.CommandStarGate;
import net.knarcraft.stargate.command.StarGateTabCompleter;
import net.knarcraft.stargate.config.EconomyConfig;
-import net.knarcraft.stargate.config.MessageSender;
+import net.knarcraft.stargate.config.Message;
+import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.config.StargateConfig;
import net.knarcraft.stargate.config.StargateGateConfig;
import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.container.ChunkUnloadRequest;
+import net.knarcraft.stargate.container.ControlBlockUpdateRequest;
import net.knarcraft.stargate.listener.BlockEventListener;
import net.knarcraft.stargate.listener.EntityEventListener;
import net.knarcraft.stargate.listener.EntitySpawnListener;
@@ -22,15 +28,16 @@ import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.thread.BlockChangeThread;
import net.knarcraft.stargate.thread.ChunkUnloadThread;
+import net.knarcraft.stargate.thread.ControlBlocksUpdateThread;
import net.knarcraft.stargate.thread.StarGateThread;
-import org.bukkit.Server;
-import org.bukkit.command.PluginCommand;
-import org.bukkit.configuration.file.FileConfiguration;
+import net.knarcraft.stargate.utility.BStatsHelper;
+import org.bukkit.Bukkit;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
-import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
import org.bukkit.scheduler.BukkitScheduler;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.LinkedList;
@@ -45,7 +52,7 @@ Copyright (C) 2011 Shaun (sturmeh)
Copyright (C) 2011 Dinnerbone
Copyright (C) 2011-2013 Steven "Drakia" Scott
Copyright (C) 2015-2020 Michael Smith (PseudoKnight)
-Copyright (C) 2021-2022 Kristian Knarvik (EpicKnarvik97)
+Copyright (C) 2021-2025 Kristian Knarvik (EpicKnarvik97)
The following license notice applies to all source and resource files in the Stargate project:
@@ -67,9 +74,11 @@ along with this program. If not, see .
* The main class of the Stargate plugin
*/
@SuppressWarnings("unused")
-public class Stargate extends JavaPlugin {
+public class Stargate extends ConfigCommentPlugin {
- private static final Queue blockChangeRequestQueue = new LinkedList<>();
+ private static final String CONFIG_FILE_NAME = "config.yml";
+ private static final Queue controlBlockUpdateRequestQueue = new LinkedList<>();
+ private static final Queue CONTROL_BLOCK_UPDATE_REQUEST_QUEUE = new LinkedList<>();
private static final Queue chunkUnloadQueue = new PriorityQueue<>();
private static Logger logger;
@@ -105,7 +114,7 @@ public class Stargate extends JavaPlugin {
*
* @param version The version of the new update available
*/
- public static void setUpdateAvailable(String version) {
+ public static void setUpdateAvailable(@NotNull String version) {
updateAvailable = version;
}
@@ -114,6 +123,7 @@ public class Stargate extends JavaPlugin {
*
* @return The version number if an update is available. Null otherwise
*/
+ @Nullable
public static String getUpdateAvailable() {
return updateAvailable;
}
@@ -123,6 +133,7 @@ public class Stargate extends JavaPlugin {
*
* @return An instance of this plugin, or null if not instantiated
*/
+ @NotNull
public static Stargate getInstance() {
return stargate;
}
@@ -132,28 +143,41 @@ public class Stargate extends JavaPlugin {
*
* @param request The request to add
*/
- public static void addBlockChangeRequest(BlockChangeRequest request) {
+ public static void addControlBlockUpdateRequest(@Nullable BlockChangeRequest request) {
if (request != null) {
- blockChangeRequestQueue.add(request);
+ controlBlockUpdateRequestQueue.add(request);
}
}
/**
- * Gets the queue containing block change requests
+ * Gets the queue containing control block update requests
*
- * @return A block change request queue
+ * @return A control block update request queue
*/
- public static Queue getBlockChangeRequestQueue() {
- return blockChangeRequestQueue;
+ @NotNull
+ public static Queue getControlBlockUpdateRequestQueue() {
+ return controlBlockUpdateRequestQueue;
}
/**
- * Gets the sender for sending messages to players
+ * Adds a control block update request to the request queue
*
- * @return The sender for sending messages to players
+ * @param request The request to add
*/
- public static MessageSender getMessageSender() {
- return stargateConfig.getMessageSender();
+ public static void addControlBlockUpdateRequest(@Nullable ControlBlockUpdateRequest request) {
+ if (request != null) {
+ CONTROL_BLOCK_UPDATE_REQUEST_QUEUE.add(request);
+ }
+ }
+
+ /**
+ * Gets the queue containing button update requests
+ *
+ * @return A button update request queue
+ */
+ @NotNull
+ public static Queue getButtonUpdateRequestQueue() {
+ return CONTROL_BLOCK_UPDATE_REQUEST_QUEUE;
}
/**
@@ -161,6 +185,7 @@ public class Stargate extends JavaPlugin {
*
* @return The object containing gate configuration values
*/
+ @NotNull
public static StargateGateConfig getGateConfig() {
return stargateConfig.getStargateGateConfig();
}
@@ -170,6 +195,7 @@ public class Stargate extends JavaPlugin {
*
* @return This plugin's version
*/
+ @NotNull
public static String getPluginVersion() {
return pluginVersion;
}
@@ -179,6 +205,7 @@ public class Stargate extends JavaPlugin {
*
* @return The logger
*/
+ @NotNull
public static Logger getConsoleLogger() {
return logger;
}
@@ -199,8 +226,8 @@ public class Stargate extends JavaPlugin {
* @param route The class name/route where something happened
* @param message A message describing what happened
*/
- public static void debug(String route, String message) {
- if (stargateConfig == null || stargateConfig.isDebuggingEnabled()) {
+ public static void debug(@NotNull String route, @NotNull String message) {
+ if (stargateConfig == null || stargateConfig.isNotLoaded() || stargateConfig.isDebuggingEnabled()) {
logger.info("[Stargate::" + route + "] " + message);
} else {
logger.log(Level.FINEST, "[Stargate::" + route + "] " + message);
@@ -212,8 +239,8 @@ public class Stargate extends JavaPlugin {
*
* @param message The message to log
*/
- public static void logInfo(String message) {
- logger.info(getBackupString("prefix") + message);
+ public static void logInfo(@NotNull String message) {
+ log(Level.INFO, message);
}
/**
@@ -221,7 +248,7 @@ public class Stargate extends JavaPlugin {
*
* @param message The message to log
*/
- public static void logSevere(String message) {
+ public static void logSevere(@NotNull String message) {
log(Level.SEVERE, message);
}
@@ -230,7 +257,7 @@ public class Stargate extends JavaPlugin {
*
* @param message The message to log
*/
- public static void logWarning(String message) {
+ public static void logWarning(@NotNull String message) {
log(Level.WARNING, message);
}
@@ -240,8 +267,11 @@ public class Stargate extends JavaPlugin {
* @param severity The severity of the event triggering the message
* @param message The message to log
*/
- private static void log(Level severity, String message) {
- logger.log(severity, getBackupString("prefix") + message);
+ private static void log(@NotNull Level severity, @NotNull String message) {
+ if (logger == null) {
+ logger = Bukkit.getLogger();
+ }
+ logger.log(severity, message);
}
/**
@@ -251,6 +281,7 @@ public class Stargate extends JavaPlugin {
*
* @return The folder for storing the portal database
*/
+ @NotNull
public static String getPortalFolder() {
return stargateConfig.getPortalFolder();
}
@@ -262,6 +293,7 @@ public class Stargate extends JavaPlugin {
*
* @return The folder storing gate files
*/
+ @NotNull
public static String getGateFolder() {
return stargateConfig.getGateFolder();
}
@@ -271,51 +303,27 @@ public class Stargate extends JavaPlugin {
*
* @return The default network
*/
+ @NotNull
public static String getDefaultNetwork() {
return stargateConfig.getStargateGateConfig().getDefaultPortalNetwork();
}
/**
- * Gets a translated string given its string key
- *
- * The name/key is the string before the equals sign in the language files
- *
- * @param name The name/key of the string to get
- * @return The full translated string
- */
- public static String getString(String name) {
- return stargateConfig.getLanguageLoader().getString(name);
- }
-
- /**
- * Gets a backup string given its string key
- *
- * The name/key is the string before the equals sign in the language files
+ * Gets a backup string given its message key
*
* @param name The name/key of the string to get
* @return The full string in the backup language (English)
*/
- public static String getBackupString(String name) {
+ public static @NotNull String getBackupString(@NotNull Message name) {
return stargateConfig.getLanguageLoader().getBackupString(name);
}
- /**
- * Replaces a variable in a string
- *
- * @param input The input containing the variables
- * @param search The variable to replace
- * @param value The replacement value
- * @return The input string with the search replaced with value
- */
- public static String replaceVars(String input, String search, String value) {
- return input.replace(search, value);
- }
-
/**
* Gets this plugin's plugin manager
*
* @return A plugin manager
*/
+ @NotNull
public static PluginManager getPluginManager() {
return pluginManager;
}
@@ -325,6 +333,7 @@ public class Stargate extends JavaPlugin {
*
* @return The object containing economy config values
*/
+ @NotNull
public static EconomyConfig getEconomyConfig() {
return stargateConfig.getEconomyConfig();
}
@@ -333,24 +342,34 @@ public class Stargate extends JavaPlugin {
public void onDisable() {
PortalHandler.closeAllPortals();
PortalRegistry.clearPortals();
- stargateConfig.clearManagedWorlds();
+ if (stargateConfig != null) {
+ stargateConfig.clearManagedWorlds();
+ }
getServer().getScheduler().cancelTasks(this);
}
@Override
public void onEnable() {
+ Stargate.stargate = this;
+ Stargate.logger = getLogger();
+ ConfigHelper.saveDefaults(this);
PluginDescriptionFile pluginDescriptionFile = this.getDescription();
pluginManager = getServer().getPluginManager();
- FileConfiguration newConfig = this.getConfig();
- this.saveDefaultConfig();
- newConfig.options().copyDefaults(true);
- logger = Logger.getLogger("Minecraft");
- Server server = getServer();
- stargate = this;
+ // Set temporary string formatter before strings are loaded
+ SGFormatBuilder.setStringFormatter(new StringFormatter(this.getDescription().getName(), new Translator()));
- stargateConfig = new StargateConfig(logger);
- stargateConfig.finishSetup();
+ try {
+ stargateConfig = new StargateConfig(logger);
+ stargateConfig.finishSetup();
+ } catch (NoClassDefFoundError exception) {
+ logSevere("Could not properly load. Class not found: " +
+ exception.getMessage() + "\nThis is probably because you are using CraftBukkit, or other outdated" +
+ "Minecraft server software. Minecraft server software based on Spigot or Paper is required. Paper" +
+ " is recommended, and can be downloaded at: https://papermc.io/downloads/paper");
+ this.onDisable();
+ return;
+ }
pluginVersion = pluginDescriptionFile.getVersion();
@@ -362,11 +381,13 @@ public class Stargate extends JavaPlugin {
//Run necessary threads
runThreads();
- this.registerCommands();
+ registerCommand("stargate", new CommandStarGate(this), new StarGateTabCompleter());
//Check for any available updates
- UpdateChecker.checkForUpdate(this, "https://api.spigotmc.org/legacy/update.php?resource=97784",
+ UpdateChecker.checkForUpdate(this, "https://api.spigotmc.org/legacy/update.php?resource=109355",
Stargate::getPluginVersion, Stargate::setUpdateAvailable);
+
+ BStatsHelper.initialize(this);
}
/**
@@ -376,6 +397,8 @@ public class Stargate extends JavaPlugin {
BukkitScheduler scheduler = getServer().getScheduler();
scheduler.runTaskTimer(this, new StarGateThread(), 0L, 100L);
scheduler.runTaskTimer(this, new BlockChangeThread(), 0L, 1L);
+ scheduler.runTaskTimer(this, new ControlBlocksUpdateThread(), 0L,
+ getStargateConfig().getStargateGateConfig().controlUpdateDelay());
scheduler.runTaskTimer(this, new ChunkUnloadThread(), 0L, 100L);
}
@@ -395,22 +418,12 @@ public class Stargate extends JavaPlugin {
pluginManager.registerEvents(new EntitySpawnListener(), this);
}
- /**
- * Registers a command for this plugin
- */
- private void registerCommands() {
- PluginCommand stargateCommand = this.getCommand("stargate");
- if (stargateCommand != null) {
- stargateCommand.setExecutor(new CommandStarGate());
- stargateCommand.setTabCompleter(new StarGateTabCompleter());
- }
- }
-
/**
* Gets the chunk unload queue containing chunks to unload
*
* @return The chunk unload queue
*/
+ @NotNull
public static Queue getChunkUnloadQueue() {
return chunkUnloadQueue;
}
@@ -420,7 +433,7 @@ public class Stargate extends JavaPlugin {
*
* @param request The new chunk unload request to add
*/
- public static void addChunkUnloadRequest(ChunkUnloadRequest request) {
+ public static void addChunkUnloadRequest(@NotNull ChunkUnloadRequest request) {
chunkUnloadQueue.removeIf((item) -> item.getChunkToUnload().equals(request.getChunkToUnload()));
chunkUnloadQueue.add(request);
}
@@ -430,6 +443,7 @@ public class Stargate extends JavaPlugin {
*
* @return The stargate configuration
*/
+ @NotNull
public static StargateConfig getStargateConfig() {
return stargateConfig;
}
diff --git a/src/main/java/net/knarcraft/stargate/command/CommandAbout.java b/src/main/java/net/knarcraft/stargate/command/CommandAbout.java
index f0acd50..715e656 100644
--- a/src/main/java/net/knarcraft/stargate/command/CommandAbout.java
+++ b/src/main/java/net/knarcraft/stargate/command/CommandAbout.java
@@ -1,12 +1,20 @@
package net.knarcraft.stargate.command;
+import de.themoep.minedown.MineDown;
+import net.knarcraft.knarlib.util.FileHelper;
import net.knarcraft.stargate.Stargate;
+import net.knarcraft.stargate.config.Message;
import net.md_5.bungee.api.ChatColor;
+import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
/**
* This command represents the plugin's about command
*/
@@ -18,11 +26,19 @@ public class CommandAbout implements CommandExecutor {
ChatColor textColor = ChatColor.GOLD;
ChatColor highlightColor = ChatColor.GREEN;
- commandSender.sendMessage(textColor + "Stargate Plugin originally created by " + highlightColor +
- "Drakia" + textColor + ", and revived by " + highlightColor + "EpicKnarvik97");
- commandSender.sendMessage(textColor + "Go to " + highlightColor +
- "https://git.knarcraft.net/EpicKnarvik97/Stargate " + textColor + "for the official repository");
- String author = Stargate.getStargateConfig().getLanguageLoader().getString("author");
+
+
+ try (InputStream inputStream = FileHelper.getInputStreamForInternalFile("/messages/about.md")) {
+ if (inputStream != null) {
+ List lines = FileHelper.readLines(FileHelper.getBufferedReaderFromInputStream(inputStream));
+ String aboutMessageString = String.join("\n", lines);
+ BaseComponent[] component = MineDown.parse(aboutMessageString);
+ commandSender.spigot().sendMessage(component);
+ }
+ } catch (IOException ioException) {
+ commandSender.sendMessage("Internal error");
+ }
+ String author = Stargate.getStargateConfig().getLanguageLoader().getString(Message.AUTHOR);
if (!author.isEmpty()) {
commandSender.sendMessage(textColor + "Language created by " + highlightColor + author);
}
diff --git a/src/main/java/net/knarcraft/stargate/command/CommandConfig.java b/src/main/java/net/knarcraft/stargate/command/CommandConfig.java
index 6374518..dd5d5d2 100644
--- a/src/main/java/net/knarcraft/stargate/command/CommandConfig.java
+++ b/src/main/java/net/knarcraft/stargate/command/CommandConfig.java
@@ -4,7 +4,9 @@ import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.ConfigOption;
import net.knarcraft.stargate.config.ConfigTag;
import net.knarcraft.stargate.config.DynmapManager;
+import net.knarcraft.stargate.config.Message;
import net.knarcraft.stargate.config.OptionDataType;
+import net.knarcraft.stargate.config.SGFormatBuilder;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalRegistry;
import net.knarcraft.stargate.portal.PortalSignDrawer;
@@ -16,6 +18,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
@@ -30,7 +33,7 @@ public class CommandConfig implements CommandExecutor {
@NotNull String[] args) {
if (commandSender instanceof Player player) {
if (!player.hasPermission("stargate.admin.config")) {
- Stargate.getMessageSender().sendErrorMessage(commandSender, "Permission Denied");
+ new SGFormatBuilder("Permission Denied").error(commandSender);
return true;
}
}
@@ -65,7 +68,8 @@ public class CommandConfig implements CommandExecutor {
* @param commandSender The command sender that changed the value
* @param value The new value of the config option
*/
- private void updateConfigValue(ConfigOption selectedOption, CommandSender commandSender, String value) {
+ private void updateConfigValue(@NotNull ConfigOption selectedOption, @NotNull CommandSender commandSender,
+ @NotNull String value) {
FileConfiguration configuration = Stargate.getInstance().getConfig();
//Validate any sign colors
@@ -119,7 +123,8 @@ public class CommandConfig implements CommandExecutor {
* @param value The new value of the config option
* @param configuration The configuration file to save to
*/
- private void updateBooleanConfigValue(ConfigOption selectedOption, String value, FileConfiguration configuration) {
+ private void updateBooleanConfigValue(@NotNull ConfigOption selectedOption, @NotNull String value,
+ @NotNull FileConfiguration configuration) {
boolean newValue = Boolean.parseBoolean(value);
if (selectedOption == ConfigOption.ENABLE_BUNGEE && newValue != Stargate.getGateConfig().enableBungee()) {
Stargate.getStargateConfig().startStopBungeeListener(newValue);
@@ -135,7 +140,8 @@ public class CommandConfig implements CommandExecutor {
* @param commandSender The command sender that changed the value
* @param value The new value of the config option
*/
- private void updateStringConfigValue(ConfigOption selectedOption, CommandSender commandSender, String value) {
+ private void updateStringConfigValue(@NotNull ConfigOption selectedOption, @NotNull CommandSender commandSender,
+ @NotNull String value) {
if (selectedOption == ConfigOption.GATE_FOLDER || selectedOption == ConfigOption.PORTAL_FOLDER ||
selectedOption == ConfigOption.DEFAULT_GATE_NETWORK) {
if (value.contains("../") || value.contains("..\\")) {
@@ -161,13 +167,13 @@ public class CommandConfig implements CommandExecutor {
* @param commandSender The command sender that changed the value
* @param arguments The arguments for the new config option
*/
- private void updateListConfigValue(ConfigOption selectedOption, CommandSender commandSender, String[] arguments) {
+ private void updateListConfigValue(@NotNull ConfigOption selectedOption, @NotNull CommandSender commandSender,
+ @NotNull String[] arguments) {
FileConfiguration configuration = Stargate.getInstance().getConfig();
if (selectedOption == ConfigOption.PER_SIGN_COLORS) {
if (arguments.length < 4) {
- Stargate.getMessageSender().sendErrorMessage(commandSender, "Usage: /sg config perSignColors " +
- " ");
+ new SGFormatBuilder("Usage: /sg config perSignColors ").error(commandSender);
return;
}
@@ -190,22 +196,24 @@ public class CommandConfig implements CommandExecutor {
* @param arguments The arguments given by the user
* @return The per-sign color string to update with, or null if the input was invalid
*/
- private String parsePerSignColorInput(CommandSender commandSender, String[] arguments) {
+ @Nullable
+ private String parsePerSignColorInput(@NotNull CommandSender commandSender, @NotNull String[] arguments) {
//Make sure the sign type is an actual sign
if (Material.matchMaterial(arguments[1] + "_SIGN") == null) {
- Stargate.getMessageSender().sendErrorMessage(commandSender, "The given sign type is invalid");
+ new SGFormatBuilder("The given sign type is invalid").error(commandSender);
return null;
}
String colorString = arguments[1] + ":";
//Validate the colors given by the user
- String[] errorMessage = new String[]{"The given main sign color is invalid!", "The given highlight sign color is invalid!"};
+ String[] errorMessage = new String[]{"The given main sign color is invalid!", "The given highlight sign color " +
+ "is invalid!"};
String[] newColors = new String[2];
for (int i = 0; i < 2; i++) {
if (validatePerSignColor(arguments[i + 2])) {
newColors[i] = arguments[i + 2];
} else {
- Stargate.getMessageSender().sendErrorMessage(commandSender, errorMessage[i]);
+ new SGFormatBuilder(errorMessage[i]).error(commandSender);
return null;
}
}
@@ -220,9 +228,11 @@ public class CommandConfig implements CommandExecutor {
* @param colorString The new color string to replace any previous value with
* @param configuration The file configuration to update with the new per-sign colors
*/
- private void updatePerSignColors(String signType, String colorString, FileConfiguration configuration) {
+ private void updatePerSignColors(@NotNull String signType, @NotNull String colorString,
+ @NotNull FileConfiguration configuration) {
List newColorStrings = new ArrayList<>();
- List> oldColors = (List>) Stargate.getStargateConfig().getConfigOptionsReference().get(ConfigOption.PER_SIGN_COLORS);
+ List> oldColors = (List>) Stargate.getStargateConfig().getConfigOptionsReference().get(
+ ConfigOption.PER_SIGN_COLORS);
for (Object object : oldColors) {
newColorStrings.add(String.valueOf(object));
}
@@ -239,7 +249,7 @@ public class CommandConfig implements CommandExecutor {
* @param color The color chosen by the user
* @return True if the given color is valid
*/
- private boolean validatePerSignColor(String color) {
+ private boolean validatePerSignColor(@NotNull String color) {
ChatColor newHighlightColor = parseColor(color);
return newHighlightColor != null || color.equalsIgnoreCase("default") ||
color.equalsIgnoreCase("inverted");
@@ -251,11 +261,11 @@ public class CommandConfig implements CommandExecutor {
* @param selectedOption The config option that was changed
* @param commandSender The command sender that executed the config command
*/
- private void saveAndReload(ConfigOption selectedOption, CommandSender commandSender) {
+ private void saveAndReload(@NotNull ConfigOption selectedOption, @NotNull CommandSender commandSender) {
//Save the config file and reload if necessary
Stargate.getInstance().saveConfig();
- Stargate.getMessageSender().sendSuccessMessage(commandSender, "Config updated");
+ new SGFormatBuilder("Config updated").success(commandSender);
//Reload whatever is necessary
reloadIfNecessary(commandSender, selectedOption);
@@ -268,7 +278,8 @@ public class CommandConfig implements CommandExecutor {
* @param commandSender The command sender to alert if the color is invalid
* @param value The new option value
*/
- private boolean registerColor(ConfigOption selectedOption, String value, CommandSender commandSender) {
+ private boolean registerColor(@NotNull ConfigOption selectedOption, @NotNull String value,
+ @NotNull CommandSender commandSender) {
ChatColor parsedColor = parseColor(value);
if (parsedColor == null) {
commandSender.sendMessage(ChatColor.RED + "Invalid color given");
@@ -291,7 +302,8 @@ public class CommandConfig implements CommandExecutor {
* @param value The value to parse
* @return The parsed color or null
*/
- private ChatColor parseColor(String value) {
+ @Nullable
+ private ChatColor parseColor(@NotNull String value) {
try {
return ChatColor.of(value.toUpperCase());
} catch (IllegalArgumentException | NullPointerException ignored) {
@@ -307,7 +319,9 @@ public class CommandConfig implements CommandExecutor {
* @param value The value given
* @return An integer, or null if it was invalid
*/
- private Integer getInteger(CommandSender commandSender, ConfigOption selectedOption, String value) {
+ @Nullable
+ private Integer getInteger(@NotNull CommandSender commandSender, @NotNull ConfigOption selectedOption,
+ @NotNull String value) {
try {
int intValue = Integer.parseInt(value);
@@ -331,7 +345,9 @@ public class CommandConfig implements CommandExecutor {
* @param value The value given
* @return A double, or null if it was invalid
*/
- private Double getDouble(CommandSender commandSender, ConfigOption selectedOption, String value) {
+ @Nullable
+ private Double getDouble(@NotNull CommandSender commandSender, @NotNull ConfigOption selectedOption,
+ @NotNull String value) {
try {
double doubleValue = Double.parseDouble(value);
@@ -353,7 +369,7 @@ public class CommandConfig implements CommandExecutor {
* @param commandSender The command sender initiating the reload
* @param configOption The changed config option
*/
- private void reloadIfNecessary(CommandSender commandSender, ConfigOption configOption) {
+ private void reloadIfNecessary(@NotNull CommandSender commandSender, @NotNull ConfigOption configOption) {
if (ConfigTag.requiresFullReload(configOption)) {
//Reload everything
Stargate.getStargateConfig().reload(commandSender);
@@ -391,7 +407,7 @@ public class CommandConfig implements CommandExecutor {
* @param sender The command sender that sent the command
* @param option The config option to print information about
*/
- private void printConfigOptionValue(CommandSender sender, ConfigOption option) {
+ private void printConfigOptionValue(@NotNull CommandSender sender, @NotNull ConfigOption option) {
Object value = Stargate.getStargateConfig().getConfigOptions().get(option);
sender.sendMessage(getOptionDescription(option));
sender.sendMessage(ChatColor.GREEN + "Current value: " + ChatColor.GOLD + value);
@@ -402,8 +418,8 @@ public class CommandConfig implements CommandExecutor {
*
* @param sender The command sender to display the config list to
*/
- private void displayConfigValues(CommandSender sender) {
- sender.sendMessage(ChatColor.GREEN + Stargate.getBackupString("prefix") + ChatColor.GOLD +
+ private void displayConfigValues(@NotNull CommandSender sender) {
+ sender.sendMessage(ChatColor.GREEN + Stargate.getBackupString(Message.PREFIX) + ChatColor.GOLD +
"Config values:");
for (ConfigOption option : ConfigOption.values()) {
sender.sendMessage(getOptionDescription(option));
@@ -416,7 +432,8 @@ public class CommandConfig implements CommandExecutor {
* @param option The option to describe
* @return A string describing the config option
*/
- private String getOptionDescription(ConfigOption option) {
+ @NotNull
+ private String getOptionDescription(@NotNull ConfigOption option) {
Object defaultValue = option.getDefaultValue();
String stringValue = String.valueOf(defaultValue);
if (option.getDataType() == OptionDataType.STRING_LIST) {
diff --git a/src/main/java/net/knarcraft/stargate/command/CommandReload.java b/src/main/java/net/knarcraft/stargate/command/CommandReload.java
index 6d29304..1bf6326 100644
--- a/src/main/java/net/knarcraft/stargate/command/CommandReload.java
+++ b/src/main/java/net/knarcraft/stargate/command/CommandReload.java
@@ -1,6 +1,7 @@
package net.knarcraft.stargate.command;
import net.knarcraft.stargate.Stargate;
+import net.knarcraft.stargate.config.SGFormatBuilder;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
@@ -17,7 +18,7 @@ public class CommandReload implements CommandExecutor {
@NotNull String[] args) {
if (commandSender instanceof Player player) {
if (!player.hasPermission("stargate.admin.reload")) {
- Stargate.getMessageSender().sendErrorMessage(commandSender, "Permission Denied");
+ new SGFormatBuilder("Permission Denied").error(commandSender);
return true;
}
}
diff --git a/src/main/java/net/knarcraft/stargate/command/CommandStarGate.java b/src/main/java/net/knarcraft/stargate/command/CommandStarGate.java
index 2185b54..5a67be4 100644
--- a/src/main/java/net/knarcraft/stargate/command/CommandStarGate.java
+++ b/src/main/java/net/knarcraft/stargate/command/CommandStarGate.java
@@ -1,10 +1,11 @@
package net.knarcraft.stargate.command;
-import net.knarcraft.stargate.Stargate;
import net.md_5.bungee.api.ChatColor;
+import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
+import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
@@ -16,6 +17,11 @@ import java.util.Arrays;
* the plugin itself, not commands for functions of the plugin.
*/
public class CommandStarGate implements CommandExecutor {
+ private final Plugin stargate;
+
+ public CommandStarGate(Plugin stargate) {
+ this.stargate = stargate;
+ }
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@@ -31,8 +37,8 @@ public class CommandStarGate implements CommandExecutor {
}
return false;
} else {
- commandSender.sendMessage(ChatColor.GOLD + "Stargate version " +
- ChatColor.GREEN + Stargate.getPluginVersion());
+ commandSender.sendMessage(ChatColor.GREEN + "Stargate version " + ChatColor.GOLD + stargate.getDescription().getVersion()
+ + ChatColor.GREEN + " running on " + ChatColor.GOLD + Bukkit.getServer().getVersion());
return true;
}
}
diff --git a/src/main/java/net/knarcraft/stargate/command/ConfigTabCompleter.java b/src/main/java/net/knarcraft/stargate/command/ConfigTabCompleter.java
index ff09aa9..c3784eb 100644
--- a/src/main/java/net/knarcraft/stargate/command/ConfigTabCompleter.java
+++ b/src/main/java/net/knarcraft/stargate/command/ConfigTabCompleter.java
@@ -61,25 +61,26 @@ public class ConfigTabCompleter implements TabCompleter {
* @param typedText The beginning of the typed text, for filtering matching results
* @return Some or all of the valid values for the option
*/
- private List getPossibleOptionValues(ConfigOption selectedOption, String typedText) {
+ @Nullable
+ private List getPossibleOptionValues(@NotNull ConfigOption selectedOption,
+ @NotNull String typedText) {
switch (selectedOption) {
- case LANGUAGE:
+ case LANGUAGE -> {
//Return available languages
return filterMatchingStartsWith(languages, typedText);
- case GATE_FOLDER:
- case PORTAL_FOLDER:
- case DEFAULT_GATE_NETWORK:
+ }
+ case GATE_FOLDER, PORTAL_FOLDER, DEFAULT_GATE_NETWORK -> {
//Just return the default value as most values should be possible
if (typedText.trim().isEmpty()) {
- return putStringInList((String) selectedOption.getDefaultValue());
+ return List.of((String) selectedOption.getDefaultValue());
} else {
return new ArrayList<>();
}
- case MAIN_SIGN_COLOR:
- case HIGHLIGHT_SIGN_COLOR:
- case FREE_GATES_COLOR:
+ }
+ case MAIN_SIGN_COLOR, HIGHLIGHT_SIGN_COLOR, FREE_GATES_COLOR -> {
//Return all colors
return filterMatchingStartsWith(chatColors, typedText);
+ }
}
//If the config value is a boolean, show the two boolean values
@@ -114,11 +115,13 @@ public class ConfigTabCompleter implements TabCompleter {
* @param args The arguments given by the user
* @return Some or all of the valid values for the option
*/
- private List getPossibleStringListOptionValues(ConfigOption selectedOption, String[] args) {
+ @NotNull
+ private List getPossibleStringListOptionValues(@NotNull ConfigOption selectedOption,
+ @NotNull String[] args) {
if (selectedOption == ConfigOption.PER_SIGN_COLORS) {
return getPerSignColorCompletion(args);
} else {
- return null;
+ return new ArrayList<>();
}
}
@@ -128,7 +131,8 @@ public class ConfigTabCompleter implements TabCompleter {
* @param args The arguments given by the user
* @return The options to give the user
*/
- private List getPerSignColorCompletion(String[] args) {
+ @NotNull
+ private List getPerSignColorCompletion(@NotNull String[] args) {
if (args.length < 3) {
return filterMatchingStartsWith(signTypes, args[1]);
} else if (args.length < 4) {
@@ -139,18 +143,6 @@ public class ConfigTabCompleter implements TabCompleter {
return new ArrayList<>();
}
- /**
- * Puts a single string value into a string list
- *
- * @param value The string to make into a list
- * @return A list containing the string value
- */
- private List putStringInList(String value) {
- List list = new ArrayList<>();
- list.add(value);
- return list;
- }
-
/**
* Initializes all lists of auto-completable values
*/
@@ -200,6 +192,7 @@ public class ConfigTabCompleter implements TabCompleter {
*
* @return The available chat colors
*/
+ @NotNull
private List getChatColors() {
List chatColors = new ArrayList<>();
char[] colors = new char[]{'a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
@@ -216,6 +209,7 @@ public class ConfigTabCompleter implements TabCompleter {
*/
private void initializeLanguages() {
languages = new ArrayList<>();
+ languages.add("cs");
languages.add("de");
languages.add("en");
languages.add("es");
@@ -223,12 +217,15 @@ public class ConfigTabCompleter implements TabCompleter {
languages.add("hu");
languages.add("it");
languages.add("ja");
- languages.add("nb-no");
+ languages.add("nb");
languages.add("nl");
- languages.add("nn-no");
- languages.add("pt-br");
+ languages.add("nn");
+ languages.add("pt");
languages.add("ru");
- languages.add("zh_cn");
+ languages.add("sv");
+ languages.add("tr");
+ languages.add("uk");
+ languages.add("zh");
//TODO: Generate this list dynamically by listing the language files in the jar and adding the user's custom
// language files
}
diff --git a/src/main/java/net/knarcraft/stargate/command/StarGateTabCompleter.java b/src/main/java/net/knarcraft/stargate/command/StarGateTabCompleter.java
index 96ecd3d..25c1d1d 100644
--- a/src/main/java/net/knarcraft/stargate/command/StarGateTabCompleter.java
+++ b/src/main/java/net/knarcraft/stargate/command/StarGateTabCompleter.java
@@ -17,8 +17,9 @@ import java.util.List;
public class StarGateTabCompleter implements TabCompleter {
@Override
- public @Nullable List onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command,
- @NotNull String s, @NotNull String[] args) {
+ @Nullable
+ public List onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
+ @NotNull String[] args) {
if (args.length == 1) {
List commands = getAvailableCommands(commandSender);
List matchingCommands = new ArrayList<>();
@@ -42,7 +43,8 @@ public class StarGateTabCompleter implements TabCompleter {
* @param commandSender The command sender to get available commands for
* @return The commands available to the command sender
*/
- private List getAvailableCommands(CommandSender commandSender) {
+ @NotNull
+ private List getAvailableCommands(@NotNull CommandSender commandSender) {
List commands = new ArrayList<>();
commands.add("about");
if (!(commandSender instanceof Player player) || player.hasPermission("stargate.admin.reload")) {
diff --git a/src/main/java/net/knarcraft/stargate/config/ConfigOption.java b/src/main/java/net/knarcraft/stargate/config/ConfigOption.java
index e12ea59..cdd8563 100644
--- a/src/main/java/net/knarcraft/stargate/config/ConfigOption.java
+++ b/src/main/java/net/knarcraft/stargate/config/ConfigOption.java
@@ -1,5 +1,8 @@
package net.knarcraft.stargate.config;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
/**
* A ConfigOption represents one of the available config options
*/
@@ -55,7 +58,8 @@ public enum ConfigOption {
*/
PER_SIGN_COLORS("gates.cosmetic.perSignColors", "The per-sign color specification", new String[]{
"'ACACIA:default,default'", "'BIRCH:default,default'", "'CRIMSON:inverted,inverted'", "'DARK_OAK:inverted,inverted'",
- "'JUNGLE:default,default'", "'OAK:default,default'", "'SPRUCE:inverted,inverted'", "'WARPED:inverted,inverted'"}),
+ "'JUNGLE:default,default'", "'OAK:default,default'", "'SPRUCE:inverted,inverted'", "'WARPED:inverted,inverted'",
+ "'BAMBOO:default,default'", "'CHERRY:default,default'"}),
/**
* Whether to destroy portals when any blocks are broken by explosions
@@ -150,6 +154,11 @@ public enum ConfigOption {
CHARGE_FREE_DESTINATION("economy.chargeFreeDestination",
"Whether to require payment if the destination is free, but the entrance stargate is not", true),
+ /**
+ * The account to transfer all paid fees to
+ */
+ TAX_ACCOUNT("economy.taxAccount", "The UUID of the account all fees are paid to (except for money to the Stargate owner)", ""),
+
/**
* Whether to mark free gates with a different color
*/
@@ -189,7 +198,14 @@ public enum ConfigOption {
* Whether to hide Dynmap icons by default
*/
DYNMAP_ICONS_DEFAULT_HIDDEN("dynmap.dynmapIconsHiddenByDefault",
- "Whether to hide Stargate's Dynmap icons by default, requiring the user to enable them.", true);
+ "Whether to hide Stargate's Dynmap icons by default, requiring the user to enable them.", true),
+
+ /**
+ * The amount of ticks to wait when processing the Stargate control update queue
+ */
+ CONTROL_UPDATE_QUEUE_DELAY("gates.integrity.controlUpdateDelay",
+ "The delay between each time a Stargate's controls are updated after startup", 3),
+ ;
private final String configNode;
private final String description;
@@ -203,7 +219,7 @@ public enum ConfigOption {
* @param description The description of what this config option does
* @param defaultValue The default value of this config option
*/
- ConfigOption(String configNode, String description, Object defaultValue) {
+ ConfigOption(@NotNull String configNode, @NotNull String description, @NotNull Object defaultValue) {
this.configNode = configNode;
this.description = description;
this.defaultValue = defaultValue;
@@ -229,7 +245,7 @@ public enum ConfigOption {
* @param name The name of the config option to get
* @return The corresponding config option, or null if the name is invalid
*/
- public static ConfigOption getByName(String name) {
+ public static @Nullable ConfigOption getByName(@NotNull String name) {
for (ConfigOption option : ConfigOption.values()) {
if (option.getName().equalsIgnoreCase(name)) {
return option;
@@ -243,7 +259,7 @@ public enum ConfigOption {
*
* @return The name of this config option
*/
- public String getName() {
+ public @NotNull String getName() {
if (!this.configNode.contains(".")) {
return this.configNode;
}
@@ -256,7 +272,7 @@ public enum ConfigOption {
*
* @return The data type used
*/
- public OptionDataType getDataType() {
+ public @NotNull OptionDataType getDataType() {
return this.dataType;
}
@@ -265,7 +281,7 @@ public enum ConfigOption {
*
* @return This config option's config node
*/
- public String getConfigNode() {
+ public @NotNull String getConfigNode() {
return this.configNode;
}
@@ -274,7 +290,7 @@ public enum ConfigOption {
*
* @return The description of this config option
*/
- public String getDescription() {
+ public @NotNull String getDescription() {
return this.description;
}
@@ -283,7 +299,7 @@ public enum ConfigOption {
*
* @return This config option's default value
*/
- public Object getDefaultValue() {
+ public @NotNull Object getDefaultValue() {
return this.defaultValue;
}
diff --git a/src/main/java/net/knarcraft/stargate/config/ConfigTag.java b/src/main/java/net/knarcraft/stargate/config/ConfigTag.java
index 024b205..a992d46 100644
--- a/src/main/java/net/knarcraft/stargate/config/ConfigTag.java
+++ b/src/main/java/net/knarcraft/stargate/config/ConfigTag.java
@@ -1,25 +1,38 @@
package net.knarcraft.stargate.config;
-import java.util.Arrays;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
/**
* A config tag groups config values by a property
*/
public enum ConfigTag {
- COLOR(new ConfigOption[]{ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR,
- ConfigOption.HIGHLIGHT_SIGN_COLOR, ConfigOption.PER_SIGN_COLORS}),
- FOLDER(new ConfigOption[]{ConfigOption.GATE_FOLDER, ConfigOption.PORTAL_FOLDER}),
- DYNMAP(new ConfigOption[]{ConfigOption.ENABLE_DYNMAP, ConfigOption.DYNMAP_ICONS_DEFAULT_HIDDEN});
+ /**
+ * Color-related configuration options
+ */
+ COLOR(Set.of(ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR, ConfigOption.HIGHLIGHT_SIGN_COLOR,
+ ConfigOption.PER_SIGN_COLORS)),
- private final ConfigOption[] taggedOptions;
+ /**
+ * Folder-altering configuration options
+ */
+ FOLDER(Set.of(ConfigOption.GATE_FOLDER, ConfigOption.PORTAL_FOLDER)),
+
+ /**
+ * Dynmap-related configuration options
+ */
+ DYNMAP(Set.of(ConfigOption.ENABLE_DYNMAP, ConfigOption.DYNMAP_ICONS_DEFAULT_HIDDEN));
+
+ private final Set taggedOptions;
/**
* Instantiates a new config tag
*
* @param taggedOptions The config options included in this tag
*/
- ConfigTag(ConfigOption[] taggedOptions) {
+ ConfigTag(@NotNull Set taggedOptions) {
this.taggedOptions = taggedOptions;
}
@@ -29,8 +42,8 @@ public enum ConfigTag {
* @param option The config option to check
* @return True of the config option is tagged
*/
- public boolean isTagged(ConfigOption option) {
- return Arrays.stream(taggedOptions).anyMatch((item) -> item == option);
+ public boolean isTagged(@NotNull ConfigOption option) {
+ return taggedOptions.contains(option);
}
/**
@@ -39,7 +52,7 @@ public enum ConfigTag {
* @param configOption The config option to check
* @return True if changing the config option requires a "reload of colors" to take effect
*/
- public static boolean requiresColorReload(ConfigOption configOption) {
+ public static boolean requiresColorReload(@NotNull ConfigOption configOption) {
return (COLOR.isTagged(configOption) && configOption != ConfigOption.FREE_GATES_COLOR);
}
@@ -49,7 +62,7 @@ public enum ConfigTag {
* @param option The config option to check
* @return True if changing the config option requires a full reload to take effect
*/
- public static boolean requiresFullReload(ConfigOption option) {
+ public static boolean requiresFullReload(@NotNull ConfigOption option) {
return FOLDER.isTagged(option);
}
@@ -59,7 +72,7 @@ public enum ConfigTag {
* @param configOption The config option to check
* @return True if changing the config option requires a reload of all dynmap markers
*/
- public static boolean requiresDynmapReload(ConfigOption configOption) {
+ public static boolean requiresDynmapReload(@NotNull ConfigOption configOption) {
return DYNMAP.isTagged(configOption);
}
@@ -69,7 +82,7 @@ public enum ConfigTag {
* @param option The config option to check
* @return True if changing the config option requires a portal reload to take effect
*/
- public static boolean requiresPortalReload(ConfigOption option) {
+ public static boolean requiresPortalReload(@NotNull ConfigOption option) {
return COLOR.isTagged(option) || FOLDER.isTagged(option) || option == ConfigOption.VERIFY_PORTALS;
}
@@ -79,7 +92,7 @@ public enum ConfigTag {
* @param option The config option to check
* @return True if the language loader requires a reload
*/
- public static boolean requiresLanguageReload(ConfigOption option) {
+ public static boolean requiresLanguageReload(@NotNull ConfigOption option) {
return option == ConfigOption.LANGUAGE;
}
@@ -89,7 +102,7 @@ public enum ConfigTag {
* @param option The config option to check
* @return True if economy requires a reload
*/
- public static boolean requiresEconomyReload(ConfigOption option) {
+ public static boolean requiresEconomyReload(@NotNull ConfigOption option) {
return option == ConfigOption.USE_ECONOMY;
}
diff --git a/src/main/java/net/knarcraft/stargate/config/DynmapManager.java b/src/main/java/net/knarcraft/stargate/config/DynmapManager.java
index 5eaa0c9..8283e5a 100644
--- a/src/main/java/net/knarcraft/stargate/config/DynmapManager.java
+++ b/src/main/java/net/knarcraft/stargate/config/DynmapManager.java
@@ -1,6 +1,7 @@
package net.knarcraft.stargate.config;
import net.knarcraft.stargate.Stargate;
+import net.knarcraft.stargate.container.RelativeBlockVector;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalRegistry;
import org.bukkit.Location;
@@ -10,6 +11,8 @@ import org.dynmap.markers.GenericMarker;
import org.dynmap.markers.Marker;
import org.dynmap.markers.MarkerIcon;
import org.dynmap.markers.MarkerSet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* A manager for dealing with everything Dynmap
@@ -27,9 +30,10 @@ public final class DynmapManager {
* Initializes the dynmap manager
*
* @param dynmapAPI A reference
+ * @throws NullPointerException If dynmap has an invalid state
*/
- public static void initialize(DynmapAPI dynmapAPI) {
- if (dynmapAPI == null || dynmapAPI.getMarkerAPI() == null) {
+ public static void initialize(@Nullable DynmapAPI dynmapAPI) throws NullPointerException {
+ if (dynmapAPI == null || !dynmapAPI.markerAPIInitialized() || dynmapAPI.getMarkerAPI() == null) {
markerSet = null;
portalIcon = null;
} else {
@@ -66,7 +70,7 @@ public final class DynmapManager {
*
* @param portal The portal to add a marker for
*/
- public static void addPortalMarker(Portal portal) {
+ public static void addPortalMarker(@NotNull Portal portal) {
if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
return;
}
@@ -75,8 +79,22 @@ public final class DynmapManager {
return;
}
- Location location = portal.getBlockAt(portal.getGate().getLayout().getExit());
- Marker marker = markerSet.createMarker(getPortalMarkerId(portal), portal.getName(), world.getName(),
+ Location location;
+ @Nullable RelativeBlockVector exit = portal.getGate().getLayout().getExit();
+ if (exit == null) {
+ location = portal.getTopLeft();
+ } else {
+ location = portal.getBlockAt(exit);
+ }
+
+ String markerId = getPortalMarkerId(portal);
+ if (markerSet.findMarker(markerId) != null) {
+ Stargate.debug("DynmapManager::addPortalMarker", "Skipped marker creation, as the portal " +
+ "marker " + markerId + " already exists");
+ return;
+ }
+
+ Marker marker = markerSet.createMarker(markerId, portal.getName(), world.getName(),
location.getX(), location.getY(), location.getZ(), portalIcon, false);
if (marker == null) {
Stargate.logWarning(String.format(
@@ -86,7 +104,7 @@ public final class DynmapManager {
Portal name: %s
Portal world: %s
Portal location: %s,%s,%s""",
- getPortalMarkerId(portal), portal.getName(), world.getName(), location.getX(), location.getY(),
+ markerId, portal.getName(), world.getName(), location.getX(), location.getY(),
location.getZ()));
return;
}
@@ -111,7 +129,7 @@ public final class DynmapManager {
*
* @param portal The portal to remove the marker for
*/
- public static void removePortalMarker(Portal portal) {
+ public static void removePortalMarker(@NotNull Portal portal) {
if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
return;
}
@@ -121,13 +139,21 @@ public final class DynmapManager {
}
}
+ /**
+ * Disables Dynmap integration
+ */
+ public static void disable() {
+ markerSet = null;
+ portalIcon = null;
+ }
+
/**
* Gets the id used for the given portal's marker
*
* @param portal The portal to get a marker id for
* @return
*/
- private static String getPortalMarkerId(Portal portal) {
+ private static String getPortalMarkerId(@NotNull Portal portal) {
return portal.getNetwork() + "-:-" + portal.getName();
}
diff --git a/src/main/java/net/knarcraft/stargate/config/EconomyConfig.java b/src/main/java/net/knarcraft/stargate/config/EconomyConfig.java
index 1b8400c..165cf51 100644
--- a/src/main/java/net/knarcraft/stargate/config/EconomyConfig.java
+++ b/src/main/java/net/knarcraft/stargate/config/EconomyConfig.java
@@ -11,6 +11,8 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicesManager;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.Map;
@@ -29,7 +31,7 @@ public final class EconomyConfig {
*
* @param configOptions The loaded config options to read
*/
- public EconomyConfig(Map configOptions) {
+ public EconomyConfig(@NotNull Map configOptions) {
this.configOptions = configOptions;
try {
String freeColor = (String) configOptions.get(ConfigOption.FREE_GATES_COLOR);
@@ -62,6 +64,7 @@ public final class EconomyConfig {
*
* @return An economy object, or null if economy is disabled or not initialized
*/
+ @Nullable
public Economy getEconomy() {
return economy;
}
@@ -71,6 +74,7 @@ public final class EconomyConfig {
*
* @return An instance of the Vault plugin, or null if Vault is not loaded
*/
+ @Nullable
public Plugin getVault() {
return vault;
}
@@ -132,6 +136,16 @@ public final class EconomyConfig {
return (Integer) configOptions.get(ConfigOption.DESTROY_COST);
}
+ /**
+ * Gets the account all taxes are paid to
+ *
+ * @return The account all taxes are paid to
+ */
+ @Nullable
+ public String getTaxAccount() {
+ return (String) configOptions.get(ConfigOption.TAX_ACCOUNT);
+ }
+
/**
* Checks whether the given player can afford the given fee
*
@@ -149,6 +163,7 @@ public final class EconomyConfig {
* @param amount The amount to display
* @return A formatted text string describing the amount
*/
+ @NotNull
public String format(int amount) {
if (isEconomyEnabled()) {
return economy.format(amount);
@@ -163,7 +178,7 @@ public final class EconomyConfig {
* @param pluginManager The plugin manager to get plugins from
* @return True if economy was enabled
*/
- public boolean setupEconomy(PluginManager pluginManager) {
+ public boolean setupEconomy(@NotNull PluginManager pluginManager) {
if (!isEconomyEnabled()) {
return false;
}
@@ -177,10 +192,10 @@ public final class EconomyConfig {
this.vault = vault;
return true;
} else {
- Stargate.logInfo(Stargate.getString("ecoLoadError"));
+ Stargate.logInfo(new SGFormatBuilder(Message.ECONOMY_LOAD_ERROR).toString());
}
} else {
- Stargate.logInfo(Stargate.getString("vaultLoadError"));
+ Stargate.logInfo(new SGFormatBuilder(Message.VAULT_LOAD_ERROR).toString());
}
configOptions.put(ConfigOption.USE_ECONOMY, false);
return false;
@@ -202,7 +217,7 @@ public final class EconomyConfig {
* @param gate The gate type used
* @return The cost of creating the gate
*/
- public int getCreateCost(Player player, Gate gate) {
+ public int getCreateCost(@NotNull Player player, @NotNull Gate gate) {
if (isFree(player, "create")) {
return 0;
} else {
@@ -217,7 +232,7 @@ public final class EconomyConfig {
* @param gate The gate type used
* @return The cost of destroying the gate
*/
- public int getDestroyCost(Player player, Gate gate) {
+ public int getDestroyCost(@NotNull Player player, @NotNull Gate gate) {
if (isFree(player, "destroy")) {
return 0;
} else {
@@ -232,7 +247,7 @@ public final class EconomyConfig {
* @param permissionNode The free.permissionNode necessary to allow free gate {action}
* @return
*/
- private boolean isFree(Player player, String permissionNode) {
+ private boolean isFree(@NotNull Player player, @NotNull String permissionNode) {
return !useEconomy() || PermissionHelper.hasPermission(player, "stargate.free." + permissionNode);
}
diff --git a/src/main/java/net/knarcraft/stargate/config/LanguageLoader.java b/src/main/java/net/knarcraft/stargate/config/LanguageLoader.java
index 0383794..f36b5c6 100644
--- a/src/main/java/net/knarcraft/stargate/config/LanguageLoader.java
+++ b/src/main/java/net/knarcraft/stargate/config/LanguageLoader.java
@@ -3,15 +3,16 @@ package net.knarcraft.stargate.config;
import net.knarcraft.knarlib.property.ColorConversion;
import net.knarcraft.knarlib.util.FileHelper;
import net.knarcraft.stargate.Stargate;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-import java.util.HashMap;
+import java.util.EnumMap;
import java.util.Map;
-import java.util.Set;
/**
* This class is responsible for loading all strings which are translated into several languages
@@ -19,9 +20,9 @@ import java.util.Set;
public final class LanguageLoader {
private final String languageFolder;
- private final Map loadedBackupStrings;
+ private final Map loadedBackupStrings;
private String chosenLanguage;
- private Map loadedStringTranslations;
+ private Map loadedStringTranslations;
/**
* Instantiates a new language loader
@@ -30,7 +31,7 @@ public final class LanguageLoader {
*
* @param languageFolder The folder containing the language files
*/
- public LanguageLoader(String languageFolder) {
+ public LanguageLoader(@NotNull String languageFolder) {
this.languageFolder = languageFolder;
File testFile = new File(languageFolder, "en.txt");
if (!testFile.exists()) {
@@ -45,7 +46,7 @@ public final class LanguageLoader {
loadedBackupStrings = load("en", inputStream);
} else {
loadedBackupStrings = null;
- Stargate.getConsoleLogger().severe("[stargate] Error loading backup language. " +
+ Stargate.logSevere("Error loading backup language. " +
"There may be missing text in-game");
}
}
@@ -60,32 +61,34 @@ public final class LanguageLoader {
}
/**
- * Gets the string to display given its name/key
+ * Gets the string to display given its message key
*
- * @param name The name/key of the string to display
- * @return The string in the user's preferred language
+ * @param message The message to display
+ * @return The message in the user's preferred language
*/
- public String getString(String name) {
+ @NotNull
+ public String getString(@NotNull Message message) {
String value = null;
if (loadedStringTranslations != null) {
- value = loadedStringTranslations.get(name);
+ value = loadedStringTranslations.get(message);
}
if (value == null) {
- value = getBackupString(name);
+ value = getBackupString(message);
}
return value;
}
/**
- * Gets the string to display given its name/key
+ * Gets the string to display given its message key
*
- * @param name The name/key of the string to display
+ * @param message The message to display
* @return The string in the backup language (English)
*/
- public String getBackupString(String name) {
+ @NotNull
+ public String getBackupString(@NotNull Message message) {
String value = null;
if (loadedBackupStrings != null) {
- value = loadedBackupStrings.get(name);
+ value = loadedBackupStrings.get(message);
}
if (value == null) {
return "";
@@ -98,7 +101,7 @@ public final class LanguageLoader {
*
* @param chosenLanguage The new plugin language
*/
- public void setChosenLanguage(String chosenLanguage) {
+ public void setChosenLanguage(@NotNull String chosenLanguage) {
this.chosenLanguage = chosenLanguage;
}
@@ -107,21 +110,21 @@ public final class LanguageLoader {
*
* @param language The language to update
*/
- private void updateLanguage(String language) {
- Map currentLanguageValues = load(language);
+ private void updateLanguage(@NotNull String language) {
+ Map currentLanguageValues = load(language);
- InputStream inputStream = getClass().getResourceAsStream("/lang/" + language + ".txt");
+ InputStream inputStream = FileHelper.getInputStreamForInternalFile("/lang/" + language + ".txt");
if (inputStream == null) {
- Stargate.logInfo(String.format("The language %s is not available. Falling back to english, You can add a " +
- "custom language by creating a new text file in the lang directory.", language));
+ Stargate.logInfo(String.format("Unable to find internal language file for %s. This will normally not " +
+ "cause any problems, except newly added translatable strings won't be automatically added", language));
Stargate.debug("LanguageLoader::updateLanguage", String.format("Unable to load /lang/%s.txt", language));
return;
}
try {
readChangedLanguageStrings(inputStream, language, currentLanguageValues);
- } catch (IOException ex) {
- ex.printStackTrace();
+ } catch (IOException exception) {
+ Stargate.logSevere("Unable to read language strings! Message: " + exception.getMessage());
}
}
@@ -133,12 +136,12 @@ public final class LanguageLoader {
* @param currentLanguageValues The current values of the loaded/processed language
* @throws IOException if unable to read a language file
*/
- private void readChangedLanguageStrings(InputStream inputStream, String language, Map currentLanguageValues) throws IOException {
+ private void readChangedLanguageStrings(@NotNull InputStream inputStream, @NotNull String language,
+ @Nullable Map currentLanguageValues) throws IOException {
//Get language values
BufferedReader bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream);
- Map internalLanguageValues = FileHelper.readKeyValuePairs(bufferedReader, "=",
- ColorConversion.NORMAL);
+ Map internalLanguageValues = fromStringMap(FileHelper.readKeyValuePairs(bufferedReader,
+ "=", ColorConversion.NORMAL));
//If currentLanguageValues is null; the chosen language has not been used before
if (currentLanguageValues == null) {
@@ -149,11 +152,14 @@ public final class LanguageLoader {
//If a key is not found in the language file, add the one in the internal file. Must update the external file
if (!internalLanguageValues.keySet().equals(currentLanguageValues.keySet())) {
- Map newLanguageValues = new HashMap<>();
+ Map newLanguageValues = new EnumMap<>(Message.class);
boolean updateNecessary = false;
- for (String key : internalLanguageValues.keySet()) {
+ for (Map.Entry entry : internalLanguageValues.entrySet()) {
+ Message key = entry.getKey();
+ String value = entry.getValue();
+
if (currentLanguageValues.get(key) == null) {
- newLanguageValues.put(key, internalLanguageValues.get(key));
+ newLanguageValues.put(key, value);
//Found at least one value in the internal file not in the external file. Need to update
updateNecessary = true;
} else {
@@ -177,20 +183,20 @@ public final class LanguageLoader {
* @param customLanguageStrings Any custom language strings not recognized
* @throws IOException If unable to write to the language file
*/
- private void updateLanguageFile(String language, Map languageStrings,
- Map customLanguageStrings) throws IOException {
+ private void updateLanguageFile(@NotNull String language, @NotNull Map languageStrings,
+ @Nullable Map customLanguageStrings) throws IOException {
BufferedWriter bufferedWriter = FileHelper.getBufferedWriterFromString(languageFolder + language + ".txt");
//Output normal Language data
- for (String key : languageStrings.keySet()) {
- bufferedWriter.write(key + "=" + languageStrings.get(key));
+ for (Map.Entry entry : languageStrings.entrySet()) {
+ bufferedWriter.write(entry.getKey() + "=" + entry.getValue());
bufferedWriter.newLine();
}
bufferedWriter.newLine();
//Output any custom language strings the user had
if (customLanguageStrings != null) {
- for (String key : customLanguageStrings.keySet()) {
- bufferedWriter.write(key + "=" + customLanguageStrings.get(key));
+ for (Map.Entry entry : customLanguageStrings.entrySet()) {
+ bufferedWriter.write(entry.getKey() + "=" + entry.getValue());
bufferedWriter.newLine();
}
}
@@ -203,7 +209,8 @@ public final class LanguageLoader {
* @param lang The language to load
* @return A mapping between loaded string indexes and the strings to display
*/
- private Map load(String lang) {
+ @Nullable
+ private Map load(@NotNull String lang) {
return load(lang, null);
}
@@ -214,8 +221,8 @@ public final class LanguageLoader {
* @param inputStream An optional input stream to use. Defaults to using a file input stream
* @return A mapping between loaded string indexes and the strings to display
*/
- private Map load(String lang, InputStream inputStream) {
- Map strings;
+ @Nullable
+ private Map load(@NotNull String lang, @Nullable InputStream inputStream) {
BufferedReader bufferedReader;
try {
if (inputStream == null) {
@@ -223,14 +230,13 @@ public final class LanguageLoader {
} else {
bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream);
}
- strings = FileHelper.readKeyValuePairs(bufferedReader, "=", ColorConversion.NORMAL);
- } catch (Exception e) {
+ return fromStringMap(FileHelper.readKeyValuePairs(bufferedReader, "=", ColorConversion.NORMAL));
+ } catch (Exception exception) {
if (Stargate.getStargateConfig().isDebuggingEnabled()) {
- Stargate.getConsoleLogger().info("[Stargate] Unable to load language " + lang);
+ Stargate.logInfo("Unable to load language " + lang);
}
return null;
}
- return strings;
}
/**
@@ -238,20 +244,41 @@ public final class LanguageLoader {
*/
public void debug() {
if (loadedStringTranslations != null) {
- Set keys = loadedStringTranslations.keySet();
- for (String key : keys) {
- Stargate.debug("LanguageLoader::Debug::loadedStringTranslations", key + " => " +
- loadedStringTranslations.get(key));
+ for (Map.Entry entry : loadedStringTranslations.entrySet()) {
+ Stargate.debug("LanguageLoader::Debug::loadedStringTranslations", entry.getKey() +
+ " => " + entry.getValue());
}
}
if (loadedBackupStrings == null) {
return;
}
- Set keys = loadedBackupStrings.keySet();
- for (String key : keys) {
- Stargate.debug("LanguageLoader::Debug::loadedBackupStrings", key + " => " +
- loadedBackupStrings.get(key));
+
+ for (Map.Entry entry : loadedBackupStrings.entrySet()) {
+ Stargate.debug("LanguageLoader::Debug::loadedBackupStrings", entry.getKey() + " => " +
+ entry.getValue());
}
}
+ /**
+ * Converts a map from string key to message into a map from message key to message
+ *
+ * @param configurationStrings The map to convert
+ * @return The converted map
+ */
+ @NotNull
+ private Map fromStringMap(@NotNull Map configurationStrings) {
+ Map output = new EnumMap<>(Message.class);
+ for (Map.Entry entry : configurationStrings.entrySet()) {
+ Message message = Message.getFromKey(entry.getKey());
+ if (message == null) {
+ Stargate.logWarning("Found unrecognized language key " + entry.getKey());
+ continue;
+ }
+
+ output.put(message, entry.getValue());
+ }
+
+ return output;
+ }
+
}
diff --git a/src/main/java/net/knarcraft/stargate/config/Message.java b/src/main/java/net/knarcraft/stargate/config/Message.java
new file mode 100644
index 0000000..312f5ad
--- /dev/null
+++ b/src/main/java/net/knarcraft/stargate/config/Message.java
@@ -0,0 +1,251 @@
+package net.knarcraft.stargate.config;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Translated messages displayed to players
+ */
+public enum Message {
+
+ /**
+ * The prefix displayed in front of all messages shown in the chat
+ */
+ PREFIX("prefix"),
+
+ /**
+ * The message displayed when a player is teleported
+ */
+ TELEPORTED("teleportMsg"),
+
+ /**
+ * The message displayed when a player destroys a Stargate
+ */
+ DESTROYED("destroyMsg"),
+
+ /**
+ * The message displayed when the currently selected Stargate destination is invalid
+ */
+ INVALID_DESTINATION("invalidMsg"),
+
+ /**
+ * The message displayed when the destination portal is busy with another player
+ */
+ DESTINATION_BLOCKED("blockMsg"),
+
+ /**
+ * The message displayed when the Stargate has no destinations available to the player
+ */
+ NO_DESTINATION("destEmpty"),
+
+ /**
+ * The message displayed when a player is denied access to any action
+ */
+ ACCESS_DENIED("denyMsg"),
+
+ /**
+ * The message displayed when the plugin is reloaded
+ */
+ RELOADED("reloaded"),
+
+ /**
+ * The message displayed when a player has some currency deducted from their account
+ */
+ ECONOMY_DEDUCTED("ecoDeduct"),
+
+ /**
+ * The message displayed when a player has some currency refunded to their account
+ */
+ ECONOMY_REFUNDED("ecoRefund"),
+
+ /**
+ * The message displayed when a player obtains some currency to their account (from portal usage)
+ */
+ ECONOMY_OBTAINED("ecoObtain"),
+
+ /**
+ * The message displayed when the player has an insufficient amount of currency to perform an action
+ */
+ ECONOMY_INSUFFICIENT("ecoInFunds"),
+
+ /**
+ * The message displayed when economy fails to load
+ */
+ ECONOMY_LOAD_ERROR("ecoLoadError"),
+
+ /**
+ * The message displayed when Vault fails to load
+ */
+ VAULT_LOAD_ERROR("vaultLoadError"),
+
+ /**
+ * The message displayed when Vault successfully loads
+ */
+ VAULT_LOADED("vaultLoaded"),
+
+ /**
+ * The message displayed when a Stargate is successfully created
+ */
+ CREATED("createMsg"),
+
+ /**
+ * The message displayed when a player is denied from creating a Stargate on the selected network
+ */
+ CREATION_NETWORK_DENIED("createNetDeny"),
+
+ /**
+ * The message displayed when a player is denied from creating a Stargate of the given gate type
+ */
+ CREATION_GATE_DENIED("createGateDeny"),
+
+ /**
+ * The message displayed when a Stargate is created on the player's personal network
+ */
+ CREATION_PERSONAL("createPersonal"),
+
+ /**
+ * The message displayed when the name of a Stargate is too short or too long
+ */
+ CREATION_NAME_LENGTH("createNameLength"),
+
+ /**
+ * The message displayed when another Stargate on the network has the same name as the new Stargate
+ */
+ CREATION_NAME_COLLISION("createExists"),
+
+ /**
+ * The message displayed when the specified network is full
+ */
+ CREATION_NETWORK_FULL("createFull"),
+
+ /**
+ * The message displayed when a player is denied from creating a Stargate in the current world
+ */
+ CREATION_WORLD_DENIED("createWorldDeny"),
+
+ /**
+ * The message displayed when a gate is physically conflicting with another
+ */
+ CREATION_CONFLICT("createConflict"),
+
+ /**
+ * The right-click prompt displayed on Stargate signs
+ */
+ SIGN_RIGHT_CLICK("signRightClick"),
+
+ /**
+ * The to use prompt displayed on Stargate signs
+ */
+ SIGN_TO_USE("signToUse"),
+
+ /**
+ * The random string displayed on Stargate signs
+ */
+ SIGN_RANDOM("signRandom"),
+
+ /**
+ * The disconnected string displayed on Stargate signs
+ */
+ SIGN_DISCONNECTED("signDisconnected"),
+
+ /**
+ * The invalid gate string displayed on Stargate signs
+ */
+ SIGN_INVALID("signInvalidGate"),
+
+ /**
+ * The message displayed if trying to create a bungee gate when bungee is disabled
+ */
+ BUNGEE_DISABLED("bungeeDisabled"),
+
+ /**
+ * The message displayed when a player is denied from creating a bungee Stargate
+ */
+ BUNGEE_CREATION_DENIED("bungeeDeny"),
+
+ /**
+ * The message displayed if a Stargate is missing the destination, the network or both
+ */
+ BUNGEE_MISSING_INFO("bungeeEmpty"),
+
+ /**
+ * The teleportation prompt shown on bungee signs
+ */
+ BUNGEE_SIGN("bungeeSign"),
+
+ /**
+ * The format of the title of the portal info shown in chat
+ */
+ PORTAL_INFO_TITLE("portalInfoTitle"),
+
+ /**
+ * The format of the name of the portal info shown in chat
+ */
+ PORTAL_INFO_NAME("portalInfoName"),
+
+ /**
+ * The format of the destination of the portal info shown in chat
+ */
+ PORTAL_INFO_DESTINATION("portalInfoDestination"),
+
+ /**
+ * The format of the network of the portal info shown in chat
+ */
+ PORTAL_INFO_NETWORK("portalInfoNetwork"),
+
+ /**
+ * The format of the server of the portal info shown in chat
+ */
+ PORTAL_INFO_SERVER("portalInfoServer"),
+
+ /**
+ * The author that created the loaded translation
+ */
+ AUTHOR("author"),
+ ;
+
+ private final String key;
+
+ /**
+ * Instantiates a new message
+ *
+ * @param key The key of the message in the language files
+ */
+ Message(@NotNull String key) {
+ this.key = key;
+ }
+
+ /**
+ * Gets the language file key for this message
+ *
+ * @return This message's key
+ */
+ @NotNull
+ public String getKey() {
+ return this.key;
+ }
+
+ /**
+ * Gets the message corresponding to the given key
+ *
+ * @param key The key to get a message from
+ * @return The message, or null if not found
+ */
+ @Nullable
+ public static Message getFromKey(@NotNull String key) {
+ for (Message message : Message.values()) {
+ if (message.getKey().equalsIgnoreCase(key)) {
+ return message;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ @NotNull
+ public String toString() {
+ return this.getKey();
+ }
+
+}
diff --git a/src/main/java/net/knarcraft/stargate/config/MessageSender.java b/src/main/java/net/knarcraft/stargate/config/MessageSender.java
deleted file mode 100644
index bfc706a..0000000
--- a/src/main/java/net/knarcraft/stargate/config/MessageSender.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package net.knarcraft.stargate.config;
-
-import net.md_5.bungee.api.ChatColor;
-import org.bukkit.command.CommandSender;
-
-/**
- * The message sender is responsible sending messages to players with correct coloring and formatting
- */
-public final class MessageSender {
-
- private final LanguageLoader languageLoader;
-
- /**
- * Instantiates a new message sender
- *
- * @param languageLoader The language loader to get translated strings from
- */
- public MessageSender(LanguageLoader languageLoader) {
- this.languageLoader = languageLoader;
- }
-
- /**
- * Sends an error message to a player
- *
- * @param player The player to send the message to
- * @param message The message to send
- */
- public void sendErrorMessage(CommandSender player, String message) {
- sendMessage(player, message, true);
- }
-
- /**
- * Sends a success message to a player
- *
- * @param player The player to send the message to
- * @param message The message to send
- */
- public void sendSuccessMessage(CommandSender player, String message) {
- sendMessage(player, message, false);
- }
-
- /**
- * Sends a message to a player
- *
- * @param sender The player to send the message to
- * @param message The message to send
- * @param error Whether the message sent is an error
- */
- private void sendMessage(CommandSender sender, String message, boolean error) {
- if (message.isEmpty()) {
- return;
- }
- message = ChatColor.translateAlternateColorCodes('&', message);
- if (error) {
- sender.sendMessage(ChatColor.RED + languageLoader.getString("prefix") + ChatColor.WHITE + message);
- } else {
- sender.sendMessage(ChatColor.GREEN + languageLoader.getString("prefix") + ChatColor.WHITE + message);
- }
- }
-
-}
diff --git a/src/main/java/net/knarcraft/stargate/config/SGFormatBuilder.java b/src/main/java/net/knarcraft/stargate/config/SGFormatBuilder.java
new file mode 100644
index 0000000..23b83fb
--- /dev/null
+++ b/src/main/java/net/knarcraft/stargate/config/SGFormatBuilder.java
@@ -0,0 +1,40 @@
+package net.knarcraft.stargate.config;
+
+import net.knarcraft.knarlib.formatting.FormatBuilder;
+import net.knarcraft.stargate.Stargate;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A customized format builder for automatic translation of Stargate messages
+ */
+public class SGFormatBuilder extends FormatBuilder {
+
+ /**
+ * Instantiates a new format builder
+ */
+ public SGFormatBuilder() {
+ super();
+ }
+
+ /**
+ * Instantiates a new format builder
+ *
+ * If the input is a list, it will be joined using the default delimiter: ",".
+ *
+ * @param input The input to use as the initial string of this format builder
+ * @throws IllegalStateException If the string formatter has not been set, and the input is a translatable message
+ */
+ public SGFormatBuilder(@NotNull K input) throws IllegalStateException {
+ super(input);
+ }
+
+ @Override
+ @NotNull
+ protected String asString(@NotNull K input, @NotNull String delimiter) {
+ if (input instanceof Message message) {
+ return Stargate.getStargateConfig().getLanguageLoader().getString(message);
+ }
+ return super.asString(input, delimiter);
+ }
+
+}
diff --git a/src/main/java/net/knarcraft/stargate/config/StargateConfig.java b/src/main/java/net/knarcraft/stargate/config/StargateConfig.java
index f03b852..afb81ff 100644
--- a/src/main/java/net/knarcraft/stargate/config/StargateConfig.java
+++ b/src/main/java/net/knarcraft/stargate/config/StargateConfig.java
@@ -1,7 +1,9 @@
package net.knarcraft.stargate.config;
+import net.knarcraft.knarlib.formatting.StringFormatter;
+import net.knarcraft.knarlib.formatting.Translator;
import net.knarcraft.knarlib.property.ColorConversion;
-import net.knarcraft.knarlib.util.FileHelper;
+import net.knarcraft.knarlib.util.ConfigHelper;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.container.BlockChangeRequest;
import net.knarcraft.stargate.listener.BungeeCordListener;
@@ -17,9 +19,9 @@ import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.messaging.Messenger;
import org.dynmap.DynmapAPI;
+import org.jetbrains.annotations.NotNull;
import java.io.File;
-import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -27,6 +29,8 @@ import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* The stargate config is responsible for keeping track of all configuration values
@@ -38,7 +42,6 @@ public final class StargateConfig {
private final HashSet managedWorlds = new HashSet<>();
private StargateGateConfig stargateGateConfig;
- private MessageSender messageSender;
private final LanguageLoader languageLoader;
private EconomyConfig economyConfig;
private final Logger logger;
@@ -47,6 +50,7 @@ public final class StargateConfig {
private String gateFolder;
private String portalFolder;
private String languageName = "en";
+ private boolean isLoaded = false;
private final Map configOptions;
@@ -55,7 +59,7 @@ public final class StargateConfig {
*
* @param logger The logger to use for logging errors
*/
- public StargateConfig(Logger logger) {
+ public StargateConfig(@NotNull Logger logger) {
this.logger = logger;
configOptions = new HashMap<>();
@@ -73,6 +77,7 @@ public final class StargateConfig {
*
* @return A reference to the config options map
*/
+ @NotNull
public Map getConfigOptionsReference() {
return configOptions;
}
@@ -92,22 +97,48 @@ public final class StargateConfig {
languageLoader.setChosenLanguage(languageName);
languageLoader.reload();
- messageSender = new MessageSender(languageLoader);
+ // Update prefix of the format builder
+ SGFormatBuilder.setStringFormatter(getStringFormatter());
+
if (isDebuggingEnabled()) {
languageLoader.debug();
}
- this.createMissingFolders();
this.loadGates();
+ this.createMissingFolders();
this.loadAllPortals();
//Set up vault economy if vault has been loaded
setupVaultEconomy();
- DynmapAPI dynmapAPI = (DynmapAPI) Bukkit.getPluginManager().getPlugin("dynmap");
- if (dynmapAPI != null) {
- DynmapManager.initialize(dynmapAPI);
- DynmapManager.addAllPortalMarkers();
+
+ //Set up dynmap
+ try {
+ DynmapAPI dynmapAPI = (DynmapAPI) Bukkit.getPluginManager().getPlugin("dynmap");
+ if (dynmapAPI != null) {
+ try {
+ DynmapManager.initialize(dynmapAPI);
+ DynmapManager.addAllPortalMarkers();
+ } catch (NullPointerException ignored) {
+ logger.warning("Dynmap started in an invalid state. Check your log/console for dynmap-related " +
+ "problems. Dynmap integration cannot be initialized.");
+ }
+ }
+ } catch (NoClassDefFoundError error) {
+ logger.warning("Dynmap seems to be unavailable, even though its API is registered. Dynmap " +
+ "integration is disabled.");
+ DynmapManager.disable();
}
+
+ this.isLoaded = true;
+ }
+
+ /**
+ * Gets whether this configuration has been fully loaded
+ *
+ * @return True if not fully loaded
+ */
+ public boolean isNotLoaded() {
+ return !this.isLoaded;
}
/**
@@ -115,6 +146,7 @@ public final class StargateConfig {
*
* @return The loaded config options
*/
+ @NotNull
public Map getConfigOptions() {
return new HashMap<>(configOptions);
}
@@ -126,6 +158,7 @@ public final class StargateConfig {
*
* @return The open portals queue
*/
+ @NotNull
public Queue getOpenPortalsQueue() {
return openPortalsQueue;
}
@@ -137,6 +170,7 @@ public final class StargateConfig {
*
* @return The active portals queue
*/
+ @NotNull
public Queue getActivePortalsQueue() {
return activePortalsQueue;
}
@@ -182,6 +216,7 @@ public final class StargateConfig {
*
* @return The object containing economy config values
*/
+ @NotNull
public EconomyConfig getEconomyConfig() {
return this.economyConfig;
}
@@ -191,16 +226,16 @@ public final class StargateConfig {
*
* @param sender The sender of the reload request
*/
- public void reload(CommandSender sender) {
+ public void reload(@NotNull CommandSender sender) {
//Unload all saved data
unload();
//Perform all block change requests to prevent mismatch if a gate's open-material changes. Changing the
// closed-material still requires a restart.
- BlockChangeRequest firstElement = Stargate.getBlockChangeRequestQueue().peek();
+ BlockChangeRequest firstElement = Stargate.getControlBlockUpdateRequestQueue().peek();
while (firstElement != null) {
BlockChangeThread.pollQueue();
- firstElement = Stargate.getBlockChangeRequestQueue().peek();
+ firstElement = Stargate.getControlBlockUpdateRequestQueue().peek();
}
//Store the old enable bungee state in case it changes
@@ -217,7 +252,10 @@ public final class StargateConfig {
//Reload portal markers
DynmapManager.addAllPortalMarkers();
- messageSender.sendErrorMessage(sender, languageLoader.getString("reloaded"));
+ // Update prefix of the format builder
+ SGFormatBuilder.setStringFormatter(getStringFormatter());
+
+ new SGFormatBuilder(Message.RELOADED).error(sender);
}
/**
@@ -264,6 +302,7 @@ public final class StargateConfig {
*
* @return The managed worlds
*/
+ @NotNull
public Set getManagedWorlds() {
return new HashSet<>(managedWorlds);
}
@@ -273,7 +312,7 @@ public final class StargateConfig {
*
* @param worldName The name of the world to manage
*/
- public void addManagedWorld(String worldName) {
+ public void addManagedWorld(@NotNull String worldName) {
managedWorlds.add(worldName);
}
@@ -282,7 +321,7 @@ public final class StargateConfig {
*
* @param worldName The name of the world to stop managing
*/
- public void removeManagedWorld(String worldName) {
+ public void removeManagedWorld(@NotNull String worldName) {
managedWorlds.remove(worldName);
}
@@ -364,9 +403,11 @@ public final class StargateConfig {
FileConfiguration newConfig = Stargate.getInstance().getConfig();
boolean isMigrating = false;
- if (newConfig.getString("lang") != null || newConfig.getString("economy.freeGatesGreen") != null) {
- migrateConfig(newConfig);
+ if (newConfig.getString("lang") != null || newConfig.getString("economy.taxAccount") == null) {
+ ConfigHelper.migrateConfig(Stargate.getInstance());
isMigrating = true;
+ Stargate.getInstance().reloadConfig();
+ newConfig = Stargate.getInstance().getConfig();
}
//Copy missing default values if any values are missing
@@ -380,13 +421,10 @@ public final class StargateConfig {
//Load the option using its correct data type
switch (option.getDataType()) {
case STRING_LIST -> optionValue = newConfig.getStringList(configNode);
- case STRING -> {
- String value = newConfig.getString(configNode);
- optionValue = value != null ? value.trim() : "";
- }
- case BOOLEAN -> optionValue = newConfig.getBoolean(configNode);
- case INTEGER -> optionValue = newConfig.getInt(configNode);
- case DOUBLE -> optionValue = newConfig.getDouble(configNode);
+ case STRING -> optionValue = newConfig.getString(configNode, (String) option.getDefaultValue()).trim();
+ case BOOLEAN -> optionValue = newConfig.getBoolean(configNode, (boolean) option.getDefaultValue());
+ case INTEGER -> optionValue = newConfig.getInt(configNode, (int) option.getDefaultValue());
+ case DOUBLE -> optionValue = newConfig.getDouble(configNode, (double) option.getDefaultValue());
default -> throw new IllegalArgumentException("Invalid config data type encountered");
}
configOptions.put(option, optionValue);
@@ -397,10 +435,24 @@ public final class StargateConfig {
//Get important folders from the config
portalFolder = (String) configOptions.get(ConfigOption.PORTAL_FOLDER);
+ if (portalFolder.isEmpty()) {
+ portalFolder = dataFolderPath + "/portals/";
+ } else {
+ portalFolder = replacePluginFolderPath(portalFolder);
+ }
+ Stargate.debug("StargateConfig::loadConfig", "Portal folder is " + portalFolder);
+
gateFolder = (String) configOptions.get(ConfigOption.GATE_FOLDER);
+ if (gateFolder.isEmpty()) {
+ gateFolder = dataFolderPath + "/gates/";
+ } else {
+ gateFolder = replacePluginFolderPath(gateFolder);
+ }
+ Stargate.debug("StargateConfig::loadConfig", "Gate folder is " + gateFolder);
//If users have an outdated config, assume they also need to update their default gates
if (isMigrating) {
+ this.createMissingFolders();
GateHandler.writeDefaultGatesToFolder(gateFolder);
}
@@ -413,11 +465,29 @@ public final class StargateConfig {
Stargate.getInstance().saveConfig();
}
+ /**
+ * Replaces "plugins/Stargate" in a folder path, and replaces it with the full path relative to the data folder
+ *
+ * @param input The input string to replace in
+ * @return The replaced path, or the input if not applicable
+ */
+ @NotNull
+ private String replacePluginFolderPath(@NotNull String input) {
+ Pattern pattern = Pattern.compile("(?i)^plugins[\\\\/]Stargate");
+ Matcher matcher = pattern.matcher(input);
+ if (matcher.find()) {
+ return dataFolderPath + matcher.replaceAll("");
+ } else {
+ return input;
+ }
+ }
+
/**
* Gets the object containing configuration values regarding gates
*
* @return Gets the gate config
*/
+ @NotNull
public StargateGateConfig getStargateGateConfig() {
return stargateGateConfig;
}
@@ -430,54 +500,15 @@ public final class StargateConfig {
Stargate.logInfo(String.format("Loaded %s gate layouts", GateHandler.getGateCount()));
}
- /**
- * Changes all configuration values from the old name to the new name
- *
- * @param newConfig The config to read from and write to
- */
- private void migrateConfig(FileConfiguration newConfig) {
- //Save the old config just in case something goes wrong
- try {
- newConfig.save(dataFolderPath + "/config.yml.old");
- } catch (IOException e) {
- Stargate.debug("Stargate::migrateConfig", "Unable to save old backup and do migration");
- e.printStackTrace();
- return;
- }
-
- //Read all available config migrations
- Map migrationFields;
- try {
- migrationFields = FileHelper.readKeyValuePairs(FileHelper.getBufferedReaderFromInputStream(
- FileHelper.getInputStreamForInternalFile("/config-migrations.txt")), "=",
- ColorConversion.NORMAL);
- } catch (IOException e) {
- Stargate.debug("Stargate::migrateConfig", "Unable to load config migration file");
- e.printStackTrace();
- return;
- }
-
- //Replace old config names with the new ones
- for (String key : migrationFields.keySet()) {
- if (newConfig.contains(key)) {
- String newPath = migrationFields.get(key);
- Object oldValue = newConfig.get(key);
- if (!newPath.trim().isEmpty()) {
- newConfig.set(newPath, oldValue);
- }
- newConfig.set(key, null);
- }
- }
- }
-
/**
* Loads economy from Vault
*/
private void setupVaultEconomy() {
EconomyConfig economyConfig = getEconomyConfig();
- if (economyConfig.setupEconomy(Stargate.getPluginManager()) && economyConfig.getEconomy() != null) {
+ if (economyConfig.setupEconomy(Stargate.getPluginManager()) && economyConfig.getEconomy() != null &&
+ economyConfig.getVault() != null) {
String vaultVersion = economyConfig.getVault().getDescription().getVersion();
- Stargate.logInfo(Stargate.replaceVars(Stargate.getString("vaultLoaded"), "%version%", vaultVersion));
+ Stargate.logInfo(new SGFormatBuilder(Message.VAULT_LOADED).replace("%version%", vaultVersion).toString());
}
}
@@ -497,18 +528,24 @@ public final class StargateConfig {
* Creates missing folders
*/
private void createMissingFolders() {
- File newPortalDir = new File(portalFolder);
- if (!newPortalDir.exists()) {
- if (!newPortalDir.mkdirs()) {
- logger.severe("Unable to create portal directory");
- }
- }
+ createMissingFolder(new File(gateFolder), "Unable to create gate directory");
+ createMissingFolder(new File(portalFolder), "Unable to create portal directory");
File newFile = new File(portalFolder, Stargate.getInstance().getServer().getWorlds().get(0).getName() +
".db");
- if (!newFile.exists() && !newFile.getParentFile().exists()) {
- if (!newFile.getParentFile().mkdirs()) {
- logger.severe("Unable to create portal database folder: " + newFile.getParentFile().getPath());
- }
+ if (!newFile.exists() && !newFile.getParentFile().exists() && !newFile.getParentFile().mkdirs()) {
+ logger.severe("Unable to create portal database folder: " + newFile.getParentFile().getPath());
+ }
+ }
+
+ /**
+ * Creates the given folder if it's missing
+ *
+ * @param folder The folder to create
+ * @param errorMessage The error message to display if unable to create the folder
+ */
+ private void createMissingFolder(File folder, String errorMessage) {
+ if (!folder.exists() && !folder.mkdirs()) {
+ logger.severe(errorMessage);
}
}
@@ -517,6 +554,7 @@ public final class StargateConfig {
*
* @return The portal folder
*/
+ @NotNull
public String getPortalFolder() {
return portalFolder;
}
@@ -528,26 +566,57 @@ public final class StargateConfig {
*
* @return The folder storing gate files
*/
+ @NotNull
public String getGateFolder() {
return gateFolder;
}
- /**
- * Gets the sender for sending messages to players
- *
- * @return The sender for sending messages to players
- */
- public MessageSender getMessageSender() {
- return messageSender;
- }
-
/**
* Gets the language loader containing translated strings
*
* @return The language loader
*/
+ @NotNull
public LanguageLoader getLanguageLoader() {
return languageLoader;
}
+ /**
+ * Gets the string formatter to use
+ */
+ @NotNull
+ private StringFormatter getStringFormatter() {
+ // In order to allow automatic customization of prefix color, parse it properly
+ String rawPrefix = getLanguageLoader().getString(Message.PREFIX);
+ String colorPattern = "(?:[&§][a-fA-F0-9klmnor]|&?#[0-9a-fA-F]{6}|§x(?:§[a-fA-F0-9]){6})*";
+ Pattern pattern = Pattern.compile("(" + colorPattern + "\\[" + colorPattern + ")(\\w+)(" +
+ colorPattern + "]" + colorPattern + ")");
+
+ return getStringFormatter(rawPrefix, pattern);
+ }
+
+ /**
+ * Gets the string formatter to use
+ *
+ * @param rawPrefix The formatter prefix to parse
+ * @param pattern The pattern to use for parsing
+ */
+ private static @NotNull StringFormatter getStringFormatter(String rawPrefix, Pattern pattern) {
+ String prefix = rawPrefix;
+ String namePrefix = "[";
+ String nameSuffix = "]";
+ Matcher matcher = pattern.matcher(rawPrefix);
+ if (matcher.find()) {
+ namePrefix = matcher.group(1).trim();
+ prefix = matcher.group(2).trim();
+ nameSuffix = matcher.group(3).trim();
+ }
+
+ StringFormatter stringFormatter = new StringFormatter(prefix, new Translator());
+ stringFormatter.setColorConversion(ColorConversion.RGB);
+ stringFormatter.setNamePrefix(namePrefix);
+ stringFormatter.setNameSuffix(nameSuffix);
+ return stringFormatter;
+ }
+
}
diff --git a/src/main/java/net/knarcraft/stargate/config/StargateGateConfig.java b/src/main/java/net/knarcraft/stargate/config/StargateGateConfig.java
index f1dc7ca..9a4c2fd 100644
--- a/src/main/java/net/knarcraft/stargate/config/StargateGateConfig.java
+++ b/src/main/java/net/knarcraft/stargate/config/StargateGateConfig.java
@@ -6,6 +6,7 @@ import net.knarcraft.stargate.portal.PortalSignDrawer;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Color;
import org.bukkit.Material;
+import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
@@ -26,7 +27,7 @@ public final class StargateGateConfig {
*
* @param configOptions The loaded config options to use
*/
- public StargateGateConfig(Map configOptions) {
+ public StargateGateConfig(@NotNull Map configOptions) {
this.configOptions = configOptions;
loadGateConfig();
}
@@ -100,6 +101,17 @@ public final class StargateGateConfig {
return (boolean) configOptions.get(ConfigOption.HANDLE_CREATURE_TRANSPORTATION);
}
+ /**
+ * Gets the delay to wait between each update of a Stargate's control block
+ *
+ * This only affects the queued control updates during startup. It does not affect normal gameplay.
+ *
+ * @return The amount of ticks to delay control updates by
+ */
+ public int controlUpdateDelay() {
+ return (int) configOptions.get(ConfigOption.CONTROL_UPDATE_QUEUE_DELAY);
+ }
+
/**
* Gets whether vehicles containing a creature, but not a player should be handled
*
@@ -248,8 +260,8 @@ public final class StargateGateConfig {
* @param defaultColors The specified default colors
* @param colorMaps The list of color maps to save the resulting colors to
*/
- private void parsePerSignColors(Object signColorSpecification, ChatColor[] defaultColors,
- List