mirror of https://github.com/Maxlego08/zKoth.git
🎉 Start V3
This commit is contained in:
commit
3c051e1588
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
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
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
|
@ -0,0 +1,28 @@
|
|||
# Template Plugin
|
||||
|
||||
Here is a simple project for the quick creation of minecraft plugin.
|
||||
Works from version 1.8 to version 1.19+
|
||||
|
||||
Documentation: https://drawerPlugin.groupez.dev/
|
||||
|
||||
# GroupeZ
|
||||
|
||||
https://groupez.dev is a marketplace that allows you to sell your plugins without any charge !
|
||||
|
||||
## Features
|
||||
|
||||
* Commands
|
||||
* TabCompleter
|
||||
* Inventories
|
||||
* Json file
|
||||
* Useful function (in the class ZUtils)
|
||||
* ItemBuilder
|
||||
* CooldownBuilder
|
||||
* TimerBuilder
|
||||
* Pagination
|
||||
* Inventory button
|
||||
* Custom Event
|
||||
* YML Loader (itemstack and button)
|
||||
* Scoreboard (https://github.com/MrMicky-FR/FastBoard)
|
||||
* Placeholder UTILS
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>fr.maxlego08.koth</groupId>
|
||||
<artifactId>zKoth</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<configuration>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>com/cryptomorin/xseries/messages/*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/particles/*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/XBiome*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/NMSExtras*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/NoteBlockMusic*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/SkullCacheListener*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/NoteBlockMusic*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/XTag*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/XPotion*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/XMaterial*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/XItemStack*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/XBlock*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/XEntity*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/XEnchantment*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/SkullUtils*</exclude>
|
||||
<exclude>com/cryptomorin/xseries/ReflectionUtils*</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>placeholderapi</id>
|
||||
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>minecraft-repo</id>
|
||||
<url>https://libraries.minecraft.net/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>papermc</id>
|
||||
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.Maxlego08</groupId>
|
||||
<artifactId>zTranslator</artifactId>
|
||||
<version>1.0.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.folia</groupId>
|
||||
<artifactId>folia-api</artifactId>
|
||||
<version>1.19.4-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
<version>2.11.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mojang</groupId>
|
||||
<artifactId>authlib</artifactId>
|
||||
<version>3.11.50</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.cryptomorin</groupId>
|
||||
<artifactId>XSeries</artifactId>
|
||||
<version>9.4.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,45 @@
|
|||
package fr.maxlego08.koth;
|
||||
|
||||
import fr.maxlego08.koth.command.commands.CommandKoth;
|
||||
import fr.maxlego08.koth.placeholder.LocalPlaceholder;
|
||||
import fr.maxlego08.koth.save.MessageLoader;
|
||||
import fr.maxlego08.koth.zcore.ZPlugin;
|
||||
|
||||
/**
|
||||
* System to create your plugins very simply Projet:
|
||||
* <a href="https://github.com/Maxlego08/TemplatePlugin">https://github.com/Maxlego08/TemplatePlugin</a>
|
||||
*
|
||||
* @author Maxlego08
|
||||
*/
|
||||
public class KothPlugin extends ZPlugin {
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
||||
LocalPlaceholder placeholder = LocalPlaceholder.getInstance();
|
||||
placeholder.setPrefix("zkoth");
|
||||
|
||||
this.preEnable();
|
||||
|
||||
this.registerCommand("zkoth", new CommandKoth(this), "koth");
|
||||
|
||||
this.saveDefaultConfig();
|
||||
// this.addSave(Config.getInstance());
|
||||
this.addSave(new MessageLoader(this));
|
||||
|
||||
this.loadFiles();
|
||||
|
||||
this.postEnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
|
||||
this.preDisable();
|
||||
|
||||
this.saveFiles();
|
||||
|
||||
this.postDisable();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,300 @@
|
|||
package fr.maxlego08.koth.command;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
import fr.maxlego08.koth.zcore.logger.Logger;
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandMap;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import fr.maxlego08.koth.KothPlugin;
|
||||
import fr.maxlego08.koth.zcore.utils.commands.CommandType;
|
||||
|
||||
public class CommandManager extends ZUtils implements CommandExecutor, TabCompleter {
|
||||
|
||||
private static CommandMap commandMap;
|
||||
private static Constructor<? extends PluginCommand> constructor;
|
||||
|
||||
static {
|
||||
try {
|
||||
Field bukkitCommandMap = Bukkit.getServer().getClass().getDeclaredField("commandMap");
|
||||
bukkitCommandMap.setAccessible(true);
|
||||
commandMap = (CommandMap) bukkitCommandMap.get(Bukkit.getServer());
|
||||
constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class);
|
||||
constructor.setAccessible(true);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private final KothPlugin plugin;
|
||||
private final List<VCommand> commands = new ArrayList<VCommand>();
|
||||
|
||||
/**
|
||||
* F
|
||||
*
|
||||
* @param template
|
||||
*/
|
||||
public CommandManager(KothPlugin template) {
|
||||
this.plugin = template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Valid commands
|
||||
*/
|
||||
public void validCommands() {
|
||||
this.plugin.getLog().log("Loading " + getUniqueCommand() + " commands", Logger.LogType.SUCCESS);
|
||||
this.commandChecking();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param command
|
||||
* @return
|
||||
*/
|
||||
public VCommand registerCommand(VCommand command) {
|
||||
this.commands.add(command);
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to register a command
|
||||
*
|
||||
* @param string
|
||||
* @param command
|
||||
* @return VCommand
|
||||
*/
|
||||
public VCommand registerCommand(String string, VCommand command) {
|
||||
this.commands.add(command.addSubCommand(string));
|
||||
this.plugin.getCommand(string).setExecutor(this);
|
||||
this.plugin.getCommand(string).setTabCompleter(this);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
|
||||
for (VCommand command : this.commands) {
|
||||
if (command.getSubCommands().contains(cmd.getName().toLowerCase())) {
|
||||
if ((args.length == 0 || command.isIgnoreParent()) && command.getParent() == null) {
|
||||
CommandType type = processRequirements(command, sender, args);
|
||||
if (!type.equals(CommandType.CONTINUE))
|
||||
return true;
|
||||
}
|
||||
} else if (args.length >= 1 && command.getParent() != null
|
||||
&& canExecute(args, cmd.getName().toLowerCase(), command)) {
|
||||
CommandType type = processRequirements(command, sender, args);
|
||||
if (!type.equals(CommandType.CONTINUE))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
message(sender, Message.COMMAND_NO_ARG);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args
|
||||
* @param cmd
|
||||
* @param command
|
||||
* @return true if can execute
|
||||
*/
|
||||
private boolean canExecute(String[] args, String cmd, VCommand command) {
|
||||
for (int index = args.length - 1; index > -1; index--) {
|
||||
if (command.getSubCommands().contains(args[index].toLowerCase())) {
|
||||
if (command.isIgnoreArgs()
|
||||
&& (command.getParent() != null ? canExecute(args, cmd, command.getParent(), index - 1) : true))
|
||||
return true;
|
||||
if (index < args.length - 1)
|
||||
return false;
|
||||
return canExecute(args, cmd, command.getParent(), index - 1);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args
|
||||
* @param cmd
|
||||
* @param command
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
private boolean canExecute(String[] args, String cmd, VCommand command, int index) {
|
||||
if (index < 0 && command.getSubCommands().contains(cmd.toLowerCase())) {
|
||||
return true;
|
||||
} else if (index < 0) {
|
||||
return false;
|
||||
} else if (command.getSubCommands().contains(args[index].toLowerCase())) {
|
||||
return canExecute(args, cmd, command.getParent(), index - 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to process an order. First we check if the sender has the
|
||||
* permission or if the command has a permission. If yes then we execute the
|
||||
* command otherwise we send the message for the permission
|
||||
*
|
||||
* @param command
|
||||
* - Object that contains the command
|
||||
* @param sender
|
||||
* - Person who executes the command
|
||||
* @param strings
|
||||
* - Argument of the command
|
||||
* @return CommandType - Return of the command
|
||||
*/
|
||||
private CommandType processRequirements(VCommand command, CommandSender sender, String[] strings) {
|
||||
|
||||
if (!(sender instanceof Player) && !command.isConsoleCanUse()) {
|
||||
message(sender, Message.COMMAND_NO_CONSOLE);
|
||||
return CommandType.DEFAULT;
|
||||
}
|
||||
|
||||
if (command.getPermission() == null || hasPermission(sender, command.getPermission())) {
|
||||
|
||||
if (command.runAsync) {
|
||||
super.runAsync(this.plugin, () -> {
|
||||
CommandType returnType = command.prePerform(this.plugin, sender, strings);
|
||||
if (returnType == CommandType.SYNTAX_ERROR) {
|
||||
message(sender, Message.COMMAND_SYNTAXE_ERROR, "%syntax%", command.getSyntax());
|
||||
}
|
||||
});
|
||||
return CommandType.DEFAULT;
|
||||
}
|
||||
|
||||
CommandType returnType = command.prePerform(this.plugin, sender, strings);
|
||||
if (returnType == CommandType.SYNTAX_ERROR) {
|
||||
message(sender, Message.COMMAND_SYNTAXE_ERROR, "%syntax%", command.getSyntax());
|
||||
}
|
||||
return returnType;
|
||||
}
|
||||
message(sender, Message.COMMAND_NO_PERMISSION);
|
||||
return CommandType.DEFAULT;
|
||||
}
|
||||
|
||||
public List<VCommand> getCommands() {
|
||||
return this.commands;
|
||||
}
|
||||
|
||||
private int getUniqueCommand() {
|
||||
return (int) this.commands.stream().filter(command -> command.getParent() == null).count();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param command
|
||||
* @param commandString
|
||||
* @return
|
||||
*/
|
||||
public boolean isValid(VCommand command, String commandString) {
|
||||
return command.getParent() != null ? isValid(command.getParent(), commandString)
|
||||
: command.getSubCommands().contains(commandString.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to check if all commands are correct If an command does not
|
||||
* have
|
||||
*/
|
||||
private void commandChecking() {
|
||||
this.commands.forEach(command -> {
|
||||
if (command.sameSubCommands()) {
|
||||
Logger.info(command.toString() + " command to an argument similar to its parent command !",
|
||||
Logger.LogType.ERROR);
|
||||
this.plugin.getPluginLoader().disablePlugin(this.plugin);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command cmd, String str, String[] args) {
|
||||
|
||||
for (VCommand command : commands) {
|
||||
|
||||
if (command.getSubCommands().contains(cmd.getName().toLowerCase())) {
|
||||
if (args.length == 1 && command.getParent() == null) {
|
||||
return proccessTab(sender, command, args);
|
||||
}
|
||||
} else {
|
||||
String[] newArgs = Arrays.copyOf(args, args.length - 1);
|
||||
if (newArgs.length >= 1 && command.getParent() != null
|
||||
&& canExecute(newArgs, cmd.getName().toLowerCase(), command)) {
|
||||
return proccessTab(sender, command, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to execute the tab completion
|
||||
*
|
||||
* @param sender
|
||||
* @param command
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
private List<String> proccessTab(CommandSender sender, VCommand command, String[] args) {
|
||||
|
||||
CommandType type = command.getTabCompleter();
|
||||
if (type.equals(CommandType.DEFAULT)) {
|
||||
|
||||
String startWith = args[args.length - 1];
|
||||
|
||||
List<String> tabCompleter = new ArrayList<>();
|
||||
for (VCommand vCommand : this.commands) {
|
||||
if ((vCommand.getParent() != null && vCommand.getParent() == command)) {
|
||||
String cmd = vCommand.getSubCommands().get(0);
|
||||
if (vCommand.getPermission() == null || sender.hasPermission(vCommand.getPermission())) {
|
||||
if (startWith.length() == 0 || cmd.startsWith(startWith)) {
|
||||
tabCompleter.add(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return tabCompleter.size() == 0 ? null : tabCompleter;
|
||||
|
||||
} else if (type.equals(CommandType.SUCCESS)) {
|
||||
return command.toTab(this.plugin, sender, args);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register spigot command without plugin.yml This method will allow to
|
||||
* register a command in the spigot without using the plugin.yml This saves
|
||||
* time and understanding, the plugin.yml file is clearer
|
||||
*
|
||||
* @param string - Main command
|
||||
* @param vCommand - Command object
|
||||
* @param aliases - Command aliases
|
||||
*/
|
||||
public void registerCommand(Plugin plugin, String string, VCommand vCommand, List<String> aliases) {
|
||||
try {
|
||||
PluginCommand command = constructor.newInstance(string, this.plugin);
|
||||
command.setExecutor(this);
|
||||
command.setTabCompleter(this);
|
||||
command.setAliases(aliases);
|
||||
|
||||
commands.add(vCommand.addSubCommand(string));
|
||||
vCommand.addSubCommand(aliases);
|
||||
|
||||
if (!commandMap.register(command.getName(), plugin.getDescription().getName(), command)) {
|
||||
Logger.info("Unable to add the command " + vCommand.getSyntax());
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,595 @@
|
|||
package fr.maxlego08.koth.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
import fr.maxlego08.koth.zcore.enums.Permission;
|
||||
import fr.maxlego08.koth.zcore.utils.commands.Arguments;
|
||||
import fr.maxlego08.koth.zcore.utils.commands.CollectionBiConsumer;
|
||||
import fr.maxlego08.koth.zcore.utils.commands.CommandType;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.maxlego08.koth.KothPlugin;
|
||||
import fr.maxlego08.koth.save.Config;
|
||||
import fr.maxlego08.koth.zcore.utils.commands.Tab;
|
||||
|
||||
public abstract class VCommand extends Arguments {
|
||||
|
||||
protected final KothPlugin plugin;
|
||||
|
||||
/**
|
||||
* Permission used for the command, if it is a null then everyone can
|
||||
* execute the command
|
||||
*/
|
||||
private String permission;
|
||||
|
||||
/**
|
||||
* Mother command of this command
|
||||
*/
|
||||
protected VCommand parent;
|
||||
|
||||
/**
|
||||
* Are all sub commands used
|
||||
*/
|
||||
private List<String> subCommands = new ArrayList<String>();
|
||||
protected List<VCommand> subVCommands = new ArrayList<VCommand>();
|
||||
|
||||
private List<String> requireArgs = new ArrayList<String>();
|
||||
private List<String> optionalArgs = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* If this variable is false the command will not be able to use this
|
||||
* command
|
||||
*/
|
||||
private boolean consoleCanUse = true;
|
||||
|
||||
/**
|
||||
* This variable allows to run the main class of the command even with
|
||||
* arguments convenient for commands like /ban <player>
|
||||
*/
|
||||
private boolean ignoreParent = false;
|
||||
private boolean ignoreArgs = false;
|
||||
private boolean extendedArgs = false;
|
||||
protected boolean runAsync = false;
|
||||
private CommandType tabCompleter = CommandType.DEFAULT;
|
||||
|
||||
/**
|
||||
* This is the person who executes the command
|
||||
*/
|
||||
protected CommandSender sender;
|
||||
protected Player player;
|
||||
|
||||
private String syntax;
|
||||
private String description;
|
||||
private int argsMinLength;
|
||||
private int argsMaxLength;
|
||||
|
||||
protected Map<Integer, CollectionBiConsumer> tabCompletions = new HashMap<>();
|
||||
|
||||
/**
|
||||
* @param plugin
|
||||
*/
|
||||
public VCommand(KothPlugin plugin) {
|
||||
super();
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
//
|
||||
// GETTER
|
||||
//
|
||||
|
||||
public Optional<CollectionBiConsumer> getCompletionAt(int index) {
|
||||
return Optional.ofNullable(this.tabCompletions.getOrDefault(index, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return command permission
|
||||
*
|
||||
* @return the permission
|
||||
*/
|
||||
public String getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the parent
|
||||
*/
|
||||
public VCommand getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the subCommand
|
||||
*/
|
||||
public List<String> getSubCommands() {
|
||||
return subCommands;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the consoleCanUse
|
||||
*/
|
||||
public boolean isConsoleCanUse() {
|
||||
return consoleCanUse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ignoreParent
|
||||
*/
|
||||
public boolean isIgnoreParent() {
|
||||
return ignoreParent;
|
||||
}
|
||||
|
||||
public CommandSender getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the argsMinLength
|
||||
*/
|
||||
public int getArgsMinLength() {
|
||||
return argsMinLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the argsMaxLength
|
||||
*/
|
||||
public int getArgsMaxLength() {
|
||||
return argsMaxLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the player
|
||||
*/
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generate or custom syntax
|
||||
*
|
||||
* @return the syntax
|
||||
*/
|
||||
public String getSyntax() {
|
||||
if (syntax == null) {
|
||||
syntax = generateDefaultSyntax("");
|
||||
}
|
||||
return syntax;
|
||||
}
|
||||
|
||||
public boolean isIgnoreArgs() {
|
||||
return ignoreArgs;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description == null ? "no description" : description;
|
||||
}
|
||||
|
||||
public CommandType getTabCompleter() {
|
||||
return tabCompleter;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
protected void setTabCompletor() {
|
||||
this.tabCompleter = CommandType.SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// SETTER
|
||||
//
|
||||
|
||||
public void setIgnoreArgs(boolean ignoreArgs) {
|
||||
this.ignoreArgs = ignoreArgs;
|
||||
}
|
||||
|
||||
public void setIgnoreParent(boolean ignoreParent) {
|
||||
this.ignoreParent = ignoreParent;
|
||||
}
|
||||
|
||||
public void setExtendedArgs(boolean extendedArgs) {
|
||||
this.extendedArgs = extendedArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param syntax
|
||||
* the syntax to set
|
||||
*/
|
||||
protected VCommand setSyntax(String syntax) {
|
||||
this.syntax = syntax;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param permission
|
||||
* the permission to set
|
||||
*/
|
||||
protected VCommand setPermission(String permission) {
|
||||
this.permission = permission;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param permission
|
||||
* the permission to set
|
||||
*/
|
||||
protected VCommand setPermission(Permission permission) {
|
||||
this.permission = permission.getPermission();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param parent
|
||||
* the parent to set
|
||||
*/
|
||||
protected VCommand setParent(VCommand parent) {
|
||||
this.parent = parent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param consoleCanUse
|
||||
* the consoleCanUse to set
|
||||
*/
|
||||
protected VCommand setConsoleCanUse(boolean consoleCanUse) {
|
||||
this.consoleCanUse = consoleCanUse;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected VCommand onlyPlayers(){
|
||||
this.consoleCanUse = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mettre la description de la commande
|
||||
*
|
||||
* @param description
|
||||
* @return
|
||||
*/
|
||||
protected VCommand setDescription(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ajouter un argument obligatoire
|
||||
*/
|
||||
protected void addRequireArg(String message) {
|
||||
this.requireArgs.add(message);
|
||||
this.ignoreParent = this.parent == null ? true : false;
|
||||
this.ignoreArgs = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ajouter un argument obligatoire
|
||||
*/
|
||||
protected void addRequireArg(String message, CollectionBiConsumer runnable) {
|
||||
this.addRequireArg(message);
|
||||
int index = this.requireArgs.size();
|
||||
this.addCompletion(index - 1, runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajouter un argument optionel
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
protected void addOptionalArg(String message, CollectionBiConsumer runnable) {
|
||||
this.addOptionalArg(message);
|
||||
int index = this.requireArgs.size() + this.optionalArgs.size();
|
||||
this.addCompletion(index - 1, runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajouter un argument optionel
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
protected void addOptionalArg(String message) {
|
||||
this.optionalArgs.add(message);
|
||||
this.ignoreParent = this.parent == null ? true : false;
|
||||
this.ignoreArgs = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mettre la description de la commande
|
||||
*
|
||||
* @param description
|
||||
* @return
|
||||
*/
|
||||
protected VCommand setDescription(Message description) {
|
||||
this.description = description.getMessage();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return first command
|
||||
*/
|
||||
public String getFirst() {
|
||||
return this.subCommands.get(0);
|
||||
}
|
||||
|
||||
//
|
||||
// OTHER
|
||||
//
|
||||
|
||||
/**
|
||||
* Adds sub orders
|
||||
*
|
||||
* @param subCommand
|
||||
* @return this
|
||||
*/
|
||||
public VCommand addSubCommand(String subCommand) {
|
||||
this.subCommands.add(subCommand);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds sub orders
|
||||
*
|
||||
* @param subCommand
|
||||
* @return this
|
||||
*/
|
||||
public VCommand addSubCommand(VCommand command) {
|
||||
command.setParent(this);
|
||||
this.plugin.getCommandManager().registerCommand(command);
|
||||
this.subVCommands.add(command);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds sub orders
|
||||
*
|
||||
* @param subCommand
|
||||
* @return this
|
||||
*/
|
||||
public VCommand addSubCommand(String... subCommand) {
|
||||
this.subCommands.addAll(Arrays.asList(subCommand));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link CollectionBiConsumer} to the index for the tab completion
|
||||
*
|
||||
* @param index
|
||||
* @param runnable
|
||||
*/
|
||||
public void addCompletion(int index, CollectionBiConsumer runnable) {
|
||||
this.tabCompletions.put(index, runnable);
|
||||
this.setTabCompletor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to generate the syntax of the command manually But you you can
|
||||
* set it yourself with the setSyntax()
|
||||
*
|
||||
* @param syntax
|
||||
* @return generate syntax
|
||||
*/
|
||||
private String generateDefaultSyntax(String syntax) {
|
||||
|
||||
String tmpString = subCommands.get(0);
|
||||
|
||||
boolean update = syntax.equals("");
|
||||
|
||||
if (requireArgs.size() != 0 && update) {
|
||||
for (String requireArg : requireArgs) {
|
||||
requireArg = "<" + requireArg + ">";
|
||||
syntax += " " + requireArg;
|
||||
}
|
||||
}
|
||||
if (optionalArgs.size() != 0 && update) {
|
||||
for (String optionalArg : optionalArgs) {
|
||||
optionalArg = "[<" + optionalArg + ">]";
|
||||
syntax += " " + optionalArg;
|
||||
}
|
||||
}
|
||||
|
||||
tmpString += syntax;
|
||||
|
||||
if (parent == null) {
|
||||
return "/" + tmpString;
|
||||
}
|
||||
|
||||
return parent.generateDefaultSyntax(" " + tmpString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to know the number of parents in a recursive way
|
||||
*
|
||||
* @param defaultParent
|
||||
* @return
|
||||
*/
|
||||
private int parentCount(int defaultParent) {
|
||||
return parent == null ? defaultParent : parent.parentCount(defaultParent + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to manage the arguments and check that the command is valid
|
||||
*
|
||||
* @param plugin
|
||||
* @param commandSender
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
public CommandType prePerform(KothPlugin plugin, CommandSender commandSender, String[] args) {
|
||||
|
||||
// We update the number of arguments according to the number of parents
|
||||
|
||||
this.parentCount = this.parentCount(0);
|
||||
this.argsMaxLength = this.requireArgs.size() + this.optionalArgs.size() + this.parentCount;
|
||||
this.argsMinLength = this.requireArgs.size() + this.parentCount;
|
||||
|
||||
// We generate the basic syntax if it is impossible to find it
|
||||
if (this.syntax == null) {
|
||||
this.syntax = generateDefaultSyntax("");
|
||||
}
|
||||
|
||||
this.args = args;
|
||||
|
||||
String defaultString = super.argAsString(0);
|
||||
|
||||
if (defaultString != null) {
|
||||
for (VCommand subCommand : subVCommands) {
|
||||
if (subCommand.getSubCommands().contains(defaultString.toLowerCase()))
|
||||
return CommandType.CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((this.argsMinLength != 0 && args.length < this.argsMinLength) || this.argsMaxLength != 0 && args.length > this.argsMaxLength && !this.extendedArgs) {
|
||||
return CommandType.SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
this.sender = commandSender;
|
||||
if (this.sender instanceof Player) {
|
||||
this.player = (Player) commandSender;
|
||||
}
|
||||
|
||||
try {
|
||||
return perform(plugin);
|
||||
} catch (Exception e) {
|
||||
if (Config.enableDebug)
|
||||
e.printStackTrace();
|
||||
return CommandType.SYNTAX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that allows you to execute the command
|
||||
*/
|
||||
protected abstract CommandType perform(KothPlugin plugin);
|
||||
|
||||
public boolean sameSubCommands() {
|
||||
if (this.parent == null) {
|
||||
return false;
|
||||
}
|
||||
for (String command : this.subCommands) {
|
||||
if (this.parent.getSubCommands().contains(command))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "VCommand [permission=" + permission + ", subCommands=" + subCommands + ", consoleCanUse="
|
||||
+ consoleCanUse + ", description=" + description + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate tab completion
|
||||
*
|
||||
* @param plugin
|
||||
* @param sender
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
public List<String> toTab(KothPlugin plugin, CommandSender sender, String[] args) {
|
||||
|
||||
this.parentCount = this.parentCount(0);
|
||||
|
||||
int currentInex = (args.length - this.parentCount) - 1;
|
||||
Optional<CollectionBiConsumer> optional = this.getCompletionAt(currentInex);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
|
||||
CollectionBiConsumer collectionRunnable = optional.get();
|
||||
String startWith = args[args.length - 1];
|
||||
return this.generateList(collectionRunnable.accept(sender, args), startWith);
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate list for tab completer
|
||||
*
|
||||
* @param startWith
|
||||
* @param strings
|
||||
* @return
|
||||
*/
|
||||
protected List<String> generateList(String startWith, String... strings) {
|
||||
return generateList(Arrays.asList(strings), startWith);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate list for tab completer
|
||||
*
|
||||
* @param startWith
|
||||
* @param strings
|
||||
* @return
|
||||
*/
|
||||
protected List<String> generateList(Tab tab, String startWith, String... strings) {
|
||||
return generateList(Arrays.asList(strings), startWith, tab);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate list for tab completer
|
||||
*
|
||||
* @param defaultList
|
||||
* @param startWith
|
||||
* @return
|
||||
*/
|
||||
protected List<String> generateList(List<String> defaultList, String startWith) {
|
||||
return generateList(defaultList, startWith, Tab.CONTAINS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate list for tab completer
|
||||
*
|
||||
* @param defaultList
|
||||
* @param startWith
|
||||
* @param tab
|
||||
* @return
|
||||
*/
|
||||
protected List<String> generateList(List<String> defaultList, String startWith, Tab tab) {
|
||||
List<String> newList = new ArrayList<>();
|
||||
for (String str : defaultList) {
|
||||
if (startWith.length() == 0
|
||||
|| (tab.equals(Tab.START) ? str.toLowerCase().startsWith(startWith.toLowerCase())
|
||||
: str.toLowerCase().contains(startWith.toLowerCase()))) {
|
||||
newList.add(str);
|
||||
}
|
||||
}
|
||||
return newList.size() == 0 ? null : newList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add list of aliases
|
||||
*
|
||||
* @param aliases
|
||||
*/
|
||||
public void addSubCommand(List<String> aliases) {
|
||||
this.subCommands.addAll(aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to send the syntax of the commands
|
||||
*
|
||||
* @param commandString
|
||||
* @param sender
|
||||
*/
|
||||
public void syntaxMessage() {
|
||||
this.subVCommands.forEach(command -> {
|
||||
if (command.getPermission() == null || hasPermission(sender, command.getPermission())) {
|
||||
message(this.sender, Message.COMMAND_SYNTAXE_HELP, "%syntax%", command.getSyntax(), "%description%",
|
||||
command.getDescription());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package fr.maxlego08.koth.command.commands;
|
||||
|
||||
import fr.maxlego08.koth.KothPlugin;
|
||||
import fr.maxlego08.koth.command.VCommand;
|
||||
import fr.maxlego08.koth.zcore.enums.Permission;
|
||||
import fr.maxlego08.koth.zcore.utils.commands.CommandType;
|
||||
|
||||
public class CommandKoth extends VCommand {
|
||||
|
||||
public CommandKoth(KothPlugin plugin) {
|
||||
super(plugin);
|
||||
this.setPermission(Permission.EXAMPLE_PERMISSION);
|
||||
this.addSubCommand(new CommandKothReload(plugin));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CommandType perform(KothPlugin plugin) {
|
||||
syntaxMessage();
|
||||
return CommandType.SUCCESS;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package fr.maxlego08.koth.command.commands;
|
||||
|
||||
import fr.maxlego08.koth.KothPlugin;
|
||||
import fr.maxlego08.koth.command.VCommand;
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
import fr.maxlego08.koth.zcore.enums.Permission;
|
||||
import fr.maxlego08.koth.zcore.utils.commands.CommandType;
|
||||
|
||||
public class CommandKothReload extends VCommand {
|
||||
|
||||
public CommandKothReload(KothPlugin plugin) {
|
||||
super(plugin);
|
||||
this.setPermission(Permission.EXAMPLE_PERMISSION_RELOAD);
|
||||
this.addSubCommand("reload", "rl");
|
||||
this.setDescription(Message.DESCRIPTION_RELOAD);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CommandType perform(KothPlugin plugin) {
|
||||
|
||||
plugin.reloadConfig();
|
||||
plugin.reloadFiles();
|
||||
message(sender, Message.RELOAD);
|
||||
|
||||
return CommandType.SUCCESS;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package fr.maxlego08.koth.exceptions;
|
||||
|
||||
public class InventoryAlreadyExistException extends Error {
|
||||
|
||||
public InventoryAlreadyExistException() {
|
||||
super();
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InventoryAlreadyExistException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InventoryAlreadyExistException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InventoryAlreadyExistException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InventoryAlreadyExistException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -5611455794293458580L;
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package fr.maxlego08.koth.exceptions;
|
||||
|
||||
public class InventoryOpenException extends Exception {
|
||||
|
||||
|
||||
|
||||
public InventoryOpenException() {
|
||||
super();
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InventoryOpenException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InventoryOpenException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InventoryOpenException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public InventoryOpenException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package fr.maxlego08.koth.exceptions;
|
||||
|
||||
public class ItemCreateException extends Error {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ItemCreateException() {
|
||||
super();
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ItemCreateException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ItemCreateException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ItemCreateException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ItemCreateException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package fr.maxlego08.koth.exceptions;
|
||||
|
||||
/**
|
||||
* @author Maxlego08
|
||||
*
|
||||
*/
|
||||
public class ItemEnchantException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public ItemEnchantException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
*/
|
||||
public ItemEnchantException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cause
|
||||
*/
|
||||
public ItemEnchantException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @param cause
|
||||
*/
|
||||
public ItemEnchantException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @param cause
|
||||
* @param enableSuppression
|
||||
* @param writableStackTrace
|
||||
*/
|
||||
public ItemEnchantException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package fr.maxlego08.koth.exceptions;
|
||||
|
||||
public class ItemFlagException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ItemFlagException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ItemFlagException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ItemFlagException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ItemFlagException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ItemFlagException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package fr.maxlego08.koth.exceptions;
|
||||
|
||||
public class ListenerNullException extends Error {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ListenerNullException() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ListenerNullException(String message) {
|
||||
super(message);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ListenerNullException(Throwable cause) {
|
||||
super(cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ListenerNullException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public ListenerNullException(String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
package fr.maxlego08.koth.inventory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import fr.maxlego08.koth.exceptions.InventoryOpenException;
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
import fr.maxlego08.koth.zcore.utils.inventory.InventoryResult;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import fr.maxlego08.koth.KothPlugin;
|
||||
import fr.maxlego08.koth.zcore.utils.builder.ItemBuilder;
|
||||
import fr.maxlego08.koth.zcore.utils.inventory.ItemButton;
|
||||
|
||||
public abstract class VInventory extends ZUtils implements Cloneable {
|
||||
|
||||
protected int id;
|
||||
protected KothPlugin plugin;
|
||||
protected Map<Integer, ItemButton> items = new HashMap<Integer, ItemButton>();
|
||||
protected Player player;
|
||||
protected int page;
|
||||
protected Object[] args;
|
||||
protected Inventory inventory;
|
||||
protected String guiName;
|
||||
protected boolean disableClick = true;
|
||||
protected boolean openAsync = false;
|
||||
|
||||
/**
|
||||
* Inventory Id
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public VInventory setId(int id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to create the spigot inventory object
|
||||
*
|
||||
* @param name
|
||||
* @return this
|
||||
*/
|
||||
protected void createInventory(String name) {
|
||||
createInventory(name, 54);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to create the spigot inventory object
|
||||
*
|
||||
* @param name - Inventory name
|
||||
* @param size - Inventory Size
|
||||
* @return this
|
||||
*/
|
||||
protected void createInventory(String name, int size) {
|
||||
this.guiName = name;
|
||||
this.inventory = Bukkit.createInventory(null, size, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create default inventory with default size and name
|
||||
*/
|
||||
private void createDefaultInventory() {
|
||||
if (this.inventory == null) {
|
||||
this.inventory = Bukkit.createInventory(null, 54, "§cDefault Inventory");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding an item to the inventory
|
||||
*
|
||||
* @param slot - Inventory slot
|
||||
* @param material - ItemStack material
|
||||
* @param name - ItemStack name
|
||||
* @return ItemButton
|
||||
*/
|
||||
public ItemButton addItem(int slot, Material material, String name) {
|
||||
return addItem(slot, new ItemBuilder(material, name).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding an item to the inventory
|
||||
*
|
||||
* @param slot - Inventory slot
|
||||
* @param item - ItemBuild
|
||||
* @return ItemButton
|
||||
*/
|
||||
public ItemButton addItem(int slot, ItemBuilder item) {
|
||||
return addItem(slot, item.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding an item to the inventory
|
||||
* Creates the default inventory if it does not exist
|
||||
*
|
||||
* @param slot - Inventory slot
|
||||
* @param item - ItemStack
|
||||
* @return ItemButton
|
||||
*/
|
||||
public ItemButton addItem(int slot, ItemStack item) {
|
||||
|
||||
createDefaultInventory();
|
||||
|
||||
ItemButton button = new ItemButton(item, slot);
|
||||
this.items.put(slot, button);
|
||||
|
||||
if (this.openAsync) {
|
||||
runAsync(this.plugin, () -> this.inventory.setItem(slot, item));
|
||||
} else {
|
||||
this.inventory.setItem(slot, item);
|
||||
}
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to remove an item from the list of items
|
||||
*
|
||||
* @param slot
|
||||
*/
|
||||
public void removeItem(int slot) {
|
||||
this.items.remove(slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to delete all items
|
||||
*/
|
||||
public void clearItem() {
|
||||
this.items.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to retrieve all items
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<Integer, ItemButton> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the click in the inventory is disabled (which is the default)
|
||||
* then it will return true
|
||||
*
|
||||
* @return vrai ou faux
|
||||
*/
|
||||
public boolean isDisableClick() {
|
||||
return disableClick;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the ability to click in the inventory
|
||||
*
|
||||
* @param disableClick
|
||||
*/
|
||||
protected void setDisableClick(boolean disableClick) {
|
||||
this.disableClick = disableClick;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to recover the player
|
||||
*
|
||||
* @return player
|
||||
*/
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to retrieve the page
|
||||
*
|
||||
* @return the page
|
||||
*/
|
||||
public int getPage() {
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the args
|
||||
*/
|
||||
public Object[] getObjets() {
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the inventory
|
||||
*/
|
||||
public Inventory getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the guiName
|
||||
*/
|
||||
public String getGuiName() {
|
||||
return guiName;
|
||||
}
|
||||
|
||||
protected InventoryResult preOpenInventory(KothPlugin main, Player player, int page, Object... args)
|
||||
throws InventoryOpenException {
|
||||
|
||||
this.page = page;
|
||||
this.args = args;
|
||||
this.player = player;
|
||||
this.plugin = main;
|
||||
|
||||
return openInventory(main, player, page, args);
|
||||
}
|
||||
|
||||
public abstract InventoryResult openInventory(KothPlugin main, Player player, int page, Object... args)
|
||||
throws InventoryOpenException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param event
|
||||
* @param plugin
|
||||
* @param player
|
||||
*/
|
||||
protected void onClose(InventoryCloseEvent event, KothPlugin plugin, Player player) {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param event
|
||||
* @param plugin
|
||||
* @param player
|
||||
*/
|
||||
protected void onDrag(InventoryDragEvent event, KothPlugin plugin, Player player) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected VInventory clone() {
|
||||
try {
|
||||
return (VInventory) getClass().newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
package fr.maxlego08.koth.inventory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import fr.maxlego08.koth.zcore.enums.EnumInventory;
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
import fr.maxlego08.koth.zcore.logger.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
|
||||
import fr.maxlego08.koth.KothPlugin;
|
||||
import fr.maxlego08.koth.exceptions.InventoryAlreadyExistException;
|
||||
import fr.maxlego08.koth.exceptions.InventoryOpenException;
|
||||
import fr.maxlego08.koth.listener.ListenerAdapter;
|
||||
import fr.maxlego08.koth.zcore.utils.inventory.InventoryResult;
|
||||
import fr.maxlego08.koth.zcore.utils.inventory.ItemButton;
|
||||
|
||||
public class ZInventoryManager extends ListenerAdapter {
|
||||
|
||||
private final Map<Integer, VInventory> inventories = new HashMap<>();
|
||||
private final Map<UUID, VInventory> playerInventories = new HashMap<>();
|
||||
private final KothPlugin plugin;
|
||||
|
||||
/**
|
||||
* @param plugin
|
||||
*/
|
||||
public ZInventoryManager(KothPlugin plugin) {
|
||||
super();
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void sendLog() {
|
||||
plugin.getLog().log("Loading " + this.inventories.size() + " inventories", Logger.LogType.SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to record an inventory If the inventory ID already exists then
|
||||
* an exception will be throw
|
||||
*
|
||||
* @param enumInventory
|
||||
* @param inventory
|
||||
*/
|
||||
public void registerInventory(EnumInventory enumInventory, VInventory inventory) {
|
||||
if (!this.inventories.containsKey(enumInventory.getId())) {
|
||||
this.inventories.put(enumInventory.getId(), inventory);
|
||||
} else {
|
||||
throw new InventoryAlreadyExistException("Inventory with id " + inventory.getId() + " already exist !");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to open an inventory
|
||||
*
|
||||
* @param enumInventory
|
||||
* - Inventory enum for get the ID
|
||||
* @param player
|
||||
* - Player that will open the inventory
|
||||
* @param page
|
||||
* - The inventory page
|
||||
* @param objects
|
||||
* - The arguments used to make the inventory work
|
||||
*/
|
||||
public void createInventory(EnumInventory enumInventory, Player player, int page, Object... objects) {
|
||||
this.createInventory(enumInventory.getId(), player, page, objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to open an inventory When opening the inventory will be cloned
|
||||
*
|
||||
* @param id
|
||||
* - Inventory ID
|
||||
* @param player
|
||||
* - Player that will open the inventory
|
||||
* @param page
|
||||
* - The inventory page
|
||||
* @param objects
|
||||
* - The arguments used to make the inventory work
|
||||
*/
|
||||
public void createInventory(int id, Player player, int page, Object... objects) {
|
||||
Optional<VInventory> optional = this.getInventory(id);
|
||||
|
||||
if (!optional.isPresent()) {
|
||||
message(player, Message.INVENTORY_CLONE_NULL, "%id%", id);
|
||||
return;
|
||||
}
|
||||
|
||||
VInventory inventory = optional.get();
|
||||
|
||||
// We need to clone the object to have one object per open inventory
|
||||
// An inventory will remain open for several seconds, during this time
|
||||
// the inventories of the invary must be correctly saved according to
|
||||
// the player.
|
||||
VInventory clonedInventory = inventory.clone();
|
||||
|
||||
if (clonedInventory == null) {
|
||||
message(player, Message.INVENTORY_CLONE_NULL, "%id%", id);
|
||||
return;
|
||||
}
|
||||
|
||||
clonedInventory.setId(id);
|
||||
try {
|
||||
InventoryResult result = clonedInventory.preOpenInventory(plugin, player, page, objects);
|
||||
if (result.equals(InventoryResult.SUCCESS)) {
|
||||
player.openInventory(clonedInventory.getInventory());
|
||||
playerInventories.put(player.getUniqueId(), clonedInventory);
|
||||
} else if (result.equals(InventoryResult.ERROR)) {
|
||||
message(player, Message.INVENTORY_OPEN_ERROR, "%id%", id);
|
||||
}
|
||||
} catch (InventoryOpenException e) {
|
||||
message(player, Message.INVENTORY_OPEN_ERROR, "%id%", id);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void createInventory(VInventory parent, Player player) {
|
||||
createInventory(parent.getId(), player, parent.getPage(), parent.getObjets());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInventoryClick(InventoryClickEvent event, Player player) {
|
||||
if (event.getClickedInventory() == null)
|
||||
return;
|
||||
if (event.getWhoClicked() instanceof Player) {
|
||||
if (!exist(player))
|
||||
return;
|
||||
VInventory gui = playerInventories.get(player.getUniqueId());
|
||||
if (gui.getGuiName() == null || gui.getGuiName().length() == 0) {
|
||||
Logger.info("An error has occurred with the menu ! " + gui.getClass().getName());
|
||||
return;
|
||||
}
|
||||
if (event.getView() != null && gui.getPlayer().equals(player)
|
||||
&& event.getView().getTitle().equals(gui.getGuiName())) {
|
||||
|
||||
event.setCancelled(gui.isDisableClick());
|
||||
|
||||
if (event.getClickedInventory().getType().equals(InventoryType.PLAYER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemButton button = gui.getItems().getOrDefault(event.getSlot(), null);
|
||||
if (button != null)
|
||||
button.onClick(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInventoryClose(InventoryCloseEvent event, Player player) {
|
||||
if (!exist(player))
|
||||
return;
|
||||
VInventory inventory = playerInventories.get(player.getUniqueId());
|
||||
remove(player);
|
||||
inventory.onClose(event, plugin, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInventoryDrag(InventoryDragEvent event, Player player) {
|
||||
if (event.getWhoClicked() instanceof Player) {
|
||||
if (!exist(player))
|
||||
return;
|
||||
playerInventories.get(player.getUniqueId()).onDrag(event, plugin, player);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean exist(Player player) {
|
||||
return playerInventories.containsKey(player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to remove the player from the list of open inventories
|
||||
*
|
||||
* @param player
|
||||
* - Player who will close the inventory
|
||||
*/
|
||||
public void remove(Player player) {
|
||||
if (playerInventories.containsKey(player.getUniqueId())) {
|
||||
playerInventories.remove(player.getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* - Inventory Id
|
||||
* @return Optional - Allows to return the inventory in an optional
|
||||
*/
|
||||
private Optional<VInventory> getInventory(int id) {
|
||||
return Optional.ofNullable(inventories.getOrDefault(id, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ids
|
||||
*/
|
||||
public void updateAllPlayer(int... ids) {
|
||||
for (int currentId : ids) {
|
||||
updateAllPlayer(currentId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
*/
|
||||
public void closeAllPlayer(int... ids) {
|
||||
for (int currentId : ids) {
|
||||
closeAllPlayer(currentId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
*/
|
||||
private void updateAllPlayer(int id) {
|
||||
Iterator<VInventory> iterator = this.playerInventories.values().stream().filter(inv -> inv.getId() == id)
|
||||
.collect(Collectors.toList()).iterator();
|
||||
while (iterator.hasNext()) {
|
||||
VInventory inventory = iterator.next();
|
||||
Bukkit.getScheduler().runTask(this.plugin, () -> createInventory(inventory, inventory.getPlayer()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
*/
|
||||
private void closeAllPlayer(int id) {
|
||||
Iterator<VInventory> iterator = this.playerInventories.values().stream().filter(inv -> inv.getId() == id)
|
||||
.collect(Collectors.toList()).iterator();
|
||||
while (iterator.hasNext()) {
|
||||
VInventory inventory = iterator.next();
|
||||
inventory.getPlayer().closeInventory();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
package fr.maxlego08.koth.listener;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.inventory.CraftItemEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerGameModeChangeEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerPickupItemEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import fr.maxlego08.koth.KothPlugin;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class AdapterListener extends ZUtils implements Listener {
|
||||
|
||||
private final KothPlugin plugin;
|
||||
|
||||
public AdapterListener(KothPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onConnect(PlayerJoinEvent event) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onConnect(event, event.getPlayer()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent event) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onQuit(event, event.getPlayer()));
|
||||
}
|
||||
|
||||
/*
|
||||
* @EventHandler public void onMove(PlayerMoveEvent event) {
|
||||
* this.plugin.getListenerAdapters().forEach(adapter ->
|
||||
* adapter.onMove(event, event.getPlayer())); if
|
||||
* (event.getFrom().getBlockX() >> 1 == event.getTo().getBlockX() >> 1 &&
|
||||
* event.getFrom().getBlockZ() >> 1 == event.getTo().getBlockZ() >> 1 &&
|
||||
* event.getFrom().getWorld() == event.getTo().getWorld()) return;
|
||||
* this.plugin.getListenerAdapters().forEach(adapter ->
|
||||
* adapter.onPlayerWalk(event, event.getPlayer(), 1)); }
|
||||
*/
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
this.plugin.getListenerAdapters()
|
||||
.forEach(adapter -> adapter.onInventoryClick(event, (Player) event.getWhoClicked()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onBlockBreak(event, event.getPlayer()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onBlockPlace(event, event.getPlayer()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityDeath(EntityDeathEvent event) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onEntityDeath(event, event.getEntity()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInteract(PlayerInteractEvent event) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onInteract(event, event.getPlayer()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerTalk(AsyncPlayerChatEvent event) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onPlayerTalk(event, event.getMessage()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onCraftItem(CraftItemEvent event) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onCraftItem(event));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDrag(InventoryDragEvent event) {
|
||||
this.plugin.getListenerAdapters()
|
||||
.forEach(adapter -> adapter.onInventoryDrag(event, (Player) event.getWhoClicked()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onClose(InventoryCloseEvent event) {
|
||||
this.plugin.getListenerAdapters()
|
||||
.forEach(adapter -> adapter.onInventoryClose(event, (Player) event.getPlayer()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onCommand(PlayerCommandPreprocessEvent event) {
|
||||
this.plugin.getListenerAdapters()
|
||||
.forEach(adapter -> adapter.onCommand(event, event.getPlayer(), event.getMessage()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onGamemodeChange(PlayerGameModeChangeEvent event) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onGamemodeChange(event, event.getPlayer()));
|
||||
}
|
||||
|
||||
/*
|
||||
* @EventHandler public void onDrop(PlayerDropItemEvent event) {
|
||||
* this.plugin.getListenerAdapters().forEach(adapter ->
|
||||
* adapter.onDrop(event, event.getPlayer())); if (!Config.useItemFallEvent)
|
||||
* return; Item item = event.getItemDrop(); AtomicBoolean hasSendEvent = new
|
||||
* AtomicBoolean(false); scheduleFix(100, (task, isActive) -> { if
|
||||
* (!isActive) return; this.plugin.getListenerAdapters().forEach(adapter ->
|
||||
* adapter.onItemMove(event, event.getPlayer(), item, item.getLocation(),
|
||||
* item.getLocation().getBlock())); if (item.isOnGround() &&
|
||||
* !hasSendEvent.get()) { task.cancel(); hasSendEvent.set(true);
|
||||
* this.plugin.getListenerAdapters().forEach( adapter ->
|
||||
* adapter.onItemisOnGround(event, event.getPlayer(), item,
|
||||
* item.getLocation())); } }); }
|
||||
*/
|
||||
|
||||
@EventHandler
|
||||
public void onPick(PlayerPickupItemEvent event) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onPickUp(event, event.getPlayer()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onMobSpawn(CreatureSpawnEvent event) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onMobSpawn(event));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDamage(EntityDamageByEntityEvent event) {
|
||||
|
||||
if (event.getEntity() instanceof LivingEntity && event.getDamager() instanceof LivingEntity) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onDamageByEntity(event, event.getCause(),
|
||||
event.getDamage(), (LivingEntity) event.getDamager(), (LivingEntity) event.getEntity()));
|
||||
}
|
||||
|
||||
if (event.getEntity() instanceof Player && event.getDamager() instanceof Player) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onPlayerDamagaByPlayer(event, event.getCause(),
|
||||
event.getDamage(), (Player) event.getDamager(), (Player) event.getEntity()));
|
||||
}
|
||||
|
||||
if (event.getEntity() instanceof Player && event.getDamager() instanceof Projectile) {
|
||||
this.plugin.getListenerAdapters().forEach(adapter -> adapter.onPlayerDamagaByArrow(event, event.getCause(),
|
||||
event.getDamage(), (Projectile) event.getDamager(), (Player) event.getEntity()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package fr.maxlego08.koth.listener;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||
import org.bukkit.event.inventory.CraftItemEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||
import org.bukkit.event.player.PlayerGameModeChangeEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerPickupItemEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class ListenerAdapter extends ZUtils {
|
||||
|
||||
protected void onConnect(PlayerJoinEvent event, Player player) {
|
||||
}
|
||||
|
||||
protected void onQuit(PlayerQuitEvent event, Player player) {
|
||||
}
|
||||
|
||||
protected void onMove(PlayerMoveEvent event, Player player) {
|
||||
}
|
||||
|
||||
protected void onInventoryClick(InventoryClickEvent event, Player player) {
|
||||
}
|
||||
|
||||
protected void onInventoryClose(InventoryCloseEvent event, Player player) {
|
||||
}
|
||||
|
||||
protected void onInventoryDrag(InventoryDragEvent event, Player player) {
|
||||
}
|
||||
|
||||
protected void onBlockBreak(BlockBreakEvent event, Player player) {
|
||||
}
|
||||
|
||||
protected void onBlockPlace(BlockPlaceEvent event, Player player) {
|
||||
}
|
||||
|
||||
protected void onEntityDeath(EntityDeathEvent event, Entity entity) {
|
||||
}
|
||||
|
||||
protected void onInteract(PlayerInteractEvent event, Player player) {
|
||||
}
|
||||
|
||||
protected void onPlayerTalk(AsyncPlayerChatEvent event, String message) {
|
||||
}
|
||||
|
||||
protected void onCraftItem(CraftItemEvent event) {
|
||||
}
|
||||
|
||||
protected void onCommand(PlayerCommandPreprocessEvent event, Player player, String message) {
|
||||
}
|
||||
|
||||
protected void onGamemodeChange(PlayerGameModeChangeEvent event, Player player) {
|
||||
}
|
||||
|
||||
protected void onDrop(PlayerDropItemEvent event, Player player) {
|
||||
}
|
||||
|
||||
protected void onPickUp(PlayerPickupItemEvent event, Player player) {
|
||||
}
|
||||
|
||||
protected void onMobSpawn(CreatureSpawnEvent event) {
|
||||
}
|
||||
|
||||
protected void onDamageByEntity(EntityDamageByEntityEvent event, DamageCause cause, double damage, LivingEntity damager,
|
||||
LivingEntity entity) {
|
||||
}
|
||||
|
||||
protected void onPlayerDamagaByPlayer(EntityDamageByEntityEvent event, DamageCause cause, double damage,
|
||||
Player damager, Player entity) {
|
||||
}
|
||||
|
||||
protected void onPlayerDamagaByArrow(EntityDamageByEntityEvent event, DamageCause cause, double damage,
|
||||
Projectile damager, Player entity) {
|
||||
}
|
||||
|
||||
protected void onItemisOnGround(PlayerDropItemEvent event, Player player, Item item, Location location) {
|
||||
}
|
||||
|
||||
protected void onItemMove(PlayerDropItemEvent event, Player player, Item item, Location location, Block block) {
|
||||
}
|
||||
|
||||
protected void onPlayerWalk(PlayerMoveEvent event, Player player, int i) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package fr.maxlego08.koth.placeholder;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class AutoPlaceholder {
|
||||
|
||||
private final String startWith;
|
||||
private final ReturnBiConsumer<Player, String, String> biConsumer;
|
||||
|
||||
/**
|
||||
* @param startWith
|
||||
* @param biConsumer
|
||||
*/
|
||||
public AutoPlaceholder(String startWith, ReturnBiConsumer<Player, String, String> biConsumer) {
|
||||
super();
|
||||
this.startWith = startWith;
|
||||
this.biConsumer = biConsumer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the startWith
|
||||
*/
|
||||
public String getStartWith() {
|
||||
return startWith;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the biConsumer
|
||||
*/
|
||||
public ReturnBiConsumer<Player, String, String> getBiConsumer() {
|
||||
return biConsumer;
|
||||
}
|
||||
|
||||
public String accept(Player player, String value) {
|
||||
return this.biConsumer.accept(player, value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package fr.maxlego08.koth.placeholder;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
|
||||
public class DistantPlaceholder extends PlaceholderExpansion {
|
||||
|
||||
private final LocalPlaceholder placeholder;
|
||||
|
||||
/**
|
||||
* @param placeholder
|
||||
*/
|
||||
public DistantPlaceholder(LocalPlaceholder placeholder) {
|
||||
super();
|
||||
this.placeholder = placeholder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
return this.placeholder.getPlugin().getDescription().getAuthors().get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return this.placeholder.getPrefix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return this.placeholder.getPlugin().getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persist() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onPlaceholderRequest(Player p, String params) {
|
||||
return this.placeholder.onRequest(p, params);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package fr.maxlego08.koth.placeholder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.maxlego08.koth.KothPlugin;
|
||||
|
||||
public class LocalPlaceholder {
|
||||
|
||||
private KothPlugin plugin;
|
||||
private String prefix = "template";
|
||||
private final Pattern pattern = Pattern.compile("[%]([^%]+)[%]");
|
||||
private final List<AutoPlaceholder> autoPlaceholders = new ArrayList<AutoPlaceholder>();
|
||||
|
||||
/**
|
||||
* Set plugin instance
|
||||
*
|
||||
* @param plugin
|
||||
*/
|
||||
public void setPlugin(KothPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* static Singleton instance.
|
||||
*/
|
||||
private static volatile LocalPlaceholder instance;
|
||||
|
||||
/**
|
||||
* Private constructor for singleton.
|
||||
*/
|
||||
private LocalPlaceholder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a singleton instance of ZPlaceholderApi.
|
||||
*/
|
||||
public static LocalPlaceholder getInstance() {
|
||||
// Double lock for thread safety.
|
||||
if (instance == null) {
|
||||
synchronized (LocalPlaceholder.class) {
|
||||
if (instance == null) {
|
||||
instance = new LocalPlaceholder();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player
|
||||
* @param displayName
|
||||
* @return
|
||||
*/
|
||||
public String setPlaceholders(Player player, String placeholder) {
|
||||
|
||||
if (placeholder == null || !placeholder.contains("%")) {
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
final String realPrefix = this.prefix + "_";
|
||||
|
||||
Matcher matcher = this.pattern.matcher(placeholder);
|
||||
while (matcher.find()) {
|
||||
String stringPlaceholder = matcher.group(0);
|
||||
String regex = matcher.group(1).replace(realPrefix, "");
|
||||
String replace = this.onRequest(player, regex);
|
||||
if (replace != null) {
|
||||
placeholder = placeholder.replace(stringPlaceholder, replace);
|
||||
}
|
||||
}
|
||||
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player
|
||||
* @param lore
|
||||
* @return
|
||||
*/
|
||||
public List<String> setPlaceholders(Player player, List<String> lore) {
|
||||
return lore == null ? null
|
||||
: lore.stream().map(e -> e = setPlaceholders(player, e)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom placeholder
|
||||
*
|
||||
* @param player
|
||||
* @param string
|
||||
* @return
|
||||
*/
|
||||
public String onRequest(Player player, String string) {
|
||||
|
||||
Optional<AutoPlaceholder> optional = this.autoPlaceholders.stream()
|
||||
.filter(e -> string.startsWith(e.getStartWith())).findFirst();
|
||||
if (optional.isPresent()) {
|
||||
|
||||
AutoPlaceholder autoPlaceholder = optional.get();
|
||||
String value = string.replace(autoPlaceholder.getStartWith(), "");
|
||||
return autoPlaceholder.accept(player, value);
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void register(String startWith, ReturnBiConsumer<Player, String, String> biConsumer) {
|
||||
this.autoPlaceholders.add(new AutoPlaceholder(startWith, biConsumer));
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public KothPlugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package fr.maxlego08.koth.placeholder;
|
||||
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface Placeholder {
|
||||
|
||||
static Placeholder getPlaceholder() {
|
||||
return LP.placeholder == null ? LP.placeholder = (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null ? new Api() : new Local()) : LP.placeholder;
|
||||
}
|
||||
|
||||
String setPlaceholders(Player player, String string);
|
||||
|
||||
List<String> setPlaceholders(Player player, List<String> list);
|
||||
|
||||
class Api implements Placeholder {
|
||||
|
||||
public Api() {
|
||||
PlaceholderExpansion expansion = new DistantPlaceholder(LocalPlaceholder.getInstance());
|
||||
expansion.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setPlaceholders(Player player, String string) {
|
||||
return PlaceholderAPI.setPlaceholders(player, string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> setPlaceholders(Player player, List<String> list) {
|
||||
return PlaceholderAPI.setPlaceholders(player, list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Local implements Placeholder {
|
||||
|
||||
@Override
|
||||
public String setPlaceholders(Player player, String string) {
|
||||
return LocalPlaceholder.getInstance().setPlaceholders(player, string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> setPlaceholders(Player player, List<String> list) {
|
||||
return LocalPlaceholder.getInstance().setPlaceholders(player, list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class LP {
|
||||
public static Placeholder placeholder;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package fr.maxlego08.koth.placeholder;
|
||||
@FunctionalInterface
|
||||
public interface ReturnBiConsumer<T, G, C> {
|
||||
|
||||
C accept(T t, G g);
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package fr.maxlego08.koth.save;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.storage.Persist;
|
||||
import fr.maxlego08.koth.zcore.utils.storage.Savable;
|
||||
|
||||
public class Config implements Savable {
|
||||
|
||||
public static boolean enableDebug = true;
|
||||
public static boolean enableDebugTime = false;
|
||||
|
||||
/**
|
||||
* static Singleton instance.
|
||||
*/
|
||||
private static volatile Config instance;
|
||||
|
||||
|
||||
/**
|
||||
* Private constructor for singleton.
|
||||
*/
|
||||
private Config() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a singleton instance of Config.
|
||||
*/
|
||||
public static Config getInstance() {
|
||||
// Double lock for thread safety.
|
||||
if (instance == null) {
|
||||
synchronized (Config.class) {
|
||||
if (instance == null) {
|
||||
instance = new Config();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void save(Persist persist) {
|
||||
persist.save(getInstance());
|
||||
}
|
||||
|
||||
public void load(Persist persist) {
|
||||
persist.loadOrSaveDefault(getInstance(), Config.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
package fr.maxlego08.koth.save;
|
||||
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
import fr.maxlego08.koth.zcore.enums.MessageType;
|
||||
import fr.maxlego08.koth.zcore.logger.Logger;
|
||||
import fr.maxlego08.koth.zcore.utils.storage.Persist;
|
||||
import fr.maxlego08.koth.zcore.utils.storage.Savable;
|
||||
import fr.maxlego08.koth.zcore.utils.yaml.YamlUtils;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* The MessageLoader class extends YamlUtils and implements Savable to manage message configurations.
|
||||
* This class is responsible for loading and saving custom messages to a YAML file for a Bukkit plugin.
|
||||
*/
|
||||
public class MessageLoader extends YamlUtils implements Savable {
|
||||
|
||||
private final List<Message> loadedMessages = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Constructor for MessageLoader.
|
||||
*
|
||||
* @param plugin The JavaPlugin instance associated with this loader.
|
||||
*/
|
||||
public MessageLoader(JavaPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves messages to the configuration file.
|
||||
*
|
||||
* @param persist The persist instance used for saving the data.
|
||||
*/
|
||||
@Override
|
||||
public void save(Persist persist) {
|
||||
|
||||
if (persist != null) return;
|
||||
|
||||
File file = new File(plugin.getDataFolder(), "messages.yml");
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
YamlConfiguration configuration = getConfig(file);
|
||||
for (Message message : Message.values()) {
|
||||
|
||||
if (!message.isUse()) continue;
|
||||
|
||||
String path = "messages." + message.name().toLowerCase().replace("_", ".");
|
||||
|
||||
if (message.getType() != MessageType.TCHAT) {
|
||||
configuration.set(path + ".type", message.getType().name());
|
||||
}
|
||||
if (message.getType().equals(MessageType.TCHAT) || message.getType().equals(MessageType.ACTION) || message.getType().equals(MessageType.CENTER)) {
|
||||
|
||||
if (message.isMessage()) {
|
||||
configuration.set(path + ".messages", colorReverse(message.getMessages()));
|
||||
} else {
|
||||
configuration.set(path + ".message", colorReverse(message.getMessage()));
|
||||
}
|
||||
} else if (message.getType().equals(MessageType.TITLE)) {
|
||||
|
||||
configuration.set(path + ".title", colorReverse(message.getTitle()));
|
||||
configuration.set(path + ".subtitle", colorReverse(message.getSubTitle()));
|
||||
configuration.set(path + ".fadeInTime", message.getStart());
|
||||
configuration.set(path + ".showTime", message.getTime());
|
||||
configuration.set(path + ".fadeOutTime", message.getEnd());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
configuration.save(file);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads messages from the configuration file.
|
||||
*
|
||||
* @param persist The persist instance used for loading the data.
|
||||
*/
|
||||
@Override
|
||||
public void load(Persist persist) {
|
||||
|
||||
File file = new File(plugin.getDataFolder(), "messages.yml");
|
||||
if (!file.exists()) {
|
||||
this.save(null);
|
||||
return;
|
||||
}
|
||||
|
||||
YamlConfiguration configuration = getConfig(file);
|
||||
|
||||
if (!configuration.contains("messages")) {
|
||||
this.save(null);
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadedMessages.clear();
|
||||
|
||||
for (String key : configuration.getConfigurationSection("messages.").getKeys(false)) {
|
||||
loadMessage(configuration, "messages." + key);
|
||||
}
|
||||
|
||||
boolean canSave = false;
|
||||
for (Message message : Message.values()) {
|
||||
|
||||
if (!this.loadedMessages.contains(message) && message.isUse()) {
|
||||
canSave = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Allows you to save new parameters
|
||||
if (canSave) {
|
||||
Logger.info("Save the message file, add new settings");
|
||||
this.save(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a single message from the given YAML configuration.
|
||||
*
|
||||
* @param configuration The YAML configuration to load the message from.
|
||||
* @param key The key under which the message is stored.
|
||||
*/
|
||||
private void loadMessage(YamlConfiguration configuration, String key) {
|
||||
try {
|
||||
|
||||
MessageType messageType = MessageType.valueOf(configuration.getString(key + ".type", "TCHAT").toUpperCase());
|
||||
String keys = key.substring("messages.".length());
|
||||
Message enumMessage = Message.valueOf(keys.toUpperCase().replace(".", "_"));
|
||||
enumMessage.setType(messageType);
|
||||
|
||||
this.loadedMessages.add(enumMessage);
|
||||
|
||||
switch (messageType) {
|
||||
case ACTION: {
|
||||
String message = configuration.getString(key + ".message");
|
||||
enumMessage.setMessage(color(message));
|
||||
break;
|
||||
}
|
||||
case CENTER:
|
||||
case TCHAT: {
|
||||
if (configuration.contains(key + ".messages")) {
|
||||
List<String> messages = configuration.getStringList(key + ".messages");
|
||||
enumMessage.setMessages(color(messages));
|
||||
enumMessage.setMessage(null);
|
||||
} else {
|
||||
String message = configuration.getString(key + ".message");
|
||||
enumMessage.setMessage(color(message));
|
||||
enumMessage.setMessages(new ArrayList<String>());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TITLE: {
|
||||
String title = configuration.getString(key + ".title");
|
||||
String subtitle = configuration.getString(key + ".subtitle");
|
||||
int fadeInTime = configuration.getInt(key + ".fadeInTime");
|
||||
int showTime = configuration.getInt(key + ".showTime");
|
||||
int fadeOutTime = configuration.getInt(key + ".fadeOutTime");
|
||||
Map<String, Object> titles = new HashMap<String, Object>();
|
||||
titles.put("title", color(title));
|
||||
titles.put("subtitle", color(subtitle));
|
||||
titles.put("start", fadeInTime);
|
||||
titles.put("time", showTime);
|
||||
titles.put("end", fadeOutTime);
|
||||
titles.put("isUse", true);
|
||||
enumMessage.setTitles(titles);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
if (configuration.isConfigurationSection(key + ".")) {
|
||||
for (String newKey : configuration.getConfigurationSection(key + ".").getKeys(false)) {
|
||||
loadMessage(configuration, key + "." + newKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,629 @@
|
|||
/*
|
||||
* This file is part of FastBoard, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2019-2021 MrMicky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fr.maxlego08.koth.scoreboard;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* Lightweight packet-based scoreboard API for Bukkit plugins.
|
||||
* It can be safely used asynchronously as everything is at packet level.
|
||||
* <p>
|
||||
* The project is on <a href="https://github.com/MrMicky-FR/FastBoard">GitHub</a>.
|
||||
*
|
||||
* @author MrMicky
|
||||
* @version 1.2.0
|
||||
*/
|
||||
public class FastBoard {
|
||||
|
||||
private static final Map<Class<?>, Field[]> PACKETS = new HashMap<>(8);
|
||||
private static final String[] COLOR_CODES = Arrays.stream(ChatColor.values())
|
||||
.map(Object::toString)
|
||||
.toArray(String[]::new);
|
||||
private static final VersionType VERSION_TYPE;
|
||||
// Packets and components
|
||||
private static final Class<?> CHAT_COMPONENT_CLASS;
|
||||
private static final Class<?> CHAT_FORMAT_ENUM;
|
||||
private static final Object EMPTY_MESSAGE;
|
||||
private static final Object RESET_FORMATTING;
|
||||
private static final MethodHandle MESSAGE_FROM_STRING;
|
||||
private static final MethodHandle PLAYER_CONNECTION;
|
||||
private static final MethodHandle SEND_PACKET;
|
||||
private static final MethodHandle PLAYER_GET_HANDLE;
|
||||
// Scoreboard packets
|
||||
private static final FastReflection.PacketConstructor PACKET_SB_OBJ;
|
||||
private static final FastReflection.PacketConstructor PACKET_SB_DISPLAY_OBJ;
|
||||
private static final FastReflection.PacketConstructor PACKET_SB_SCORE;
|
||||
private static final FastReflection.PacketConstructor PACKET_SB_TEAM;
|
||||
private static final FastReflection.PacketConstructor PACKET_SB_SERIALIZABLE_TEAM;
|
||||
// Scoreboard enums
|
||||
private static final Class<?> ENUM_SB_HEALTH_DISPLAY;
|
||||
private static final Class<?> ENUM_SB_ACTION;
|
||||
private static final Object ENUM_SB_HEALTH_DISPLAY_INTEGER;
|
||||
private static final Object ENUM_SB_ACTION_CHANGE;
|
||||
private static final Object ENUM_SB_ACTION_REMOVE;
|
||||
|
||||
static {
|
||||
try {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
if (FastReflection.isRepackaged()) {
|
||||
VERSION_TYPE = VersionType.V1_17;
|
||||
} else if (FastReflection.nmsOptionalClass(null, "ScoreboardServer$Action").isPresent()) {
|
||||
VERSION_TYPE = VersionType.V1_13;
|
||||
} else if (FastReflection.nmsOptionalClass(null, "IScoreboardCriteria$EnumScoreboardHealthDisplay").isPresent()) {
|
||||
VERSION_TYPE = VersionType.V1_8;
|
||||
} else {
|
||||
VERSION_TYPE = VersionType.V1_7;
|
||||
}
|
||||
|
||||
String gameProtocolPackage = "network.protocol.game";
|
||||
Class<?> craftPlayerClass = FastReflection.obcClass("entity.CraftPlayer");
|
||||
Class<?> craftChatMessageClass = FastReflection.obcClass("util.CraftChatMessage");
|
||||
Class<?> entityPlayerClass = FastReflection.nmsClass("server.level", "EntityPlayer");
|
||||
Class<?> playerConnectionClass = FastReflection.nmsClass("server.network", "PlayerConnection");
|
||||
Class<?> packetClass = FastReflection.nmsClass("network.protocol", "Packet");
|
||||
Class<?> packetSbObjClass = FastReflection.nmsClass(gameProtocolPackage, "PacketPlayOutScoreboardObjective");
|
||||
Class<?> packetSbDisplayObjClass = FastReflection.nmsClass(gameProtocolPackage, "PacketPlayOutScoreboardDisplayObjective");
|
||||
Class<?> packetSbScoreClass = FastReflection.nmsClass(gameProtocolPackage, "PacketPlayOutScoreboardScore");
|
||||
Class<?> packetSbTeamClass = FastReflection.nmsClass(gameProtocolPackage, "PacketPlayOutScoreboardTeam");
|
||||
Class<?> sbTeamClass = VersionType.V1_17.isHigherOrEqual()
|
||||
? FastReflection.innerClass(packetSbTeamClass, innerClass -> !innerClass.isEnum()) : null;
|
||||
Field playerConnectionField = Arrays.stream(entityPlayerClass.getFields())
|
||||
.filter(field -> field.getType().isAssignableFrom(playerConnectionClass))
|
||||
.findFirst().orElseThrow(NoSuchFieldException::new);
|
||||
|
||||
MESSAGE_FROM_STRING = lookup.unreflect(craftChatMessageClass.getMethod("fromString", String.class));
|
||||
CHAT_COMPONENT_CLASS = FastReflection.nmsClass("network.chat", "IChatBaseComponent");
|
||||
CHAT_FORMAT_ENUM = FastReflection.nmsClass(null, "EnumChatFormat");
|
||||
EMPTY_MESSAGE = Array.get(MESSAGE_FROM_STRING.invoke(""), 0);
|
||||
RESET_FORMATTING = FastReflection.enumValueOf(CHAT_FORMAT_ENUM, "RESET", 21);
|
||||
PLAYER_GET_HANDLE = lookup.findVirtual(craftPlayerClass, "getHandle", MethodType.methodType(entityPlayerClass));
|
||||
PLAYER_CONNECTION = lookup.unreflectGetter(playerConnectionField);
|
||||
SEND_PACKET = lookup.findVirtual(playerConnectionClass, "sendPacket", MethodType.methodType(void.class, packetClass));
|
||||
PACKET_SB_OBJ = FastReflection.findPacketConstructor(packetSbObjClass, lookup);
|
||||
PACKET_SB_DISPLAY_OBJ = FastReflection.findPacketConstructor(packetSbDisplayObjClass, lookup);
|
||||
PACKET_SB_SCORE = FastReflection.findPacketConstructor(packetSbScoreClass, lookup);
|
||||
PACKET_SB_TEAM = FastReflection.findPacketConstructor(packetSbTeamClass, lookup);
|
||||
PACKET_SB_SERIALIZABLE_TEAM = sbTeamClass == null ? null : FastReflection.findPacketConstructor(sbTeamClass, lookup);
|
||||
|
||||
for (Class<?> clazz : Arrays.asList(packetSbObjClass, packetSbDisplayObjClass, packetSbScoreClass, packetSbTeamClass, sbTeamClass)) {
|
||||
if (clazz == null) {
|
||||
continue;
|
||||
}
|
||||
Field[] fields = Arrays.stream(clazz.getDeclaredFields())
|
||||
.filter(field -> !Modifier.isStatic(field.getModifiers()))
|
||||
.toArray(Field[]::new);
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
PACKETS.put(clazz, fields);
|
||||
}
|
||||
|
||||
if (VersionType.V1_8.isHigherOrEqual()) {
|
||||
String enumSbActionClass = VersionType.V1_13.isHigherOrEqual()
|
||||
? "ScoreboardServer$Action"
|
||||
: "PacketPlayOutScoreboardScore$EnumScoreboardAction";
|
||||
ENUM_SB_HEALTH_DISPLAY = FastReflection.nmsClass("world.scores.criteria", "IScoreboardCriteria$EnumScoreboardHealthDisplay");
|
||||
ENUM_SB_ACTION = FastReflection.nmsClass("server", enumSbActionClass);
|
||||
ENUM_SB_HEALTH_DISPLAY_INTEGER = FastReflection.enumValueOf(ENUM_SB_HEALTH_DISPLAY, "INTEGER", 0);
|
||||
ENUM_SB_ACTION_CHANGE = FastReflection.enumValueOf(ENUM_SB_ACTION, "CHANGE", 0);
|
||||
ENUM_SB_ACTION_REMOVE = FastReflection.enumValueOf(ENUM_SB_ACTION, "REMOVE", 1);
|
||||
} else {
|
||||
ENUM_SB_HEALTH_DISPLAY = null;
|
||||
ENUM_SB_ACTION = null;
|
||||
ENUM_SB_HEALTH_DISPLAY_INTEGER = null;
|
||||
ENUM_SB_ACTION_CHANGE = null;
|
||||
ENUM_SB_ACTION_REMOVE = null;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
throw new ExceptionInInitializerError(t);
|
||||
}
|
||||
}
|
||||
|
||||
private final Player player;
|
||||
private final String id;
|
||||
|
||||
private final List<String> lines = new ArrayList<>();
|
||||
private String title = ChatColor.RESET.toString();
|
||||
|
||||
private boolean deleted = false;
|
||||
|
||||
/**
|
||||
* Creates a new FastBoard.
|
||||
*
|
||||
* @param player the owner of the scoreboard
|
||||
*/
|
||||
public FastBoard(Player player) {
|
||||
this.player = Objects.requireNonNull(player, "player");
|
||||
this.id = "fb-" + Integer.toHexString(ThreadLocalRandom.current().nextInt());
|
||||
|
||||
try {
|
||||
sendObjectivePacket(ObjectiveMode.CREATE);
|
||||
sendDisplayObjectivePacket();
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Unable to create scoreboard", t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scoreboard title.
|
||||
*
|
||||
* @return the scoreboard title
|
||||
*/
|
||||
public String getTitle() {
|
||||
return this.title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the scoreboard title.
|
||||
*
|
||||
* @param title the new scoreboard title
|
||||
* @throws IllegalArgumentException if the title is longer than 32 chars on 1.12 or lower
|
||||
* @throws IllegalStateException if {@link #delete()} was call before
|
||||
*/
|
||||
public void updateTitle(String title) {
|
||||
if (this.title.equals(Objects.requireNonNull(title, "title"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!VersionType.V1_13.isHigherOrEqual() && title.length() > 32) {
|
||||
throw new IllegalArgumentException("Title is longer than 32 chars");
|
||||
}
|
||||
|
||||
this.title = title;
|
||||
|
||||
try {
|
||||
sendObjectivePacket(ObjectiveMode.UPDATE);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Unable to update scoreboard title", t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scoreboard lines.
|
||||
*
|
||||
* @return the scoreboard lines
|
||||
*/
|
||||
public List<String> getLines() {
|
||||
return new ArrayList<>(this.lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the specified scoreboard line.
|
||||
*
|
||||
* @param line the line number
|
||||
* @return the line
|
||||
* @throws IndexOutOfBoundsException if the line is higher than {@code size}
|
||||
*/
|
||||
public String getLine(int line) {
|
||||
checkLineNumber(line, true, false);
|
||||
|
||||
return this.lines.get(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a single scoreboard line.
|
||||
*
|
||||
* @param line the line number
|
||||
* @param text the new line text
|
||||
* @throws IndexOutOfBoundsException if the line is higher than {@link #size() size() + 1}
|
||||
*/
|
||||
public synchronized void updateLine(int line, String text) {
|
||||
checkLineNumber(line, false, true);
|
||||
|
||||
try {
|
||||
if (line < size()) {
|
||||
this.lines.set(line, text);
|
||||
|
||||
sendTeamPacket(getScoreByLine(line), TeamMode.UPDATE);
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> newLines = new ArrayList<>(this.lines);
|
||||
|
||||
if (line > size()) {
|
||||
for (int i = size(); i < line; i++) {
|
||||
newLines.add("");
|
||||
}
|
||||
}
|
||||
|
||||
newLines.add(text);
|
||||
|
||||
updateLines(newLines);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Unable to update scoreboard lines", t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a scoreboard line.
|
||||
*
|
||||
* @param line the line number
|
||||
*/
|
||||
public synchronized void removeLine(int line) {
|
||||
checkLineNumber(line, false, false);
|
||||
|
||||
if (line >= size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> newLines = new ArrayList<>(this.lines);
|
||||
newLines.remove(line);
|
||||
updateLines(newLines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all the scoreboard lines.
|
||||
*
|
||||
* @param lines the new lines
|
||||
* @throws IllegalArgumentException if one line is longer than 30 chars on 1.12 or lower
|
||||
* @throws IllegalStateException if {@link #delete()} was call before
|
||||
*/
|
||||
public void updateLines(String... lines) {
|
||||
updateLines(Arrays.asList(lines));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the lines of the scoreboard
|
||||
*
|
||||
* @param lines the new scoreboard lines
|
||||
* @throws IllegalArgumentException if one line is longer than 30 chars on 1.12 or lower
|
||||
* @throws IllegalStateException if {@link #delete()} was call before
|
||||
*/
|
||||
public synchronized void updateLines(Collection<String> lines) {
|
||||
Objects.requireNonNull(lines, "lines");
|
||||
checkLineNumber(lines.size(), false, true);
|
||||
|
||||
if (!VersionType.V1_13.isHigherOrEqual()) {
|
||||
int lineCount = 0;
|
||||
for (String s : lines) {
|
||||
if (s != null && s.length() > 30) {
|
||||
throw new IllegalArgumentException("Line " + lineCount + " is longer than 30 chars");
|
||||
}
|
||||
lineCount++;
|
||||
}
|
||||
}
|
||||
|
||||
List<String> oldLines = new ArrayList<>(this.lines);
|
||||
this.lines.clear();
|
||||
this.lines.addAll(lines);
|
||||
|
||||
int linesSize = this.lines.size();
|
||||
|
||||
try {
|
||||
if (oldLines.size() != linesSize) {
|
||||
List<String> oldLinesCopy = new ArrayList<>(oldLines);
|
||||
|
||||
if (oldLines.size() > linesSize) {
|
||||
for (int i = oldLinesCopy.size(); i > linesSize; i--) {
|
||||
sendTeamPacket(i - 1, TeamMode.REMOVE);
|
||||
sendScorePacket(i - 1, ScoreboardAction.REMOVE);
|
||||
|
||||
oldLines.remove(0);
|
||||
}
|
||||
} else {
|
||||
for (int i = oldLinesCopy.size(); i < linesSize; i++) {
|
||||
sendScorePacket(i, ScoreboardAction.CHANGE);
|
||||
sendTeamPacket(i, TeamMode.CREATE);
|
||||
|
||||
oldLines.add(oldLines.size() - i, getLineByScore(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < linesSize; i++) {
|
||||
if (!Objects.equals(getLineByScore(oldLines, i), getLineByScore(i))) {
|
||||
sendTeamPacket(i, TeamMode.UPDATE);
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Unable to update scoreboard lines", t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the player who has the scoreboard.
|
||||
*
|
||||
* @return current player for this FastBoard
|
||||
*/
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scoreboard id.
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if the scoreboard is deleted.
|
||||
*
|
||||
* @return true if the scoreboard is deleted
|
||||
*/
|
||||
public boolean isDeleted() {
|
||||
return this.deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scoreboard size (the number of lines).
|
||||
*
|
||||
* @return the size
|
||||
*/
|
||||
public int size() {
|
||||
return this.lines.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this FastBoard, and will remove the scoreboard for the associated player if he is online.
|
||||
* After this, all uses of {@link #updateLines} and {@link #updateTitle} will throws an {@link IllegalStateException}
|
||||
*
|
||||
* @throws IllegalStateException if this was already call before
|
||||
*/
|
||||
public void delete() {
|
||||
try {
|
||||
for (int i = 0; i < this.lines.size(); i++) {
|
||||
sendTeamPacket(i, TeamMode.REMOVE);
|
||||
}
|
||||
|
||||
sendObjectivePacket(ObjectiveMode.REMOVE);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Unable to delete scoreboard", t);
|
||||
}
|
||||
|
||||
this.deleted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the player has a prefix/suffix characters limit.
|
||||
* By default, it returns true only in 1.12 or lower.
|
||||
* This method can be overridden to fix compatibility with some versions support plugin.
|
||||
*
|
||||
* @return max length
|
||||
*/
|
||||
protected boolean hasLinesMaxLength() {
|
||||
return !VersionType.V1_13.isHigherOrEqual();
|
||||
}
|
||||
|
||||
private void checkLineNumber(int line, boolean checkInRange, boolean checkMax) {
|
||||
if (line < 0) {
|
||||
throw new IllegalArgumentException("Line number must be positive");
|
||||
}
|
||||
|
||||
if (checkInRange && line >= this.lines.size()) {
|
||||
throw new IllegalArgumentException("Line number must be under " + this.lines.size());
|
||||
}
|
||||
|
||||
if (checkMax && line >= COLOR_CODES.length - 1) {
|
||||
throw new IllegalArgumentException("Line number is too high: " + line);
|
||||
}
|
||||
}
|
||||
|
||||
private int getScoreByLine(int line) {
|
||||
return this.lines.size() - line - 1;
|
||||
}
|
||||
|
||||
private String getLineByScore(int score) {
|
||||
return getLineByScore(this.lines, score);
|
||||
}
|
||||
|
||||
private String getLineByScore(List<String> lines, int score) {
|
||||
return lines.get(lines.size() - score - 1);
|
||||
}
|
||||
|
||||
private void sendObjectivePacket(ObjectiveMode mode) throws Throwable {
|
||||
Object packet = PACKET_SB_OBJ.invoke();
|
||||
|
||||
setField(packet, String.class, this.id);
|
||||
setField(packet, int.class, mode.ordinal());
|
||||
|
||||
if (mode != ObjectiveMode.REMOVE) {
|
||||
setComponentField(packet, this.title, 1);
|
||||
|
||||
if (VersionType.V1_8.isHigherOrEqual()) {
|
||||
setField(packet, ENUM_SB_HEALTH_DISPLAY, ENUM_SB_HEALTH_DISPLAY_INTEGER);
|
||||
}
|
||||
} else if (VERSION_TYPE == VersionType.V1_7) {
|
||||
setField(packet, String.class, "", 1);
|
||||
}
|
||||
|
||||
sendPacket(packet);
|
||||
}
|
||||
|
||||
private void sendDisplayObjectivePacket() throws Throwable {
|
||||
Object packet = PACKET_SB_DISPLAY_OBJ.invoke();
|
||||
|
||||
setField(packet, int.class, 1); // Position (1: sidebar)
|
||||
setField(packet, String.class, this.id); // Score Name
|
||||
|
||||
sendPacket(packet);
|
||||
}
|
||||
|
||||
private void sendScorePacket(int score, ScoreboardAction action) throws Throwable {
|
||||
Object packet = PACKET_SB_SCORE.invoke();
|
||||
|
||||
setField(packet, String.class, COLOR_CODES[score], 0); // Player Name
|
||||
|
||||
if (VersionType.V1_8.isHigherOrEqual()) {
|
||||
setField(packet, ENUM_SB_ACTION, action == ScoreboardAction.REMOVE ? ENUM_SB_ACTION_REMOVE : ENUM_SB_ACTION_CHANGE);
|
||||
} else {
|
||||
setField(packet, int.class, action.ordinal(), 1); // Action
|
||||
}
|
||||
|
||||
if (action == ScoreboardAction.CHANGE) {
|
||||
setField(packet, String.class, this.id, 1); // Objective Name
|
||||
setField(packet, int.class, score); // Score
|
||||
}
|
||||
|
||||
sendPacket(packet);
|
||||
}
|
||||
|
||||
private void sendTeamPacket(int score, TeamMode mode) throws Throwable {
|
||||
if (mode == TeamMode.ADD_PLAYERS || mode == TeamMode.REMOVE_PLAYERS) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
int maxLength = hasLinesMaxLength() ? 16 : 1024;
|
||||
Object packet = PACKET_SB_TEAM.invoke();
|
||||
|
||||
setField(packet, String.class, this.id + ':' + score); // Team name
|
||||
setField(packet, int.class, mode.ordinal(), VERSION_TYPE == VersionType.V1_8 ? 1 : 0); // Update mode
|
||||
|
||||
if (mode == TeamMode.CREATE || mode == TeamMode.UPDATE) {
|
||||
String line = getLineByScore(score);
|
||||
String prefix;
|
||||
String suffix = null;
|
||||
|
||||
if (line == null || line.isEmpty()) {
|
||||
prefix = COLOR_CODES[score] + ChatColor.RESET;
|
||||
} else if (line.length() <= maxLength) {
|
||||
prefix = line;
|
||||
} else {
|
||||
// Prevent splitting color codes
|
||||
int index = line.charAt(maxLength - 1) == ChatColor.COLOR_CHAR ? (maxLength - 1) : maxLength;
|
||||
prefix = line.substring(0, index);
|
||||
String suffixTmp = line.substring(index);
|
||||
ChatColor chatColor = null;
|
||||
|
||||
if (suffixTmp.length() >= 2 && suffixTmp.charAt(0) == ChatColor.COLOR_CHAR) {
|
||||
chatColor = ChatColor.getByChar(suffixTmp.charAt(1));
|
||||
}
|
||||
|
||||
String color = ChatColor.getLastColors(prefix);
|
||||
boolean addColor = chatColor == null || chatColor.isFormat();
|
||||
|
||||
suffix = (addColor ? (color.isEmpty() ? ChatColor.RESET.toString() : color) : "") + suffixTmp;
|
||||
}
|
||||
|
||||
if (prefix.length() > maxLength || (suffix != null && suffix.length() > maxLength)) {
|
||||
// Something went wrong, just cut to prevent client crash/kick
|
||||
prefix = prefix.substring(0, maxLength);
|
||||
suffix = (suffix != null) ? suffix.substring(0, maxLength) : null;
|
||||
}
|
||||
|
||||
if (VersionType.V1_17.isHigherOrEqual()) {
|
||||
Object team = PACKET_SB_SERIALIZABLE_TEAM.invoke();
|
||||
// Since the packet is initialized with null values, we need to change more things.
|
||||
setComponentField(team, "", 0); // Display name
|
||||
setField(team, CHAT_FORMAT_ENUM, RESET_FORMATTING); // Color
|
||||
setComponentField(team, prefix, 1); // Prefix
|
||||
setComponentField(team, suffix == null ? "" : suffix, 2); // Suffix
|
||||
setField(team, String.class, "always", 0); // Visibility
|
||||
setField(team, String.class, "always", 1); // Collisions
|
||||
setField(packet, Optional.class, Optional.of(team));
|
||||
} else {
|
||||
setComponentField(packet, prefix, 2); // Prefix
|
||||
setComponentField(packet, suffix == null ? "" : suffix, 3); // Suffix
|
||||
setField(packet, String.class, "always", 4); // Visibility for 1.8+
|
||||
setField(packet, String.class, "always", 5); // Collisions for 1.9+
|
||||
}
|
||||
|
||||
if (mode == TeamMode.CREATE) {
|
||||
setField(packet, Collection.class, Collections.singletonList(COLOR_CODES[score])); // Players in the team
|
||||
}
|
||||
}
|
||||
|
||||
sendPacket(packet);
|
||||
}
|
||||
|
||||
private void sendPacket(Object packet) throws Throwable {
|
||||
if (this.deleted) {
|
||||
throw new IllegalStateException("This FastBoard is deleted");
|
||||
}
|
||||
|
||||
if (this.player.isOnline()) {
|
||||
Object entityPlayer = PLAYER_GET_HANDLE.invoke(this.player);
|
||||
Object playerConnection = PLAYER_CONNECTION.invoke(entityPlayer);
|
||||
SEND_PACKET.invoke(playerConnection, packet);
|
||||
}
|
||||
}
|
||||
|
||||
private void setField(Object object, Class<?> fieldType, Object value) throws ReflectiveOperationException {
|
||||
setField(object, fieldType, value, 0);
|
||||
}
|
||||
|
||||
private void setField(Object packet, Class<?> fieldType, Object value, int count) throws ReflectiveOperationException {
|
||||
int i = 0;
|
||||
for (Field field : PACKETS.get(packet.getClass())) {
|
||||
if (field.getType() == fieldType && count == i++) {
|
||||
field.set(packet, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setComponentField(Object packet, String value, int count) throws Throwable {
|
||||
if (!VersionType.V1_13.isHigherOrEqual()) {
|
||||
setField(packet, String.class, value, count);
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (Field field : PACKETS.get(packet.getClass())) {
|
||||
if ((field.getType() == String.class || field.getType() == CHAT_COMPONENT_CLASS) && count == i++) {
|
||||
field.set(packet, value.isEmpty() ? EMPTY_MESSAGE : Array.get(MESSAGE_FROM_STRING.invoke(value), 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ObjectiveMode {
|
||||
CREATE, REMOVE, UPDATE
|
||||
}
|
||||
|
||||
enum TeamMode {
|
||||
CREATE, REMOVE, UPDATE, ADD_PLAYERS, REMOVE_PLAYERS
|
||||
}
|
||||
|
||||
enum ScoreboardAction {
|
||||
CHANGE, REMOVE
|
||||
}
|
||||
|
||||
enum VersionType {
|
||||
V1_7, V1_8, V1_13, V1_17;
|
||||
|
||||
public boolean isHigherOrEqual() {
|
||||
return VERSION_TYPE.ordinal() >= ordinal();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* This file is part of FastBoard, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2019-2021 MrMicky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fr.maxlego08.koth.scoreboard;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Small reflection utility class to use CraftBukkit and NMS.
|
||||
*
|
||||
* @author MrMicky
|
||||
*/
|
||||
public final class FastReflection {
|
||||
|
||||
private static final String NM_PACKAGE = "net.minecraft";
|
||||
public static final String OBC_PACKAGE = "org.bukkit.craftbukkit";
|
||||
public static final String NMS_PACKAGE = NM_PACKAGE + ".server";
|
||||
|
||||
public static final String VERSION = Bukkit.getServer().getClass().getPackage().getName().substring(OBC_PACKAGE.length() + 1);
|
||||
|
||||
private static final MethodType VOID_METHOD_TYPE = MethodType.methodType(void.class);
|
||||
private static final boolean NMS_REPACKAGED = optionalClass(NM_PACKAGE + ".network.protocol.Packet").isPresent();
|
||||
|
||||
private static volatile Object theUnsafe;
|
||||
|
||||
private FastReflection() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static boolean isRepackaged() {
|
||||
return NMS_REPACKAGED;
|
||||
}
|
||||
|
||||
public static String nmsClassName(String post1_17package, String className) {
|
||||
if (NMS_REPACKAGED) {
|
||||
String classPackage = post1_17package == null ? NM_PACKAGE : NM_PACKAGE + '.' + post1_17package;
|
||||
return classPackage + '.' + className;
|
||||
}
|
||||
return NMS_PACKAGE + '.' + VERSION + '.' + className;
|
||||
}
|
||||
|
||||
public static Class<?> nmsClass(String post1_17package, String className) throws ClassNotFoundException {
|
||||
return Class.forName(nmsClassName(post1_17package, className));
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> nmsOptionalClass(String post1_17package, String className) {
|
||||
return optionalClass(nmsClassName(post1_17package, className));
|
||||
}
|
||||
|
||||
public static String obcClassName(String className) {
|
||||
return OBC_PACKAGE + '.' + VERSION + '.' + className;
|
||||
}
|
||||
|
||||
public static Class<?> obcClass(String className) throws ClassNotFoundException {
|
||||
return Class.forName(obcClassName(className));
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> obcOptionalClass(String className) {
|
||||
return optionalClass(obcClassName(className));
|
||||
}
|
||||
|
||||
public static Optional<Class<?>> optionalClass(String className) {
|
||||
try {
|
||||
return Optional.of(Class.forName(className));
|
||||
} catch (ClassNotFoundException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public static Object enumValueOf(Class<?> enumClass, String enumName) {
|
||||
return Enum.valueOf(enumClass.asSubclass(Enum.class), enumName);
|
||||
}
|
||||
|
||||
public static Object enumValueOf(Class<?> enumClass, String enumName, int fallbackOrdinal) {
|
||||
try {
|
||||
return enumValueOf(enumClass, enumName);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Object[] constants = enumClass.getEnumConstants();
|
||||
if (constants.length > fallbackOrdinal) {
|
||||
return constants[fallbackOrdinal];
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
static Class<?> innerClass(Class<?> parentClass, Predicate<Class<?>> classPredicate) throws ClassNotFoundException {
|
||||
for (Class<?> innerClass : parentClass.getDeclaredClasses()) {
|
||||
if (classPredicate.test(innerClass)) {
|
||||
return innerClass;
|
||||
}
|
||||
}
|
||||
throw new ClassNotFoundException("No class in " + parentClass.getCanonicalName() + " matches the predicate.");
|
||||
}
|
||||
|
||||
public static PacketConstructor findPacketConstructor(Class<?> packetClass, MethodHandles.Lookup lookup) throws Exception {
|
||||
try {
|
||||
MethodHandle constructor = lookup.findConstructor(packetClass, VOID_METHOD_TYPE);
|
||||
return constructor::invoke;
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
// try below with Unsafe
|
||||
}
|
||||
|
||||
if (theUnsafe == null) {
|
||||
synchronized (FastReflection.class) {
|
||||
if (theUnsafe == null) {
|
||||
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
|
||||
Field theUnsafeField = unsafeClass.getDeclaredField("theUnsafe");
|
||||
theUnsafeField.setAccessible(true);
|
||||
theUnsafe = theUnsafeField.get(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MethodType allocateMethodType = MethodType.methodType(Object.class, Class.class);
|
||||
MethodHandle allocateMethod = lookup.findVirtual(theUnsafe.getClass(), "allocateInstance", allocateMethodType);
|
||||
return () -> allocateMethod.invoke(theUnsafe, packetClass);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface PacketConstructor {
|
||||
Object invoke() throws Throwable;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
package fr.maxlego08.koth.scoreboard;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.interfaces.CollectionConsumer;
|
||||
|
||||
public class ScoreBoardManager extends ZUtils {
|
||||
|
||||
private final Plugin plugin;
|
||||
private final Map<Player, FastBoard> boards = new HashMap<Player, FastBoard>();
|
||||
private final long schedulerMillisecond;
|
||||
private boolean isRunning = false;
|
||||
private CollectionConsumer<Player> lines;
|
||||
|
||||
public ScoreBoardManager(Plugin plugin, long schedulerMillisecond) {
|
||||
super();
|
||||
this.schedulerMillisecond = schedulerMillisecond;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start scheduler
|
||||
*/
|
||||
public void schedule() {
|
||||
|
||||
if (this.isRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isRunning = true;
|
||||
|
||||
scheduleFix(this.plugin, this.schedulerMillisecond, (task, canRun) -> {
|
||||
|
||||
// If the task cannot continue then we do not update the scoreboard
|
||||
if (!canRun)
|
||||
return;
|
||||
|
||||
if (!this.isRunning) {
|
||||
task.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
// if the addition of the lines is null then we stop the task
|
||||
if (this.lines == null) {
|
||||
task.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
Iterator<FastBoard> iterator = this.boards.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
FastBoard b = iterator.next();
|
||||
if (b.isDeleted() || !b.getPlayer().isOnline()) {
|
||||
this.boards.remove(b.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
this.boards.forEach((player, board) -> board.updateLines(this.lines.accept(player)));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a scoreboard for a player
|
||||
*
|
||||
* @param player
|
||||
* @param title
|
||||
* @return {@link FastBoard}
|
||||
*/
|
||||
public FastBoard createBoard(Player player, String title) {
|
||||
|
||||
if (this.hasBoard(player)) {
|
||||
return this.getBoard(player);
|
||||
}
|
||||
|
||||
FastBoard board = new FastBoard(player);
|
||||
board.updateTitle(title);
|
||||
|
||||
if (this.lines != null) {
|
||||
board.updateLines(this.lines.accept(player));
|
||||
}
|
||||
|
||||
this.boards.put(player, board);
|
||||
|
||||
return board;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete player board
|
||||
*
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
public boolean delete(Player player) {
|
||||
|
||||
if (!this.hasBoard(player)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FastBoard board = getBoard(player);
|
||||
if (!board.isDeleted()) {
|
||||
board.delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update board title
|
||||
*
|
||||
* @param player
|
||||
* @param title
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean updateTitle(Player player, String title) {
|
||||
|
||||
if (!hasBoard(player)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FastBoard board = getBoard(player);
|
||||
if (!board.isDeleted()) {
|
||||
board.updateTitle(title);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update board line
|
||||
*
|
||||
* @param player
|
||||
* @param title
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean updateLine(Player player, int line, String string) {
|
||||
|
||||
if (!hasBoard(player)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FastBoard board = getBoard(player);
|
||||
if (!board.isDeleted()) {
|
||||
board.updateLine(line, string);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if player has board
|
||||
*
|
||||
* @param player
|
||||
* @return {@link Boolean}
|
||||
*/
|
||||
public boolean hasBoard(Player player) {
|
||||
return this.boards.containsKey(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return player's board
|
||||
*
|
||||
* @param player
|
||||
* @return {@link FastBoard}
|
||||
*/
|
||||
public FastBoard getBoard(Player player) {
|
||||
return this.boards.getOrDefault(player, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the boards
|
||||
*/
|
||||
public Map<Player, FastBoard> getBoards() {
|
||||
return this.boards;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the schedulerMillisecond
|
||||
*/
|
||||
public long getSchedulerMillisecond() {
|
||||
return this.schedulerMillisecond;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the isRunning
|
||||
*/
|
||||
public boolean isRunning() {
|
||||
return this.isRunning;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lines
|
||||
*/
|
||||
public CollectionConsumer<Player> getLines() {
|
||||
return this.lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isRunning
|
||||
* the isRunning to set
|
||||
*/
|
||||
public void setRunning(boolean isRunning) {
|
||||
this.isRunning = isRunning;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lines
|
||||
* the lines to set
|
||||
*/
|
||||
public void setLines(CollectionConsumer<Player> lines) {
|
||||
this.lines = lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lines
|
||||
* the lines to set
|
||||
*/
|
||||
public void setLinesAndSchedule(CollectionConsumer<Player> lines) {
|
||||
this.lines = lines;
|
||||
this.schedule();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,278 @@
|
|||
package fr.maxlego08.koth.zcore;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import fr.maxlego08.koth.exceptions.ListenerNullException;
|
||||
import fr.maxlego08.koth.inventory.ZInventoryManager;
|
||||
import fr.maxlego08.koth.placeholder.LocalPlaceholder;
|
||||
import fr.maxlego08.koth.placeholder.Placeholder;
|
||||
import fr.maxlego08.koth.zcore.enums.EnumInventory;
|
||||
import fr.maxlego08.koth.zcore.logger.Logger;
|
||||
import fr.maxlego08.koth.KothPlugin;
|
||||
import fr.maxlego08.koth.command.CommandManager;
|
||||
import fr.maxlego08.koth.command.VCommand;
|
||||
import fr.maxlego08.koth.inventory.VInventory;
|
||||
import fr.maxlego08.koth.listener.AdapterListener;
|
||||
import fr.maxlego08.koth.listener.ListenerAdapter;
|
||||
import fr.maxlego08.koth.zcore.utils.gson.LocationAdapter;
|
||||
import fr.maxlego08.koth.zcore.utils.gson.PotionEffectAdapter;
|
||||
import fr.maxlego08.koth.zcore.utils.plugins.Plugins;
|
||||
import fr.maxlego08.koth.zcore.utils.storage.NoReloadable;
|
||||
import fr.maxlego08.koth.zcore.utils.storage.Persist;
|
||||
import fr.maxlego08.koth.zcore.utils.storage.Savable;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public abstract class ZPlugin extends JavaPlugin {
|
||||
|
||||
public static final ExecutorService service = Executors.newFixedThreadPool(5);
|
||||
private final Logger log = new Logger(this.getDescription().getFullName());
|
||||
private final List<Savable> savers = new ArrayList<>();
|
||||
private final List<ListenerAdapter> listenerAdapters = new ArrayList<>();
|
||||
|
||||
private Gson gson;
|
||||
private Persist persist;
|
||||
private long enableTime;
|
||||
|
||||
protected CommandManager commandManager;
|
||||
protected ZInventoryManager inventoryManager;
|
||||
|
||||
protected void preEnable() {
|
||||
|
||||
LocalPlaceholder.getInstance().setPlugin((KothPlugin) this);
|
||||
Placeholder.getPlaceholder();
|
||||
|
||||
this.enableTime = System.currentTimeMillis();
|
||||
|
||||
this.log.log("=== ENABLE START ===");
|
||||
this.log.log("Plugin Version V<&>c" + getDescription().getVersion(), Logger.LogType.INFO);
|
||||
|
||||
this.getDataFolder().mkdirs();
|
||||
|
||||
this.gson = getGsonBuilder().create();
|
||||
this.persist = new Persist(this);
|
||||
|
||||
this.commandManager = new CommandManager((KothPlugin) this);
|
||||
this.inventoryManager = new ZInventoryManager((KothPlugin) this);
|
||||
|
||||
/* Add Listener */
|
||||
this.addListener(new AdapterListener((KothPlugin) this));
|
||||
this.addListener(this.inventoryManager);
|
||||
}
|
||||
|
||||
protected void postEnable() {
|
||||
|
||||
if (this.inventoryManager != null) {
|
||||
this.inventoryManager.sendLog();
|
||||
}
|
||||
|
||||
if (this.commandManager != null) {
|
||||
this.commandManager.validCommands();
|
||||
}
|
||||
|
||||
this.log.log(
|
||||
"=== ENABLE DONE <&>7(<&>6" + Math.abs(enableTime - System.currentTimeMillis()) + "ms<&>7) <&>e===");
|
||||
|
||||
}
|
||||
|
||||
protected void preDisable() {
|
||||
this.enableTime = System.currentTimeMillis();
|
||||
this.log.log("=== DISABLE START ===");
|
||||
}
|
||||
|
||||
protected void postDisable() {
|
||||
this.log.log(
|
||||
"=== DISABLE DONE <&>7(<&>6" + Math.abs(enableTime - System.currentTimeMillis()) + "ms<&>7) <&>e===");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Build gson
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public GsonBuilder getGsonBuilder() {
|
||||
return new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().serializeNulls()
|
||||
.excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.VOLATILE)
|
||||
.registerTypeAdapter(PotionEffect.class, new PotionEffectAdapter(this))
|
||||
.registerTypeAdapter(Location.class, new LocationAdapter(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
public void addListener(Listener listener) {
|
||||
if (listener instanceof Savable)
|
||||
this.addSave((Savable) listener);
|
||||
Bukkit.getPluginManager().registerEvents(listener, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener from ListenerAdapter
|
||||
*
|
||||
* @param adapter
|
||||
*/
|
||||
public void addListener(ListenerAdapter adapter) {
|
||||
if (adapter == null)
|
||||
throw new ListenerNullException("Warning, your listener is null");
|
||||
if (adapter instanceof Savable)
|
||||
this.addSave((Savable) adapter);
|
||||
this.listenerAdapters.add(adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Saveable
|
||||
*
|
||||
* @param saver
|
||||
*/
|
||||
public void addSave(Savable saver) {
|
||||
this.savers.add(saver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get logger
|
||||
*
|
||||
* @return loggers
|
||||
*/
|
||||
public Logger getLog() {
|
||||
return this.log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get gson
|
||||
*
|
||||
* @return {@link Gson}
|
||||
*/
|
||||
public Gson getGson() {
|
||||
return gson;
|
||||
}
|
||||
|
||||
public Persist getPersist() {
|
||||
return persist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all saveables
|
||||
*
|
||||
* @return savers
|
||||
*/
|
||||
public List<Savable> getSavers() {
|
||||
return savers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param classz
|
||||
* @return
|
||||
*/
|
||||
protected <T> T getProvider(Class<T> classz) {
|
||||
RegisteredServiceProvider<T> provider = getServer().getServicesManager().getRegistration(classz);
|
||||
if (provider == null) {
|
||||
log.log("Unable to retrieve the provider " + classz.toString(), Logger.LogType.WARNING);
|
||||
return null;
|
||||
}
|
||||
return provider.getProvider() != null ? (T) provider.getProvider() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return listenerAdapters
|
||||
*/
|
||||
public List<ListenerAdapter> getListenerAdapters() {
|
||||
return listenerAdapters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the commandManager
|
||||
*/
|
||||
public CommandManager getCommandManager() {
|
||||
return commandManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the inventoryManager
|
||||
*/
|
||||
public ZInventoryManager getInventoryManager() {
|
||||
return inventoryManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plugin is enable
|
||||
*
|
||||
* @param pluginName
|
||||
* @return
|
||||
*/
|
||||
protected boolean isEnable(Plugins pl) {
|
||||
Plugin plugin = getPlugin(pl);
|
||||
return plugin == null ? false : plugin.isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin for plugins enum
|
||||
*
|
||||
* @param pluginName
|
||||
* @return
|
||||
*/
|
||||
protected Plugin getPlugin(Plugins plugin) {
|
||||
return Bukkit.getPluginManager().getPlugin(plugin.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register command
|
||||
*
|
||||
* @param command
|
||||
* @param vCommand
|
||||
* @param aliases
|
||||
*/
|
||||
protected void registerCommand(String command, VCommand vCommand, String... aliases) {
|
||||
this.commandManager.registerCommand(this, command, vCommand, Arrays.asList(aliases));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Inventory
|
||||
*
|
||||
* @param inventory
|
||||
* @param vInventory
|
||||
*/
|
||||
protected void registerInventory(EnumInventory inventory, VInventory vInventory) {
|
||||
this.inventoryManager.registerInventory(inventory, vInventory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load files
|
||||
*/
|
||||
public void loadFiles() {
|
||||
this.savers.forEach(save -> save.load(this.persist));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save files
|
||||
*/
|
||||
public void saveFiles() {
|
||||
this.savers.forEach(save -> save.save(this.persist));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload files
|
||||
*/
|
||||
public void reloadFiles() {
|
||||
this.savers.forEach(save -> {
|
||||
if (!(save instanceof NoReloadable)) {
|
||||
save.load(this.persist);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package fr.maxlego08.koth.zcore.enums;
|
||||
|
||||
public enum EnumInventory {
|
||||
|
||||
;
|
||||
|
||||
private final int id;
|
||||
|
||||
private EnumInventory(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package fr.maxlego08.koth.zcore.enums;
|
||||
|
||||
public enum Folder {
|
||||
|
||||
UTILS,
|
||||
|
||||
;
|
||||
|
||||
|
||||
public String toFolder(){
|
||||
return name().toLowerCase();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
package fr.maxlego08.koth.zcore.enums;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.nms.NMSUtils;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public enum Message {
|
||||
|
||||
PREFIX("§8(§6Template§8) "),
|
||||
|
||||
TELEPORT_MOVE("§cYou must not move!"),
|
||||
TELEPORT_MESSAGE("§7Teleportation in §3%second% §7seconds!"),
|
||||
TELEPORT_ERROR("§cYou already have a teleportation in progress!"),
|
||||
TELEPORT_SUCCESS("§7Teleportation done!"),
|
||||
INVENTORY_CLONE_NULL("§cThe inventory clone is null!"),
|
||||
INVENTORY_OPEN_ERROR("§cAn error occurred with the opening of the inventory §6%id%§c."),
|
||||
TIME_DAY("%02d %day% %02d %hour% %02d %minute% %02d %second%"),
|
||||
TIME_HOUR("%02d %hour% %02d minute(s) %02d %second%"),
|
||||
TIME_MINUTE("%02d %minute% %02d %second%"),
|
||||
TIME_SECOND("%02d %second%"),
|
||||
|
||||
FORMAT_SECOND("second"),
|
||||
FORMAT_SECONDS("seconds"),
|
||||
|
||||
FORMAT_MINUTE("minute"),
|
||||
FORMAT_MINUTES("minutes"),
|
||||
|
||||
FORMAT_HOUR("hour"),
|
||||
FORMAT_HOURS("hours"),
|
||||
|
||||
FORMAT_DAY("d"),
|
||||
FORMAT_DAYS("days"),
|
||||
|
||||
COMMAND_SYNTAXE_ERROR("§cYou must execute the command like this§7: §a%syntax%"),
|
||||
COMMAND_NO_PERMISSION("§cYou do not have permission to run this command."),
|
||||
COMMAND_NO_CONSOLE("§cOnly one player can execute this command."),
|
||||
COMMAND_NO_ARG("§cImpossible to find the command with its arguments."),
|
||||
COMMAND_SYNTAXE_HELP("§f%syntax% §7» §7%description%"),
|
||||
|
||||
RELOAD("§aYou have just reloaded the configuration files."),
|
||||
|
||||
DESCRIPTION_RELOAD("Reload configuration files"),
|
||||
|
||||
;
|
||||
|
||||
private List<String> messages;
|
||||
private String message;
|
||||
private Map<String, Object> titles = new HashMap<>();
|
||||
private boolean use = true;
|
||||
private MessageType type = MessageType.TCHAT;
|
||||
|
||||
private ItemStack itemStack;
|
||||
|
||||
/**
|
||||
* @param message
|
||||
*/
|
||||
private Message(String message) {
|
||||
this.message = message;
|
||||
this.use = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param title
|
||||
* @param subTitle
|
||||
* @param a
|
||||
* @param b
|
||||
* @param c
|
||||
*/
|
||||
private Message(String title, String subTitle, int a, int b, int c) {
|
||||
this.use = true;
|
||||
this.titles.put("title", title);
|
||||
this.titles.put("subtitle", subTitle);
|
||||
this.titles.put("start", a);
|
||||
this.titles.put("time", b);
|
||||
this.titles.put("end", c);
|
||||
this.titles.put("isUse", true);
|
||||
this.type = MessageType.TITLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
*/
|
||||
private Message(String... message) {
|
||||
this.messages = Arrays.asList(message);
|
||||
this.use = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
*/
|
||||
private Message(MessageType type, String... message) {
|
||||
this.messages = Arrays.asList(message);
|
||||
this.use = true;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
*/
|
||||
private Message(MessageType type, String message) {
|
||||
this.message = message;
|
||||
this.use = true;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @param use
|
||||
*/
|
||||
private Message(String message, boolean use) {
|
||||
this.message = message;
|
||||
this.use = use;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String toMsg() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String msg() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public boolean isUse() {
|
||||
return use;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public List<String> getMessages() {
|
||||
return messages == null ? Arrays.asList(message) : messages;
|
||||
}
|
||||
|
||||
public void setMessages(List<String> messages) {
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
public boolean isMessage() {
|
||||
return messages != null && messages.size() > 1;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return (String) titles.get("title");
|
||||
}
|
||||
|
||||
public Map<String, Object> getTitles() {
|
||||
return titles;
|
||||
}
|
||||
|
||||
public void setTitles(Map<String, Object> titles) {
|
||||
this.titles = titles;
|
||||
this.type = MessageType.TITLE;
|
||||
}
|
||||
|
||||
public String getSubTitle() {
|
||||
return (String) titles.get("subtitle");
|
||||
}
|
||||
|
||||
public boolean isTitle() {
|
||||
return titles.containsKey("title");
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return ((Number) titles.get("start")).intValue();
|
||||
}
|
||||
|
||||
public int getEnd() {
|
||||
return ((Number) titles.get("end")).intValue();
|
||||
}
|
||||
|
||||
public int getTime() {
|
||||
return ((Number) titles.get("time")).intValue();
|
||||
}
|
||||
|
||||
public boolean isUseTitle() {
|
||||
return (boolean) titles.getOrDefault("isUse", "true");
|
||||
}
|
||||
|
||||
public String replace(String a, String b) {
|
||||
return message.replace(a, b);
|
||||
}
|
||||
|
||||
public MessageType getType() {
|
||||
return type.equals(MessageType.ACTION) && NMSUtils.isVeryOldVersion() ? MessageType.TCHAT : type;
|
||||
}
|
||||
|
||||
public ItemStack getItemStack() {
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
public void setType(MessageType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setItemStack(ItemStack itemStack) {
|
||||
this.itemStack = itemStack;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package fr.maxlego08.koth.zcore.enums;
|
||||
|
||||
public enum MessageType {
|
||||
|
||||
ACTION,
|
||||
TCHAT,
|
||||
TITLE,
|
||||
CENTER,
|
||||
NONE,
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package fr.maxlego08.koth.zcore.enums;
|
||||
|
||||
public enum Permission {
|
||||
|
||||
EXAMPLE_PERMISSION,
|
||||
EXAMPLE_PERMISSION_RELOAD,
|
||||
|
||||
;
|
||||
|
||||
private String permission;
|
||||
|
||||
private Permission() {
|
||||
this.permission = this.name().toLowerCase().replace("_", ".");
|
||||
}
|
||||
|
||||
public String getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package fr.maxlego08.koth.zcore.logger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class Logger {
|
||||
|
||||
private final String prefix;
|
||||
private static Logger logger;
|
||||
|
||||
public Logger(String prefix) {
|
||||
this.prefix = prefix;
|
||||
logger = this;
|
||||
}
|
||||
|
||||
public static Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
public static void info(String message, LogType type) {
|
||||
getLogger().log(message, type);
|
||||
}
|
||||
|
||||
public static void info(String message) {
|
||||
getLogger().log(message, LogType.INFO);
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public enum LogType {
|
||||
ERROR("§c"),
|
||||
INFO("§7"),
|
||||
WARNING("§6"),
|
||||
SUCCESS("§2");
|
||||
|
||||
private final String color;
|
||||
|
||||
LogType(String color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
public void log(String message, LogType type) {
|
||||
Bukkit.getConsoleSender().sendMessage("§8[§e" + prefix + "§8] " + type.getColor() + getColoredMessage(message));
|
||||
}
|
||||
|
||||
public void log(String message) {
|
||||
Bukkit.getConsoleSender().sendMessage("§8[§e" + prefix + "§8] §e" + getColoredMessage(message));
|
||||
}
|
||||
|
||||
public void log(String message, Object... args) {
|
||||
log(String.format(message, args));
|
||||
}
|
||||
|
||||
public void log(String message, LogType type, Object... args) {
|
||||
log(String.format(message, args), type);
|
||||
}
|
||||
|
||||
public void log(String[] messages, LogType type) {
|
||||
for (String message : messages) {
|
||||
log(message, type);
|
||||
}
|
||||
}
|
||||
|
||||
public String getColoredMessage(String message) {
|
||||
return message.replace("<&>", "§");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,269 @@
|
|||
package fr.maxlego08.koth.zcore.utils;
|
||||
|
||||
public final class Base64 {
|
||||
|
||||
static private final int BASELENGTH = 128;
|
||||
static private final int LOOKUPLENGTH = 64;
|
||||
static private final int TWENTYFOURBITGROUP = 24;
|
||||
static private final int EIGHTBIT = 8;
|
||||
static private final int SIXTEENBIT = 16;
|
||||
static private final int FOURBYTE = 4;
|
||||
static private final int SIGN = -128;
|
||||
static private final char PAD = '=';
|
||||
static private final boolean fDebug = false;
|
||||
static final private byte [] base64Alphabet = new byte[BASELENGTH];
|
||||
static final private char [] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
|
||||
|
||||
static {
|
||||
|
||||
for (int i = 0; i < BASELENGTH; ++i) {
|
||||
base64Alphabet[i] = -1;
|
||||
}
|
||||
for (int i = 'Z'; i >= 'A'; i--) {
|
||||
base64Alphabet[i] = (byte) (i-'A');
|
||||
}
|
||||
for (int i = 'z'; i>= 'a'; i--) {
|
||||
base64Alphabet[i] = (byte) ( i-'a' + 26);
|
||||
}
|
||||
|
||||
for (int i = '9'; i >= '0'; i--) {
|
||||
base64Alphabet[i] = (byte) (i-'0' + 52);
|
||||
}
|
||||
|
||||
base64Alphabet['+'] = 62;
|
||||
base64Alphabet['/'] = 63;
|
||||
|
||||
for (int i = 0; i<=25; i++)
|
||||
lookUpBase64Alphabet[i] = (char)('A'+i);
|
||||
|
||||
for (int i = 26, j = 0; i<=51; i++, j++)
|
||||
lookUpBase64Alphabet[i] = (char)('a'+ j);
|
||||
|
||||
for (int i = 52, j = 0; i<=61; i++, j++)
|
||||
lookUpBase64Alphabet[i] = (char)('0' + j);
|
||||
lookUpBase64Alphabet[62] = (char)'+';
|
||||
lookUpBase64Alphabet[63] = (char)'/';
|
||||
|
||||
}
|
||||
|
||||
protected static boolean isWhiteSpace(char octect) {
|
||||
return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
|
||||
}
|
||||
|
||||
protected static boolean isPad(char octect) {
|
||||
return (octect == PAD);
|
||||
}
|
||||
|
||||
protected static boolean isData(char octect) {
|
||||
return (octect < BASELENGTH && base64Alphabet[octect] != -1);
|
||||
}
|
||||
|
||||
protected static boolean isBase64(char octect) {
|
||||
return (isWhiteSpace(octect) || isPad(octect) || isData(octect));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes hex octects into Base64
|
||||
*
|
||||
* @param binaryData Array containing binaryData
|
||||
* @return Encoded Base64 array
|
||||
*/
|
||||
public static String encode(byte[] binaryData) {
|
||||
|
||||
if (binaryData == null)
|
||||
return null;
|
||||
|
||||
int lengthDataBits = binaryData.length*EIGHTBIT;
|
||||
if (lengthDataBits == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP;
|
||||
int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP;
|
||||
int numberQuartet = fewerThan24bits != 0 ? numberTriplets+1 : numberTriplets;
|
||||
char encodedData[] = null;
|
||||
|
||||
encodedData = new char[numberQuartet*4];
|
||||
|
||||
byte k=0, l=0, b1=0,b2=0,b3=0;
|
||||
|
||||
int encodedIndex = 0;
|
||||
int dataIndex = 0;
|
||||
if (fDebug) {
|
||||
System.out.println("number of triplets = " + numberTriplets );
|
||||
}
|
||||
|
||||
for (int i=0; i<numberTriplets; i++) {
|
||||
b1 = binaryData[dataIndex++];
|
||||
b2 = binaryData[dataIndex++];
|
||||
b3 = binaryData[dataIndex++];
|
||||
|
||||
if (fDebug) {
|
||||
System.out.println( "b1= " + b1 +", b2= " + b2 + ", b3= " + b3 );
|
||||
}
|
||||
|
||||
l = (byte)(b2 & 0x0f);
|
||||
k = (byte)(b1 & 0x03);
|
||||
|
||||
byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
|
||||
|
||||
byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
|
||||
byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
|
||||
|
||||
if (fDebug) {
|
||||
System.out.println( "val2 = " + val2 );
|
||||
System.out.println( "k4 = " + (k<<4));
|
||||
System.out.println( "vak = " + (val2 | (k<<4)));
|
||||
}
|
||||
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[ b3 & 0x3f ];
|
||||
}
|
||||
|
||||
// form integral number of 6-bit groups
|
||||
if (fewerThan24bits == EIGHTBIT) {
|
||||
b1 = binaryData[dataIndex];
|
||||
k = (byte) ( b1 &0x03 );
|
||||
if (fDebug) {
|
||||
System.out.println("b1=" + b1);
|
||||
System.out.println("b1<<2 = " + (b1>>2) );
|
||||
}
|
||||
byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[ k<<4 ];
|
||||
encodedData[encodedIndex++] = PAD;
|
||||
encodedData[encodedIndex++] = PAD;
|
||||
} else if (fewerThan24bits == SIXTEENBIT) {
|
||||
b1 = binaryData[dataIndex];
|
||||
b2 = binaryData[dataIndex +1 ];
|
||||
l = ( byte ) ( b2 &0x0f );
|
||||
k = ( byte ) ( b1 &0x03 );
|
||||
|
||||
byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
|
||||
byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
|
||||
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
|
||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[ l<<2 ];
|
||||
encodedData[encodedIndex++] = PAD;
|
||||
}
|
||||
|
||||
return new String(encodedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes Base64 data into octects
|
||||
*
|
||||
* @param encoded string containing Base64 data
|
||||
* @return Array containind decoded data.
|
||||
*/
|
||||
public static byte[] decode(String encoded) {
|
||||
|
||||
if (encoded == null)
|
||||
return null;
|
||||
|
||||
char[] base64Data = encoded.toCharArray();
|
||||
// remove white spaces
|
||||
int len = removeWhiteSpace(base64Data);
|
||||
|
||||
if (len%FOURBYTE != 0) {
|
||||
return null;//should be divisible by four
|
||||
}
|
||||
|
||||
int numberQuadruple = (len/FOURBYTE );
|
||||
|
||||
if (numberQuadruple == 0)
|
||||
return new byte[0];
|
||||
|
||||
byte decodedData[] = null;
|
||||
byte b1=0,b2=0,b3=0,b4=0;
|
||||
char d1=0,d2=0,d3=0,d4=0;
|
||||
|
||||
int i = 0;
|
||||
int encodedIndex = 0;
|
||||
int dataIndex = 0;
|
||||
decodedData = new byte[ (numberQuadruple)*3];
|
||||
|
||||
for (; i<numberQuadruple-1; i++) {
|
||||
|
||||
if (!isData( (d1 = base64Data[dataIndex++]) )||
|
||||
!isData( (d2 = base64Data[dataIndex++]) )||
|
||||
!isData( (d3 = base64Data[dataIndex++]) )||
|
||||
!isData( (d4 = base64Data[dataIndex++]) ))
|
||||
return null;//if found "no data" just return null
|
||||
|
||||
b1 = base64Alphabet[d1];
|
||||
b2 = base64Alphabet[d2];
|
||||
b3 = base64Alphabet[d3];
|
||||
b4 = base64Alphabet[d4];
|
||||
|
||||
decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ;
|
||||
decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
|
||||
decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
|
||||
}
|
||||
|
||||
if (!isData( (d1 = base64Data[dataIndex++]) ) ||
|
||||
!isData( (d2 = base64Data[dataIndex++]) )) {
|
||||
return null;//if found "no data" just return null
|
||||
}
|
||||
|
||||
b1 = base64Alphabet[d1];
|
||||
b2 = base64Alphabet[d2];
|
||||
|
||||
d3 = base64Data[dataIndex++];
|
||||
d4 = base64Data[dataIndex++];
|
||||
if (!isData( (d3 ) ) ||
|
||||
!isData( (d4 ) )) {//Check if they are PAD characters
|
||||
if (isPad( d3 ) && isPad( d4)) { //Two PAD e.g. 3c[Pad][Pad]
|
||||
if ((b2 & 0xf) != 0)//last 4 bits should be zero
|
||||
return null;
|
||||
byte[] tmp = new byte[ i*3 + 1 ];
|
||||
System.arraycopy( decodedData, 0, tmp, 0, i*3 );
|
||||
tmp[encodedIndex] = (byte)( b1 <<2 | b2>>4 ) ;
|
||||
return tmp;
|
||||
} else if (!isPad( d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad]
|
||||
b3 = base64Alphabet[ d3 ];
|
||||
if ((b3 & 0x3 ) != 0)//last 2 bits should be zero
|
||||
return null;
|
||||
byte[] tmp = new byte[ i*3 + 2 ];
|
||||
System.arraycopy( decodedData, 0, tmp, 0, i*3 );
|
||||
tmp[encodedIndex++] = (byte)( b1 <<2 | b2>>4 );
|
||||
tmp[encodedIndex] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
|
||||
return tmp;
|
||||
} else {
|
||||
return null;//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
|
||||
}
|
||||
} else { //No PAD e.g 3cQl
|
||||
b3 = base64Alphabet[ d3 ];
|
||||
b4 = base64Alphabet[ d4 ];
|
||||
decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ;
|
||||
decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
|
||||
decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
|
||||
|
||||
}
|
||||
|
||||
return decodedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove WhiteSpace from MIME containing encoded Base64 data.
|
||||
*
|
||||
* @param data the byte array of base64 data (with WS)
|
||||
* @return the new length
|
||||
*/
|
||||
protected static int removeWhiteSpace(char[] data) {
|
||||
if (data == null)
|
||||
return 0;
|
||||
|
||||
// count characters that's not whitespace
|
||||
int newSize = 0;
|
||||
int len = data.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (!isWhiteSpace(data[i]))
|
||||
data[newSize++] = data[i];
|
||||
}
|
||||
return newSize;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,746 @@
|
|||
package fr.maxlego08.koth.zcore.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
|
||||
public class Cuboid implements Iterable<Block>, Cloneable, ConfigurationSerializable {
|
||||
|
||||
/**
|
||||
* This class is a region/cuboid from one location to another. It can be
|
||||
* used for blocks protection and things like WorldEdit.
|
||||
*
|
||||
* @author desht (Original code), KingFaris10 (Editor of code)
|
||||
*/
|
||||
protected final String worldName;
|
||||
protected final int x1, y1, z1;
|
||||
protected final int x2, y2, z2;
|
||||
|
||||
/**
|
||||
* Construct a Cuboid given two Location objects which represent any two
|
||||
* corners of the Cuboid. Note: The 2 locations must be on the same world.
|
||||
*
|
||||
* @param l1
|
||||
* - One of the corners
|
||||
* @param l2
|
||||
* - The other corner
|
||||
*/
|
||||
public Cuboid(Location l1, Location l2) {
|
||||
if (!l1.getWorld().equals(l2.getWorld()))
|
||||
throw new IllegalArgumentException("Locations must be on the same world");
|
||||
this.worldName = l1.getWorld().getName();
|
||||
this.x1 = Math.min(l1.getBlockX(), l2.getBlockX());
|
||||
this.y1 = Math.min(l1.getBlockY(), l2.getBlockY());
|
||||
this.z1 = Math.min(l1.getBlockZ(), l2.getBlockZ());
|
||||
this.x2 = Math.max(l1.getBlockX(), l2.getBlockX());
|
||||
this.y2 = Math.max(l1.getBlockY(), l2.getBlockY());
|
||||
this.z2 = Math.max(l1.getBlockZ(), l2.getBlockZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a one-block Cuboid at the given Location of the Cuboid.
|
||||
*
|
||||
* @param l1
|
||||
* location of the Cuboid
|
||||
*/
|
||||
public Cuboid(Location l1) {
|
||||
this(l1, l1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* @param other
|
||||
* - The Cuboid to copy
|
||||
*/
|
||||
public Cuboid(Cuboid other) {
|
||||
this(other.getWorld().getName(), other.x1, other.y1, other.z1, other.x2, other.y2, other.z2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Cuboid in the given World and xyz co-ordinates
|
||||
*
|
||||
* @param world
|
||||
* - The Cuboid's world
|
||||
* @param x1
|
||||
* - X co-ordinate of corner 1
|
||||
* @param y1
|
||||
* - Y co-ordinate of corner 1
|
||||
* @param z1
|
||||
* - Z co-ordinate of corner 1
|
||||
* @param x2
|
||||
* - X co-ordinate of corner 2
|
||||
* @param y2
|
||||
* - Y co-ordinate of corner 2
|
||||
* @param z2
|
||||
* - Z co-ordinate of corner 2
|
||||
*/
|
||||
public Cuboid(World world, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||
this.worldName = world.getName();
|
||||
this.x1 = Math.min(x1, x2);
|
||||
this.x2 = Math.max(x1, x2);
|
||||
this.y1 = Math.min(y1, y2);
|
||||
this.y2 = Math.max(y1, y2);
|
||||
this.z1 = Math.min(z1, z2);
|
||||
this.z2 = Math.max(z1, z2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Cuboid in the given world name and xyz co-ordinates.
|
||||
*
|
||||
* @param worldName
|
||||
* - The Cuboid's world name
|
||||
* @param x1
|
||||
* - X co-ordinate of corner 1
|
||||
* @param y1
|
||||
* - Y co-ordinate of corner 1
|
||||
* @param z1
|
||||
* - Z co-ordinate of corner 1
|
||||
* @param x2
|
||||
* - X co-ordinate of corner 2
|
||||
* @param y2
|
||||
* - Y co-ordinate of corner 2
|
||||
* @param z2
|
||||
* - Z co-ordinate of corner 2
|
||||
*/
|
||||
private Cuboid(String worldName, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||
this.worldName = worldName;
|
||||
this.x1 = Math.min(x1, x2);
|
||||
this.x2 = Math.max(x1, x2);
|
||||
this.y1 = Math.min(y1, y2);
|
||||
this.y2 = Math.max(y1, y2);
|
||||
this.z1 = Math.min(z1, z2);
|
||||
this.z2 = Math.max(z1, z2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Cuboid using a map with the following keys: worldName, x1,
|
||||
* x2, y1, y2, z1, z2
|
||||
*
|
||||
* @param map
|
||||
* - The map of keys.
|
||||
*/
|
||||
public Cuboid(Map<String, Object> map) {
|
||||
this.worldName = (String) map.get("worldName");
|
||||
this.x1 = (Integer) map.get("x1");
|
||||
this.x2 = (Integer) map.get("x2");
|
||||
this.y1 = (Integer) map.get("y1");
|
||||
this.y2 = (Integer) map.get("y2");
|
||||
this.z1 = (Integer) map.get("z1");
|
||||
this.z2 = (Integer) map.get("z2");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> serialize() {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("worldName", this.worldName);
|
||||
map.put("x1", this.x1);
|
||||
map.put("y1", this.y1);
|
||||
map.put("z1", this.z1);
|
||||
map.put("x2", this.x2);
|
||||
map.put("y2", this.y2);
|
||||
map.put("z2", this.z2);
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Location of the lower northeast corner of the Cuboid (minimum XYZ
|
||||
* co-ordinates).
|
||||
*
|
||||
* @return Location of the lower northeast corner
|
||||
*/
|
||||
public Location getLowerNE() {
|
||||
return new Location(this.getWorld(), this.x1, this.y1, this.z1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Location of the upper southwest corner of the Cuboid (maximum XYZ
|
||||
* co-ordinates).
|
||||
*
|
||||
* @return Location of the upper southwest corner
|
||||
*/
|
||||
public Location getUpperSW() {
|
||||
return new Location(this.getWorld(), this.x2, this.y2, this.z2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the blocks in the Cuboid.
|
||||
*
|
||||
* @return The blocks in the Cuboid
|
||||
*/
|
||||
public List<Block> getBlocks(Material material) {
|
||||
Iterator<Block> blockI = this.iterator();
|
||||
List<Block> copy = new ArrayList<Block>();
|
||||
while (blockI.hasNext()){
|
||||
Block block = blockI.next();
|
||||
if (block.getType().equals(material)) copy.add(block);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the blocks in the Cuboid.
|
||||
*
|
||||
* @return The blocks in the Cuboid
|
||||
*/
|
||||
public List<Block> getBlocks() {
|
||||
Iterator<Block> blockI = this.iterator();
|
||||
List<Block> copy = new ArrayList<Block>();
|
||||
while (blockI.hasNext())
|
||||
copy.add(blockI.next());
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the the centre of the Cuboid.
|
||||
*
|
||||
* @return Location at the centre of the Cuboid
|
||||
*/
|
||||
public Location getCenter() {
|
||||
int x1 = this.getUpperX() + 1;
|
||||
int y1 = this.getUpperY() + 1;
|
||||
int z1 = this.getUpperZ() + 1;
|
||||
return new Location(this.getWorld(), this.getLowerX() + (x1 - this.getLowerX()) / 2.0,
|
||||
this.getLowerY() + (y1 - this.getLowerY()) / 2.0, this.getLowerZ() + (z1 - this.getLowerZ()) / 2.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Cuboid's world.
|
||||
*
|
||||
* @return The World object representing this Cuboid's world
|
||||
* @throws IllegalStateException
|
||||
* if the world is not loaded
|
||||
*/
|
||||
public World getWorld() {
|
||||
World world = Bukkit.getWorld(this.worldName);
|
||||
if (world == null)
|
||||
throw new IllegalStateException("World '" + this.worldName + "' is not loaded");
|
||||
return world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of this Cuboid along the X axis
|
||||
*
|
||||
* @return Size of Cuboid along the X axis
|
||||
*/
|
||||
public int getSizeX() {
|
||||
return (this.x2 - this.x1) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of this Cuboid along the Y axis
|
||||
*
|
||||
* @return Size of Cuboid along the Y axis
|
||||
*/
|
||||
public int getSizeY() {
|
||||
return (this.y2 - this.y1) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of this Cuboid along the Z axis
|
||||
*
|
||||
* @return Size of Cuboid along the Z axis
|
||||
*/
|
||||
public int getSizeZ() {
|
||||
return (this.z2 - this.z1) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum X co-ordinate of this Cuboid
|
||||
*
|
||||
* @return the minimum X co-ordinate
|
||||
*/
|
||||
public int getLowerX() {
|
||||
return this.x1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum Y co-ordinate of this Cuboid
|
||||
*
|
||||
* @return the minimum Y co-ordinate
|
||||
*/
|
||||
public int getLowerY() {
|
||||
return this.y1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum Z co-ordinate of this Cuboid
|
||||
*
|
||||
* @return the minimum Z co-ordinate
|
||||
*/
|
||||
public int getLowerZ() {
|
||||
return this.z1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum X co-ordinate of this Cuboid
|
||||
*
|
||||
* @return the maximum X co-ordinate
|
||||
*/
|
||||
public int getUpperX() {
|
||||
return this.x2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum Y co-ordinate of this Cuboid
|
||||
*
|
||||
* @return the maximum Y co-ordinate
|
||||
*/
|
||||
public int getUpperY() {
|
||||
return this.y2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum Z co-ordinate of this Cuboid
|
||||
*
|
||||
* @return the maximum Z co-ordinate
|
||||
*/
|
||||
public int getUpperZ() {
|
||||
return this.z2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Blocks at the eight corners of the Cuboid.
|
||||
*
|
||||
* @return array of Block objects representing the Cuboid corners
|
||||
*/
|
||||
public Block[] corners() {
|
||||
Block[] res = new Block[8];
|
||||
World w = this.getWorld();
|
||||
res[0] = w.getBlockAt(this.x1, this.y1, this.z1);
|
||||
res[1] = w.getBlockAt(this.x1, this.y1, this.z2);
|
||||
res[2] = w.getBlockAt(this.x1, this.y2, this.z1);
|
||||
res[3] = w.getBlockAt(this.x1, this.y2, this.z2);
|
||||
res[4] = w.getBlockAt(this.x2, this.y1, this.z1);
|
||||
res[5] = w.getBlockAt(this.x2, this.y1, this.z2);
|
||||
res[6] = w.getBlockAt(this.x2, this.y2, this.z1);
|
||||
res[7] = w.getBlockAt(this.x2, this.y2, this.z2);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the Cuboid in the given direction by the given amount. Negative
|
||||
* amounts will shrink the Cuboid in the given direction. Shrinking a
|
||||
* cuboid's face past the opposite face is not an error and will return a
|
||||
* valid Cuboid.
|
||||
*
|
||||
* @param dir
|
||||
* - The direction in which to expand
|
||||
* @param amount
|
||||
* - The number of blocks by which to expand
|
||||
* @return A new Cuboid expanded by the given direction and amount
|
||||
*/
|
||||
public Cuboid expand(CuboidDirection dir, int amount) {
|
||||
switch (dir) {
|
||||
case North:
|
||||
return new Cuboid(this.worldName, this.x1 - amount, this.y1, this.z1, this.x2, this.y2, this.z2);
|
||||
case South:
|
||||
return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2 + amount, this.y2, this.z2);
|
||||
case East:
|
||||
return new Cuboid(this.worldName, this.x1, this.y1, this.z1 - amount, this.x2, this.y2, this.z2);
|
||||
case West:
|
||||
return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2, this.z2 + amount);
|
||||
case Down:
|
||||
return new Cuboid(this.worldName, this.x1, this.y1 - amount, this.z1, this.x2, this.y2, this.z2);
|
||||
case Up:
|
||||
return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2 + amount, this.z2);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid direction " + dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift the Cuboid in the given direction by the given amount.
|
||||
*
|
||||
* @param dir
|
||||
* - The direction in which to shift
|
||||
* @param amount
|
||||
* - The number of blocks by which to shift
|
||||
* @return A new Cuboid shifted by the given direction and amount
|
||||
*/
|
||||
public Cuboid shift(CuboidDirection dir, int amount) {
|
||||
return expand(dir, amount).expand(dir.opposite(), -amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outset (grow) the Cuboid in the given direction by the given amount.
|
||||
*
|
||||
* @param dir
|
||||
* - The direction in which to outset (must be Horizontal,
|
||||
* Vertical, or Both)
|
||||
* @param amount
|
||||
* - The number of blocks by which to outset
|
||||
* @return A new Cuboid outset by the given direction and amount
|
||||
*/
|
||||
public Cuboid outset(CuboidDirection dir, int amount) {
|
||||
Cuboid c;
|
||||
switch (dir) {
|
||||
case Horizontal:
|
||||
c = expand(CuboidDirection.North, amount).expand(CuboidDirection.South, amount)
|
||||
.expand(CuboidDirection.East, amount).expand(CuboidDirection.West, amount);
|
||||
break;
|
||||
case Vertical:
|
||||
c = expand(CuboidDirection.Down, amount).expand(CuboidDirection.Up, amount);
|
||||
break;
|
||||
case Both:
|
||||
c = outset(CuboidDirection.Horizontal, amount).outset(CuboidDirection.Vertical, amount);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid direction " + dir);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inset (shrink) the Cuboid in the given direction by the given amount.
|
||||
* Equivalent to calling outset() with a negative amount.
|
||||
*
|
||||
* @param dir
|
||||
* - The direction in which to inset (must be Horizontal,
|
||||
* Vertical, or Both)
|
||||
* @param amount
|
||||
* - The number of blocks by which to inset
|
||||
* @return A new Cuboid inset by the given direction and amount
|
||||
*/
|
||||
public Cuboid inset(CuboidDirection dir, int amount) {
|
||||
return this.outset(dir, -amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the point at (x,y,z) is contained within this Cuboid.
|
||||
*
|
||||
* @param x
|
||||
* - The X co-ordinate
|
||||
* @param y
|
||||
* - The Y co-ordinate
|
||||
* @param z
|
||||
* - The Z co-ordinate
|
||||
* @return true if the given point is within this Cuboid, false otherwise
|
||||
*/
|
||||
public boolean contains(int x, int y, int z) {
|
||||
return x >= this.x1 && x <= this.x2 && y >= this.y1 && y <= this.y2 && z >= this.z1 && z <= this.z2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given Block is contained within this Cuboid.
|
||||
*
|
||||
* @param b
|
||||
* - The Block to check for
|
||||
* @return true if the Block is within this Cuboid, false otherwise
|
||||
*/
|
||||
public boolean contains(Block b) {
|
||||
return this.contains(b.getLocation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given Location is contained within this Cuboid.
|
||||
*
|
||||
* @param l
|
||||
* - The Location to check for
|
||||
* @return true if the Location is within this Cuboid, false otherwise
|
||||
*/
|
||||
public boolean contains(Location l) {
|
||||
if (!this.worldName.equals(l.getWorld().getName()))
|
||||
return false;
|
||||
return this.contains(l.getBlockX(), l.getBlockY(), l.getBlockZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the volume of this Cuboid.
|
||||
*
|
||||
* @return The Cuboid volume, in blocks
|
||||
*/
|
||||
public int getVolume() {
|
||||
return this.getSizeX() * this.getSizeY() * this.getSizeZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the average light level of all empty (air) blocks in the Cuboid.
|
||||
* Returns 0 if there are no empty blocks.
|
||||
*
|
||||
* @return The average light level of this Cuboid
|
||||
*/
|
||||
public byte getAverageLightLevel() {
|
||||
long total = 0;
|
||||
int n = 0;
|
||||
for (Block b : this) {
|
||||
if (b.isEmpty()) {
|
||||
total += b.getLightLevel();
|
||||
++n;
|
||||
}
|
||||
}
|
||||
return n > 0 ? (byte) (total / n) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contract the Cuboid, returning a Cuboid with any air around the edges
|
||||
* removed, just large enough to include all non-air blocks.
|
||||
*
|
||||
* @return A new Cuboid with no external air blocks
|
||||
*/
|
||||
public Cuboid contract() {
|
||||
return this.contract(CuboidDirection.Down).contract(CuboidDirection.South).contract(CuboidDirection.East)
|
||||
.contract(CuboidDirection.Up).contract(CuboidDirection.North).contract(CuboidDirection.West);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contract the Cuboid in the given direction, returning a new Cuboid which
|
||||
* has no exterior empty space. E.g. A direction of Down will push the top
|
||||
* face downwards as much as possible.
|
||||
*
|
||||
* @param dir
|
||||
* - The direction in which to contract
|
||||
* @return A new Cuboid contracted in the given direction
|
||||
*/
|
||||
public Cuboid contract(CuboidDirection dir) {
|
||||
Cuboid face = getFace(dir.opposite());
|
||||
switch (dir) {
|
||||
case Down:
|
||||
while (face.containsOnly(0) && face.getLowerY() > this.getLowerY()) {
|
||||
face = face.shift(CuboidDirection.Down, 1);
|
||||
}
|
||||
return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, face.getUpperY(), this.z2);
|
||||
case Up:
|
||||
while (face.containsOnly(0) && face.getUpperY() < this.getUpperY()) {
|
||||
face = face.shift(CuboidDirection.Up, 1);
|
||||
}
|
||||
return new Cuboid(this.worldName, this.x1, face.getLowerY(), this.z1, this.x2, this.y2, this.z2);
|
||||
case North:
|
||||
while (face.containsOnly(0) && face.getLowerX() > this.getLowerX()) {
|
||||
face = face.shift(CuboidDirection.North, 1);
|
||||
}
|
||||
return new Cuboid(this.worldName, this.x1, this.y1, this.z1, face.getUpperX(), this.y2, this.z2);
|
||||
case South:
|
||||
while (face.containsOnly(0) && face.getUpperX() < this.getUpperX()) {
|
||||
face = face.shift(CuboidDirection.South, 1);
|
||||
}
|
||||
return new Cuboid(this.worldName, face.getLowerX(), this.y1, this.z1, this.x2, this.y2, this.z2);
|
||||
case East:
|
||||
while (face.containsOnly(0) && face.getLowerZ() > this.getLowerZ()) {
|
||||
face = face.shift(CuboidDirection.East, 1);
|
||||
}
|
||||
return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2, face.getUpperZ());
|
||||
case West:
|
||||
while (face.containsOnly(0) && face.getUpperZ() < this.getUpperZ()) {
|
||||
face = face.shift(CuboidDirection.West, 1);
|
||||
}
|
||||
return new Cuboid(this.worldName, this.x1, this.y1, face.getLowerZ(), this.x2, this.y2, this.z2);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid direction " + dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Cuboid representing the face of this Cuboid. The resulting Cuboid
|
||||
* will be one block thick in the axis perpendicular to the requested face.
|
||||
*
|
||||
* @param dir
|
||||
* - which face of the Cuboid to get
|
||||
* @return The Cuboid representing this Cuboid's requested face
|
||||
*/
|
||||
public Cuboid getFace(CuboidDirection dir) {
|
||||
switch (dir) {
|
||||
case Down:
|
||||
return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y1, this.z2);
|
||||
case Up:
|
||||
return new Cuboid(this.worldName, this.x1, this.y2, this.z1, this.x2, this.y2, this.z2);
|
||||
case North:
|
||||
return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x1, this.y2, this.z2);
|
||||
case South:
|
||||
return new Cuboid(this.worldName, this.x2, this.y1, this.z1, this.x2, this.y2, this.z2);
|
||||
case East:
|
||||
return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2, this.z1);
|
||||
case West:
|
||||
return new Cuboid(this.worldName, this.x1, this.y1, this.z2, this.x2, this.y2, this.z2);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid direction " + dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Cuboid contains only blocks of the given type
|
||||
*
|
||||
* @param blockId
|
||||
* - The block ID to check for
|
||||
* @return true if this Cuboid contains only blocks of the given type
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public boolean containsOnly(int blockId) {
|
||||
for (Block b : this) {
|
||||
if (b.getType().getId() != blockId)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Cuboid big enough to hold both this Cuboid and the given one.
|
||||
*
|
||||
* @param other
|
||||
* - The other cuboid.
|
||||
* @return A new Cuboid large enough to hold this Cuboid and the given
|
||||
* Cuboid
|
||||
*/
|
||||
public Cuboid getBoundingCuboid(Cuboid other) {
|
||||
if (other == null)
|
||||
return this;
|
||||
|
||||
int xMin = Math.min(this.getLowerX(), other.getLowerX());
|
||||
int yMin = Math.min(this.getLowerY(), other.getLowerY());
|
||||
int zMin = Math.min(this.getLowerZ(), other.getLowerZ());
|
||||
int xMax = Math.max(this.getUpperX(), other.getUpperX());
|
||||
int yMax = Math.max(this.getUpperY(), other.getUpperY());
|
||||
int zMax = Math.max(this.getUpperZ(), other.getUpperZ());
|
||||
|
||||
return new Cuboid(this.worldName, xMin, yMin, zMin, xMax, yMax, zMax);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a block relative to the lower NE point of the Cuboid.
|
||||
*
|
||||
* @param x
|
||||
* - The X co-ordinate
|
||||
* @param y
|
||||
* - The Y co-ordinate
|
||||
* @param z
|
||||
* - The Z co-ordinate
|
||||
* @return The block at the given position
|
||||
*/
|
||||
public Block getRelativeBlock(int x, int y, int z) {
|
||||
return this.getWorld().getBlockAt(this.x1 + x, this.y1 + y, this.z1 + z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a block relative to the lower NE point of the Cuboid in the given
|
||||
* World. This version of getRelativeBlock() should be used if being called
|
||||
* many times, to avoid excessive calls to getWorld().
|
||||
*
|
||||
* @param w
|
||||
* - The world
|
||||
* @param x
|
||||
* - The X co-ordinate
|
||||
* @param y
|
||||
* - The Y co-ordinate
|
||||
* @param z
|
||||
* - The Z co-ordinate
|
||||
* @return The block at the given position
|
||||
*/
|
||||
public Block getRelativeBlock(World w, int x, int y, int z) {
|
||||
return w.getBlockAt(this.x1 + x, y1 + y, this.z1 + z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of the chunks which are fully or partially contained in this
|
||||
* cuboid.
|
||||
*
|
||||
* @return A list of Chunk objects
|
||||
*/
|
||||
public List<Chunk> getChunks() {
|
||||
List<Chunk> res = new ArrayList<Chunk>();
|
||||
|
||||
World w = this.getWorld();
|
||||
int x1 = this.getLowerX() & ~0xf;
|
||||
int x2 = this.getUpperX() & ~0xf;
|
||||
int z1 = this.getLowerZ() & ~0xf;
|
||||
int z2 = this.getUpperZ() & ~0xf;
|
||||
for (int x = x1; x <= x2; x += 16) {
|
||||
for (int z = z1; z <= z2; z += 16) {
|
||||
res.add(w.getChunkAt(x >> 4, z >> 4));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public Iterator<Block> iterator() {
|
||||
return new CuboidIterator(this.getWorld(), this.x1, this.y1, this.z1, this.x2, this.y2, this.z2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cuboid clone() {
|
||||
return new Cuboid(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new String("Cuboid: " + this.worldName + "," + this.x1 + "," + this.y1 + "," + this.z1 + "=>" + this.x2
|
||||
+ "," + this.y2 + "," + this.z2);
|
||||
}
|
||||
|
||||
public class CuboidIterator implements Iterator<Block> {
|
||||
private World w;
|
||||
private int baseX, baseY, baseZ;
|
||||
private int x, y, z;
|
||||
private int sizeX, sizeY, sizeZ;
|
||||
|
||||
public CuboidIterator(World w, int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||
this.w = w;
|
||||
this.baseX = x1;
|
||||
this.baseY = y1;
|
||||
this.baseZ = z1;
|
||||
this.sizeX = Math.abs(x2 - x1) + 1;
|
||||
this.sizeY = Math.abs(y2 - y1) + 1;
|
||||
this.sizeZ = Math.abs(z2 - z1) + 1;
|
||||
this.x = this.y = this.z = 0;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return this.x < this.sizeX && this.y < this.sizeY && this.z < this.sizeZ;
|
||||
}
|
||||
|
||||
public Block next() {
|
||||
Block b = this.w.getBlockAt(this.baseX + this.x, this.baseY + this.y, this.baseZ + this.z);
|
||||
if (++x >= this.sizeX) {
|
||||
this.x = 0;
|
||||
if (++this.y >= this.sizeY) {
|
||||
this.y = 0;
|
||||
++this.z;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
}
|
||||
}
|
||||
|
||||
public enum CuboidDirection {
|
||||
North, East, South, West, Up, Down, Horizontal, Vertical, Both, Unknown;
|
||||
|
||||
public CuboidDirection opposite() {
|
||||
switch (this) {
|
||||
case North:
|
||||
return South;
|
||||
case East:
|
||||
return West;
|
||||
case South:
|
||||
return North;
|
||||
case West:
|
||||
return East;
|
||||
case Horizontal:
|
||||
return Vertical;
|
||||
case Vertical:
|
||||
return Horizontal;
|
||||
case Up:
|
||||
return Down;
|
||||
case Down:
|
||||
return Up;
|
||||
case Both:
|
||||
return Both;
|
||||
default:
|
||||
return Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
package fr.maxlego08.koth.zcore.utils;
|
||||
|
||||
public enum DefaultFontInfo{
|
||||
|
||||
A('A', 5),
|
||||
a('a', 5),
|
||||
B('B', 5),
|
||||
b('b', 5),
|
||||
C('C', 5),
|
||||
c('c', 5),
|
||||
D('D', 5),
|
||||
d('d', 5),
|
||||
E('E', 5),
|
||||
e('e', 5),
|
||||
F('F', 5),
|
||||
f('f', 4),
|
||||
G('G', 5),
|
||||
g('g', 5),
|
||||
H('H', 5),
|
||||
h('h', 5),
|
||||
I('I', 3),
|
||||
i('i', 1),
|
||||
J('J', 5),
|
||||
j('j', 5),
|
||||
K('K', 5),
|
||||
k('k', 4),
|
||||
L('L', 5),
|
||||
l('l', 2),
|
||||
M('M', 5),
|
||||
m('m', 5),
|
||||
N('N', 5),
|
||||
n('n', 5),
|
||||
O('O', 5),
|
||||
o('o', 5),
|
||||
P('P', 5),
|
||||
p('p', 5),
|
||||
Q('Q', 5),
|
||||
q('q', 5),
|
||||
R('R', 5),
|
||||
r('r', 5),
|
||||
S('S', 5),
|
||||
s('s', 5),
|
||||
T('T', 5),
|
||||
t('t', 3),
|
||||
U('U', 5),
|
||||
u('u', 5),
|
||||
V('V', 5),
|
||||
v('v', 5),
|
||||
W('W', 5),
|
||||
w('w', 5),
|
||||
X('X', 5),
|
||||
x('x', 5),
|
||||
Y('Y', 5),
|
||||
y('y', 5),
|
||||
Z('Z', 5),
|
||||
z('z', 5),
|
||||
NUM_1('1', 5),
|
||||
NUM_2('2', 5),
|
||||
NUM_3('3', 5),
|
||||
NUM_4('4', 5),
|
||||
NUM_5('5', 5),
|
||||
NUM_6('6', 5),
|
||||
NUM_7('7', 5),
|
||||
NUM_8('8', 5),
|
||||
NUM_9('9', 5),
|
||||
NUM_0('0', 5),
|
||||
EXCLAMATION_POINT('!', 1),
|
||||
AT_SYMBOL('@', 6),
|
||||
NUM_SIGN('#', 5),
|
||||
DOLLAR_SIGN('$', 5),
|
||||
PERCENT('%', 5),
|
||||
UP_ARROW('^', 5),
|
||||
AMPERSAND('&', 5),
|
||||
ASTERISK('*', 5),
|
||||
LEFT_PARENTHESIS('(', 4),
|
||||
RIGHT_PERENTHESIS(')', 4),
|
||||
MINUS('-', 5),
|
||||
UNDERSCORE('_', 5),
|
||||
PLUS_SIGN('+', 5),
|
||||
EQUALS_SIGN('=', 5),
|
||||
LEFT_CURL_BRACE('{', 4),
|
||||
RIGHT_CURL_BRACE('}', 4),
|
||||
LEFT_BRACKET('[', 3),
|
||||
RIGHT_BRACKET(']', 3),
|
||||
COLON(':', 1),
|
||||
SEMI_COLON(';', 1),
|
||||
DOUBLE_QUOTE('"', 3),
|
||||
SINGLE_QUOTE('\'', 1),
|
||||
LEFT_ARROW('<', 4),
|
||||
RIGHT_ARROW('>', 4),
|
||||
QUESTION_MARK('?', 5),
|
||||
SLASH('/', 5),
|
||||
BACK_SLASH('\\', 5),
|
||||
LINE('|', 1),
|
||||
TILDE('~', 5),
|
||||
TICK('`', 2),
|
||||
PERIOD('.', 1),
|
||||
COMMA(',', 1),
|
||||
SPACE(' ', 3),
|
||||
DEFAULT('a', 5),
|
||||
|
||||
|
||||
;
|
||||
|
||||
private char character;
|
||||
private int length;
|
||||
|
||||
DefaultFontInfo(char character, int length) {
|
||||
this.character = character;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public char getCharacter(){
|
||||
return this.character;
|
||||
}
|
||||
|
||||
public int getLength(){
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public int getBoldLength(){
|
||||
if(this == DefaultFontInfo.SPACE) return this.getLength();
|
||||
return this.length + 1;
|
||||
}
|
||||
|
||||
public static DefaultFontInfo getDefaultFontInfo(char c){
|
||||
for(DefaultFontInfo dFI : DefaultFontInfo.values()){
|
||||
if(dFI.getCharacter() == c) return dFI;
|
||||
}
|
||||
return DefaultFontInfo.DEFAULT;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package fr.maxlego08.koth.zcore.utils;
|
||||
|
||||
import fr.maxlego08.koth.save.Config;
|
||||
|
||||
public class ElapsedTime extends ZUtils {
|
||||
|
||||
private long start;
|
||||
private long end;
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
*/
|
||||
public ElapsedTime(String name) {
|
||||
super();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start
|
||||
*/
|
||||
public void start() {
|
||||
this.start = System.nanoTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop
|
||||
*/
|
||||
public void end() {
|
||||
this.end = System.nanoTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the start
|
||||
*/
|
||||
public long getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the end
|
||||
*/
|
||||
public long getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public long getElapsedTime() {
|
||||
return this.end - this.start;
|
||||
}
|
||||
|
||||
public void endDisplay() {
|
||||
this.end();
|
||||
if (Config.enableDebugTime)
|
||||
System.out.println("[ElapsedTime] " + name + " -> " + super.format(this.getElapsedTime(), ' '));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package fr.maxlego08.koth.zcore.utils;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
public abstract class LocationUtils extends PapiUtils{
|
||||
|
||||
/**
|
||||
* Change a string location to Location object
|
||||
*
|
||||
* @param location as String
|
||||
* @return string as location
|
||||
*/
|
||||
protected Location changeStringLocationToLocation(String string) {
|
||||
return changeStringLocationToLocationEye(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a string location to Location object
|
||||
*
|
||||
* @param location as string
|
||||
* @return string as locaiton
|
||||
*/
|
||||
protected Location changeStringLocationToLocationEye(String string) {
|
||||
String[] locationArray = string.split(",");
|
||||
World w = Bukkit.getServer().getWorld(locationArray[0]);
|
||||
float x = Float.parseFloat(locationArray[1]);
|
||||
float y = Float.parseFloat(locationArray[2]);
|
||||
float z = Float.parseFloat(locationArray[3]);
|
||||
if (locationArray.length == 6) {
|
||||
float yaw = Float.parseFloat(locationArray[4]);
|
||||
float pitch = Float.parseFloat(locationArray[5]);
|
||||
return new Location(w, x, y, z, yaw, pitch);
|
||||
}
|
||||
return new Location(w, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param location
|
||||
* @return location as string
|
||||
*/
|
||||
protected String changeLocationToString(Location location) {
|
||||
String ret = location.getWorld().getName() + "," + location.getBlockX() + "," + location.getBlockY() + ","
|
||||
+ location.getBlockZ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param location
|
||||
* @return location as String
|
||||
*/
|
||||
protected String changeLocationToStringEye(Location location) {
|
||||
String ret = location.getWorld().getName() + "," + location.getBlockX() + "," + location.getBlockY() + ","
|
||||
+ location.getBlockZ() + "," + location.getYaw() + "," + location.getPitch();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param chunk
|
||||
* @return string as Chunk
|
||||
*/
|
||||
protected Chunk changeStringChuncToChunk(String chunk) {
|
||||
String[] a = chunk.split(",");
|
||||
World w = Bukkit.getServer().getWorld(a[0]);
|
||||
return w.getChunkAt(Integer.valueOf(a[1]), Integer.valueOf(a[2]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param chunk
|
||||
* @return chunk as string
|
||||
*/
|
||||
protected String changeChunkToString(Chunk chunk) {
|
||||
return chunk.getWorld().getName() + "," + chunk.getX() + "," + chunk.getZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {@link
|
||||
* Cuboid}
|
||||
* @return cuboid as string
|
||||
*/
|
||||
protected String changeCuboidToString(Cuboid cuboid) {
|
||||
return cuboid.getWorld().getName() + "," + cuboid.getLowerX() + "," + cuboid.getLowerY() + ","
|
||||
+ cuboid.getLowerZ() + "," + ";" + cuboid.getWorld().getName() + "," + cuboid.getUpperX() + ","
|
||||
+ cuboid.getUpperY() + "," + cuboid.getUpperZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @return {@link Cuboid}
|
||||
*/
|
||||
protected Cuboid changeStringToCuboid(String str) {
|
||||
|
||||
String parsedCuboid[] = str.split(";");
|
||||
String parsedFirstLoc[] = parsedCuboid[0].split(",");
|
||||
String parsedSecondLoc[] = parsedCuboid[1].split(",");
|
||||
|
||||
String firstWorldName = parsedFirstLoc[0];
|
||||
double firstX = Double.valueOf(parsedFirstLoc[1]);
|
||||
double firstY = Double.valueOf(parsedFirstLoc[2]);
|
||||
double firstZ = Double.valueOf(parsedFirstLoc[3]);
|
||||
|
||||
String secondWorldName = parsedSecondLoc[0];
|
||||
double secondX = Double.valueOf(parsedSecondLoc[1]);
|
||||
double secondY = Double.valueOf(parsedSecondLoc[2]);
|
||||
double secondZ = Double.valueOf(parsedSecondLoc[3]);
|
||||
|
||||
Location l1 = new Location(Bukkit.getWorld(firstWorldName), firstX, firstY, firstZ);
|
||||
|
||||
Location l2 = new Location(Bukkit.getWorld(secondWorldName), secondX, secondY, secondZ);
|
||||
|
||||
return new Cuboid(l1, l2);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
package fr.maxlego08.koth.zcore.utils;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
import fr.maxlego08.koth.zcore.utils.nms.NMSUtils;
|
||||
import fr.maxlego08.koth.zcore.utils.players.ActionBar;
|
||||
|
||||
/**
|
||||
* Allows you to manage messages sent to players and the console
|
||||
*
|
||||
* @author Maxence
|
||||
*
|
||||
*/
|
||||
public abstract class MessageUtils extends LocationUtils {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player
|
||||
* @param message
|
||||
* @param args
|
||||
*/
|
||||
protected void messageWO(CommandSender player, Message message, Object... args) {
|
||||
player.sendMessage(getMessage(message, args));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player
|
||||
* @param message
|
||||
* @param args
|
||||
*/
|
||||
protected void messageWO(CommandSender player, String message, Object... args) {
|
||||
player.sendMessage(getMessage(message, args));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sender
|
||||
* @param message
|
||||
* @param args
|
||||
*/
|
||||
protected void message(CommandSender sender, String message, Object... args) {
|
||||
sender.sendMessage(Message.PREFIX.msg() + getMessage(message, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to send a message to a command sender
|
||||
*
|
||||
* @param sender
|
||||
* User who sent the command
|
||||
* @param message
|
||||
* The message - Using the Message enum for simplified message
|
||||
* management
|
||||
* @param args
|
||||
* The arguments - The arguments work in pairs, you must put for
|
||||
* example %test% and then the value
|
||||
*/
|
||||
protected void message(CommandSender sender, Message message, Object... args) {
|
||||
|
||||
if (sender instanceof ConsoleCommandSender) {
|
||||
if (message.getMessages().size() > 0) {
|
||||
message.getMessages().forEach(msg -> sender.sendMessage(Message.PREFIX.msg() + getMessage(msg, args)));
|
||||
} else {
|
||||
sender.sendMessage(Message.PREFIX.msg() + getMessage(message, args));
|
||||
}
|
||||
} else {
|
||||
|
||||
Player player = (Player) sender;
|
||||
switch (message.getType()) {
|
||||
case CENTER:
|
||||
if (message.getMessages().size() > 0) {
|
||||
message.getMessages()
|
||||
.forEach(msg -> sender.sendMessage(this.getCenteredMessage(this.papi(getMessage(msg, args), player))));
|
||||
} else {
|
||||
sender.sendMessage(this.getCenteredMessage(this.papi(getMessage(message, args), player)));
|
||||
}
|
||||
|
||||
break;
|
||||
case ACTION:
|
||||
this.actionMessage(player, message, args);
|
||||
break;
|
||||
case TCHAT:
|
||||
if (message.getMessages().size() > 0) {
|
||||
message.getMessages()
|
||||
.forEach(msg -> sender.sendMessage(this.papi(Message.PREFIX.msg() + getMessage(msg, args), player)));
|
||||
} else {
|
||||
sender.sendMessage(this.papi(Message.PREFIX.msg() + getMessage(message, args), player));
|
||||
}
|
||||
break;
|
||||
case TITLE:
|
||||
// title message management
|
||||
String title = message.getTitle();
|
||||
String subTitle = message.getSubTitle();
|
||||
int fadeInTime = message.getStart();
|
||||
int showTime = message.getTime();
|
||||
int fadeOutTime = message.getEnd();
|
||||
this.title(player, this.papi(this.getMessage(title, args), player), this.papi(this.getMessage(subTitle, args), player), fadeInTime, showTime,
|
||||
fadeOutTime);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player
|
||||
* @param message
|
||||
* @param args
|
||||
*/
|
||||
protected void broadcast(Message message, Object... args) {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
message(player, message, args);
|
||||
}
|
||||
message(Bukkit.getConsoleSender(), message, args);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player
|
||||
* @param message
|
||||
* @param args
|
||||
*/
|
||||
protected void actionMessage(Player player, Message message, Object... args) {
|
||||
ActionBar.sendActionBar(player, this.papi(getMessage(message, args), player));
|
||||
}
|
||||
|
||||
protected String getMessage(Message message, Object... args) {
|
||||
return getMessage(message.getMessage(), args);
|
||||
}
|
||||
|
||||
protected String getMessage(String message, Object... args) {
|
||||
if (args.length % 2 != 0) {
|
||||
System.err.println("Impossible to apply the method for messages.");
|
||||
} else {
|
||||
for (int a = 0; a < args.length; a += 2) {
|
||||
String replace = args[a].toString();
|
||||
String to = args[a + 1].toString();
|
||||
message = message.replace(replace, to);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
protected final Class<?> getNMSClass(String name) {
|
||||
try {
|
||||
return Class.forName("net.minecraft.server."
|
||||
+ Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3] + "." + name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send title to player
|
||||
*
|
||||
* @param player
|
||||
* @param title
|
||||
* @param subtitle
|
||||
* @param fadeInTime
|
||||
* @param showTime
|
||||
* @param fadeOutTime
|
||||
*/
|
||||
protected void title(Player player, String title, String subtitle, int fadeInTime, int showTime, int fadeOutTime) {
|
||||
|
||||
if (NMSUtils.isNewVersion()) {
|
||||
player.sendTitle(title, subtitle, fadeInTime, showTime, fadeOutTime);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Object chatTitle = getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", String.class)
|
||||
.invoke(null, "{\"text\": \"" + title + "\"}");
|
||||
Constructor<?> titleConstructor = getNMSClass("PacketPlayOutTitle").getConstructor(
|
||||
getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0], getNMSClass("IChatBaseComponent"),
|
||||
int.class, int.class, int.class);
|
||||
Object packet = titleConstructor.newInstance(
|
||||
getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0].getField("TITLE").get(null), chatTitle,
|
||||
fadeInTime, showTime, fadeOutTime);
|
||||
|
||||
Object chatsTitle = getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", String.class)
|
||||
.invoke(null, "{\"text\": \"" + subtitle + "\"}");
|
||||
Constructor<?> timingTitleConstructor = getNMSClass("PacketPlayOutTitle").getConstructor(
|
||||
getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0], getNMSClass("IChatBaseComponent"),
|
||||
int.class, int.class, int.class);
|
||||
Object timingPacket = timingTitleConstructor.newInstance(
|
||||
getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0].getField("SUBTITLE").get(null),
|
||||
chatsTitle, fadeInTime, showTime, fadeOutTime);
|
||||
|
||||
sendPacket(player, packet);
|
||||
sendPacket(player, timingPacket);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param player
|
||||
* @param packet
|
||||
*/
|
||||
protected final void sendPacket(Player player, Object packet) {
|
||||
try {
|
||||
Object handle = player.getClass().getMethod("getHandle").invoke(player);
|
||||
Object playerConnection = handle.getClass().getField("playerConnection").get(handle);
|
||||
playerConnection.getClass().getMethod("sendPacket", getNMSClass("Packet")).invoke(playerConnection, packet);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private final transient static int CENTER_PX = 154;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param message
|
||||
* @return message
|
||||
*/
|
||||
protected String getCenteredMessage(String message) {
|
||||
if (message == null || message.equals(""))
|
||||
return "";
|
||||
message = ChatColor.translateAlternateColorCodes('&', message);
|
||||
|
||||
int messagePxSize = 0;
|
||||
boolean previousCode = false;
|
||||
boolean isBold = false;
|
||||
|
||||
for (char c : message.toCharArray()) {
|
||||
if (c == '§') {
|
||||
previousCode = true;
|
||||
} else if (previousCode) {
|
||||
previousCode = false;
|
||||
if (c == 'l' || c == 'L') {
|
||||
isBold = true;
|
||||
} else
|
||||
isBold = false;
|
||||
} else {
|
||||
DefaultFontInfo dFI = DefaultFontInfo.getDefaultFontInfo(c);
|
||||
messagePxSize += isBold ? dFI.getBoldLength() : dFI.getLength();
|
||||
messagePxSize++;
|
||||
}
|
||||
}
|
||||
|
||||
int halvedMessageSize = messagePxSize / 2;
|
||||
int toCompensate = CENTER_PX - halvedMessageSize;
|
||||
int spaceLength = DefaultFontInfo.SPACE.getLength() + 1;
|
||||
int compensated = 0;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (compensated < toCompensate) {
|
||||
sb.append(" ");
|
||||
compensated += spaceLength;
|
||||
}
|
||||
return sb.toString() + message;
|
||||
}
|
||||
|
||||
protected void broadcastCenterMessage(List<String> messages) {
|
||||
messages.stream().map(e -> e = getCenteredMessage(e)).forEach(e -> {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
messageWO(player, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void broadcastAction(String message) {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
ActionBar.sendActionBar(player, papi(message, player));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package fr.maxlego08.koth.zcore.utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import fr.maxlego08.koth.placeholder.Placeholder;
|
||||
|
||||
public class PapiUtils extends TranslationHelper {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param itemStack
|
||||
* @param player
|
||||
* @return itemstack
|
||||
*/
|
||||
protected ItemStack papi(ItemStack itemStack, Player player) {
|
||||
|
||||
if (itemStack == null) {
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
|
||||
if (itemMeta.hasDisplayName()) {
|
||||
itemMeta.setDisplayName(Placeholder.getPlaceholder().setPlaceholders(player, itemMeta.getDisplayName()));
|
||||
}
|
||||
|
||||
if (itemMeta.hasLore()) {
|
||||
itemMeta.setLore(Placeholder.getPlaceholder().setPlaceholders(player, itemMeta.getLore()));
|
||||
}
|
||||
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
return itemStack;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param placeHolder
|
||||
* @param player
|
||||
* @return string
|
||||
*/
|
||||
public String papi(String placeHolder, Player player) {
|
||||
return Placeholder.getPlaceholder().setPlaceholders(player, placeHolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a list into a list with placeholder API
|
||||
*
|
||||
* @param placeHolder
|
||||
* @param player
|
||||
* @return placeholders
|
||||
*/
|
||||
public List<String> papi(List<String> placeHolder, Player player) {
|
||||
return Placeholder.getPlaceholder().setPlaceholders(player, placeHolder);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package fr.maxlego08.koth.zcore.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.nms.NMSUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* Based on
|
||||
* https://www.spigotmc.org/threads/how-to-get-a-players-texture.244966/
|
||||
*
|
||||
*/
|
||||
public class PlayerSkin {
|
||||
|
||||
private static final Map<String, String> textures = new HashMap<String, String>();
|
||||
private static ExecutorService pool = Executors.newCachedThreadPool();
|
||||
|
||||
public static String getTexture(Player player) {
|
||||
if (textures.containsKey(player.getName())) {
|
||||
return textures.get(player.getName());
|
||||
}
|
||||
String[] textures = getFromPlayer(player);
|
||||
try {
|
||||
String texture = textures[0];
|
||||
PlayerSkin.textures.put(player.getName(), texture);
|
||||
return texture;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getTexture(String name) {
|
||||
if (textures.containsKey(name)) {
|
||||
return textures.get(name);
|
||||
}
|
||||
|
||||
Player player = Bukkit.getPlayer(name);
|
||||
if (player != null) {
|
||||
return getTexture(player);
|
||||
}
|
||||
|
||||
pool.execute(() -> {
|
||||
String[] textures = getFromName(name);
|
||||
try {
|
||||
String texture = textures[0];
|
||||
PlayerSkin.textures.put(name, texture);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] getFromPlayer(Player playerBukkit) {
|
||||
GameProfile profile = getProfile(playerBukkit);
|
||||
Property property = profile.getProperties().get("textures").iterator().next();
|
||||
String texture = property.getValue();
|
||||
String signature = property.getSignature();
|
||||
|
||||
return new String[] { texture, signature };
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static String[] getFromName(String name) {
|
||||
try {
|
||||
URL url_0 = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
|
||||
InputStreamReader reader_0 = new InputStreamReader(url_0.openStream());
|
||||
String uuid = new JsonParser().parse(reader_0).getAsJsonObject().get("id").getAsString();
|
||||
|
||||
URL url_1 = new URL(
|
||||
"https://sessionserver.mojang.com/session/minecraft/profile/" + uuid + "?unsigned=false");
|
||||
InputStreamReader reader_1 = new InputStreamReader(url_1.openStream());
|
||||
JsonObject textureProperty = new JsonParser().parse(reader_1).getAsJsonObject().get("properties")
|
||||
.getAsJsonArray().get(0).getAsJsonObject();
|
||||
String texture = textureProperty.get("value").getAsString();
|
||||
String signature = textureProperty.get("signature").getAsString();
|
||||
|
||||
return new String[] { texture, signature };
|
||||
} catch (IOException e) {
|
||||
System.err.println("Could not get skin data from session servers!");
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static GameProfile getProfile(Player player) {
|
||||
|
||||
try {
|
||||
Object entityPlayer = player.getClass().getMethod("getHandle").invoke(player);
|
||||
return (GameProfile) entityPlayer.getClass().getMethod(getMethodName()).invoke(entityPlayer);
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
|
||||
| SecurityException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getMethodName() {
|
||||
double version = NMSUtils.getNMSVersion();
|
||||
if (version == 1.18) {
|
||||
return "fp";
|
||||
} else if (version == 1.19) {
|
||||
return "fz";
|
||||
}
|
||||
return "getProfile";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package fr.maxlego08.koth.zcore.utils;
|
||||
|
||||
public class ProgressBar {
|
||||
|
||||
private final int lenght;
|
||||
private final char symbol;
|
||||
private final String completedColor;
|
||||
private final String notCompletedColor;
|
||||
|
||||
/**
|
||||
* @param lenght
|
||||
* @param symbol
|
||||
* @param completedColor
|
||||
* @param notCompletedColor
|
||||
*/
|
||||
public ProgressBar(int lenght, char symbol, String completedColor, String notCompletedColor) {
|
||||
super();
|
||||
this.lenght = lenght;
|
||||
this.symbol = symbol;
|
||||
this.completedColor = completedColor;
|
||||
this.notCompletedColor = notCompletedColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lenght
|
||||
*/
|
||||
public int getLenght() {
|
||||
return lenght;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the symbol
|
||||
*/
|
||||
public char getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the completedColor
|
||||
*/
|
||||
public String getCompletedColor() {
|
||||
return completedColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the notCompletedColor
|
||||
*/
|
||||
public String getNotCompletedColor() {
|
||||
return notCompletedColor;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package fr.maxlego08.koth.zcore.utils;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomString {
|
||||
|
||||
/**
|
||||
* Generate a random string.
|
||||
*/
|
||||
public String nextString() {
|
||||
for (int idx = 0; idx < buf.length; ++idx)
|
||||
buf[idx] = symbols[random.nextInt(symbols.length)];
|
||||
return new String(buf);
|
||||
}
|
||||
|
||||
public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
public static final String lower = upper.toLowerCase(Locale.ROOT);
|
||||
|
||||
public static final String digits = "0123456789";
|
||||
|
||||
public static final String alphanum = upper + lower + digits;
|
||||
|
||||
private final Random random;
|
||||
|
||||
private final char[] symbols;
|
||||
|
||||
private final char[] buf;
|
||||
|
||||
public RandomString(int length, Random random, String symbols) {
|
||||
if (length < 1) throw new IllegalArgumentException();
|
||||
if (symbols.length() < 2) throw new IllegalArgumentException();
|
||||
this.random = Objects.requireNonNull(random);
|
||||
this.symbols = symbols.toCharArray();
|
||||
this.buf = new char[length];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an alphanumeric string generator.
|
||||
*/
|
||||
public RandomString(int length, Random random) {
|
||||
this(length, random, alphanum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an alphanumeric strings from a secure generator.
|
||||
*/
|
||||
public RandomString(int length) {
|
||||
this(length, new SecureRandom());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create session identifiers.
|
||||
*/
|
||||
public RandomString() {
|
||||
this(21);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package fr.maxlego08.koth.zcore.utils;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.plugins.Plugins;
|
||||
import fr.maxlego08.ztranslator.api.Translator;
|
||||
|
||||
public abstract class TranslationHelper {
|
||||
|
||||
/**
|
||||
* Allows to translate the item name, if the zTranslator plugin is active, then the translated name will be retrieved
|
||||
*
|
||||
* @param offlinePlayer
|
||||
* @param itemStack
|
||||
* @return item name
|
||||
*/
|
||||
protected String getItemName(OfflinePlayer offlinePlayer, ItemStack itemStack) {
|
||||
|
||||
if (itemStack == null) {
|
||||
return "";
|
||||
|
||||
}
|
||||
if (itemStack.hasItemMeta() && itemStack.getItemMeta().hasDisplayName()) {
|
||||
return itemStack.getItemMeta().getDisplayName();
|
||||
}
|
||||
|
||||
if (Bukkit.getPluginManager().isPluginEnabled(Plugins.ZTRANSLATOR.getName())) {
|
||||
|
||||
RegisteredServiceProvider<Translator> provider = Bukkit.getServer().getServicesManager()
|
||||
.getRegistration(Translator.class);
|
||||
Translator translator = provider.getProvider();
|
||||
return translator.translate(offlinePlayer, itemStack);
|
||||
}
|
||||
|
||||
String name = itemStack.serialize().get("type").toString().replace("_", " ").toLowerCase();
|
||||
return name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to translate the item name, if the zTranslator plugin is active, then the translated name will be retrieved
|
||||
*
|
||||
* @param itemStack
|
||||
* @return item name
|
||||
*/
|
||||
protected String getItemName(ItemStack itemStack) {
|
||||
|
||||
if (itemStack == null) {
|
||||
return "";
|
||||
|
||||
}
|
||||
if (itemStack.hasItemMeta() && itemStack.getItemMeta().hasDisplayName()) {
|
||||
return itemStack.getItemMeta().getDisplayName();
|
||||
}
|
||||
|
||||
if (Bukkit.getPluginManager().isPluginEnabled(Plugins.ZTRANSLATOR.getName())) {
|
||||
|
||||
RegisteredServiceProvider<Translator> provider = Bukkit.getServer().getServicesManager()
|
||||
.getRegistration(Translator.class);
|
||||
Translator translator = provider.getProvider();
|
||||
return translator.translate(itemStack);
|
||||
}
|
||||
|
||||
String name = itemStack.serialize().get("type").toString().replace("_", " ").toLowerCase();
|
||||
return name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,153 @@
|
|||
package fr.maxlego08.koth.zcore.utils.builder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.storage.Persist;
|
||||
import fr.maxlego08.koth.zcore.utils.storage.Savable;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class CooldownBuilder implements Savable {
|
||||
|
||||
public static Map<String, Map<UUID, Long>> cooldowns = new HashMap<>();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
public static Map<UUID, Long> getCooldownMap(String key) {
|
||||
return cooldowns.getOrDefault(key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static void clear() {
|
||||
cooldowns.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public static void createCooldown(String key) {
|
||||
cooldowns.putIfAbsent(key, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param joueur
|
||||
*/
|
||||
public static void removeCooldown(String key, UUID uuid) {
|
||||
|
||||
createCooldown(key);
|
||||
|
||||
getCooldownMap(key).remove(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param player
|
||||
*/
|
||||
public static void removeCooldown(String key, Player player) {
|
||||
removeCooldown(key, player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param joueur
|
||||
* @param seconds
|
||||
*/
|
||||
public static void addCooldown(String key, UUID uuid, int seconds) {
|
||||
|
||||
createCooldown(key);
|
||||
|
||||
long next = System.currentTimeMillis() + seconds * 1000L;
|
||||
getCooldownMap(key).put(uuid, Long.valueOf(next));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param player
|
||||
* @param seconds
|
||||
*/
|
||||
public static void addCooldown(String key, Player player, int seconds) {
|
||||
addCooldown(key, player.getUniqueId(), seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param uuid
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isCooldown(String key, UUID uuid) {
|
||||
|
||||
createCooldown(key);
|
||||
Map<UUID, Long> map = cooldowns.get(key);
|
||||
|
||||
return (map.containsKey(uuid)) && (System.currentTimeMillis() <= ((Long) map.get(uuid)).longValue());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param player
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isCooldown(String key, Player player) {
|
||||
return isCooldown(key, player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param uuid
|
||||
* @return long
|
||||
*/
|
||||
public static long getCooldown(String key, UUID uuid) {
|
||||
|
||||
createCooldown(key);
|
||||
Map<UUID, Long> map = cooldowns.get(key);
|
||||
|
||||
return ((Long) map.getOrDefault(uuid, 0l)).longValue() - System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param player
|
||||
* @return long
|
||||
*/
|
||||
public static long getCooldownPlayer(String key, Player player) {
|
||||
return getCooldown(key, player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
public static String getCooldownAsString(String key, UUID player) {
|
||||
return TimerBuilder.getStringTime(getCooldown(key, player) / 1000);
|
||||
}
|
||||
|
||||
private static transient CooldownBuilder i = new CooldownBuilder();
|
||||
|
||||
@Override
|
||||
public void save(Persist persist) {
|
||||
persist.save(i, "cooldowns");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Persist persist) {
|
||||
persist.loadOrSaveDefault(i, CooldownBuilder.class, "cooldowns");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,368 @@
|
|||
package fr.maxlego08.koth.zcore.utils.builder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Maxlego08
|
||||
*
|
||||
*/
|
||||
public class ItemBuilder extends ZUtils implements Cloneable {
|
||||
|
||||
private ItemStack item;
|
||||
private final Material material;
|
||||
private ItemMeta meta;
|
||||
private int data;
|
||||
private int amount;
|
||||
private String name;
|
||||
private List<String> lore;
|
||||
private List<ItemFlag> flags;
|
||||
private int durability;
|
||||
private Map<Enchantment, Integer> enchantments;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param material
|
||||
* @param data
|
||||
* @param amount
|
||||
* @param name
|
||||
* @param lore
|
||||
* @param flags
|
||||
* @param enchantments
|
||||
*/
|
||||
public ItemBuilder(Material material, int data, int amount, String name, List<String> lore, List<ItemFlag> flags,
|
||||
Map<Enchantment, Integer> enchantments) {
|
||||
super();
|
||||
this.material = material;
|
||||
this.data = data;
|
||||
this.amount = amount;
|
||||
this.name = name;
|
||||
this.lore = lore;
|
||||
this.flags = flags;
|
||||
this.enchantments = enchantments;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param material
|
||||
*/
|
||||
public ItemBuilder(Material material) {
|
||||
this(material, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param material
|
||||
* @param amount
|
||||
*/
|
||||
public ItemBuilder(Material material, int amount) {
|
||||
this(material, amount, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param material
|
||||
* @param amount
|
||||
* @param data
|
||||
*/
|
||||
public ItemBuilder(Material material, int amount, int data) {
|
||||
this(material, amount, data, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param material
|
||||
* @param amount
|
||||
* @param data
|
||||
* @param name
|
||||
*/
|
||||
public ItemBuilder(Material material, int amount, int data, String name) {
|
||||
this(material, data, amount, name, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param material
|
||||
* @param amount
|
||||
* @param name
|
||||
*/
|
||||
public ItemBuilder(Material material, int amount, String name) {
|
||||
this(material, 0, amount, name, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param material
|
||||
* @param name
|
||||
*/
|
||||
public ItemBuilder(Material material, String name) {
|
||||
this(material, 0, 1, name, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param material
|
||||
* @param flags
|
||||
*/
|
||||
public ItemBuilder(Material material, ItemFlag... flags) {
|
||||
this(material, 0, 1, null, null, Arrays.asList(flags), null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param material
|
||||
* @param lore
|
||||
*/
|
||||
public ItemBuilder(Material material, String... lore) {
|
||||
this(material, 0, 1, null, Arrays.asList(lore), null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* add enchant
|
||||
*
|
||||
* @param enchantment
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public ItemBuilder addEnchant(Enchantment enchantment, int value) {
|
||||
if (enchantments == null)
|
||||
enchantments = new HashMap<Enchantment, Integer>();
|
||||
enchantments.put(enchantment, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* add flags
|
||||
*
|
||||
* @param flags
|
||||
* @return
|
||||
*/
|
||||
public ItemBuilder setFlag(ItemFlag... flags) {
|
||||
this.flags = Arrays.asList(flags);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param flag
|
||||
* @return
|
||||
*/
|
||||
public ItemBuilder setFlag(ItemFlag flag) {
|
||||
if (flags == null)
|
||||
flags = new ArrayList<ItemFlag>();
|
||||
this.flags.add(flag);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param format
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
public ItemBuilder addLine(String format, Object... args) {
|
||||
if (lore == null)
|
||||
lore = new ArrayList<String>();
|
||||
lore.add(String.format(format, args));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param format
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
public ItemBuilder addLine(String format) {
|
||||
if (lore == null)
|
||||
lore = new ArrayList<String>();
|
||||
lore.add(format);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param lores
|
||||
* @return
|
||||
*/
|
||||
public ItemBuilder setLore(String... lores) {
|
||||
this.lore = Arrays.asList(lores);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public ItemBuilder setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param durability
|
||||
* @return
|
||||
*/
|
||||
public ItemBuilder durability(int durability) {
|
||||
this.durability = durability;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ItemBuilder glow() {
|
||||
addEnchant(material != Material.BOW ? Enchantment.ARROW_INFINITE : Enchantment.LUCK, 10);
|
||||
setFlag(ItemFlag.HIDE_ENCHANTS);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public ItemBuilder owner(Player name) {
|
||||
return owner(name.getName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public ItemBuilder owner(String name) {
|
||||
if ((material == getMaterial(144)) || (material == getMaterial(397))) {
|
||||
SkullMeta smeta = (SkullMeta) meta;
|
||||
smeta.setOwner(name);
|
||||
if (meta == null)
|
||||
build();
|
||||
meta = smeta;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public ItemStack build() {
|
||||
item = new ItemStack(material, amount, (short) data);
|
||||
|
||||
if (meta == null)
|
||||
meta = item.getItemMeta();
|
||||
|
||||
if (flags != null)
|
||||
flags.forEach(flag -> meta.addItemFlags(flag));
|
||||
|
||||
if (name != null)
|
||||
meta.setDisplayName(name);
|
||||
|
||||
if (lore != null)
|
||||
meta.setLore(lore);
|
||||
|
||||
if (enchantments != null)
|
||||
enchantments.forEach((e, l) -> meta.addEnchant(e, l, true));
|
||||
|
||||
if (durability != 0)
|
||||
item.setDurability((short) durability);
|
||||
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone
|
||||
*/
|
||||
public ItemBuilder clone() {
|
||||
try {
|
||||
return (ItemBuilder) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the item
|
||||
*/
|
||||
public ItemStack getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the material
|
||||
*/
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the meta
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public ItemMeta getMeta() {
|
||||
if (meta == null)
|
||||
meta = new ItemStack(material, amount, (short) data).getItemMeta();
|
||||
return meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the data
|
||||
*/
|
||||
public int getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the amount
|
||||
*/
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lore
|
||||
*/
|
||||
public List<String> getLore() {
|
||||
return lore;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the flags
|
||||
*/
|
||||
public List<ItemFlag> getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the durability
|
||||
*/
|
||||
public int getDurability() {
|
||||
return durability;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the enchantments
|
||||
*/
|
||||
public Map<Enchantment, Integer> getEnchantments() {
|
||||
return enchantments;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
package fr.maxlego08.koth.zcore.utils.builder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.meta.PotionMeta;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Maxlego08
|
||||
*
|
||||
*/
|
||||
public class PotionBuilder extends ItemBuilder {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
* @param amount
|
||||
* @param name
|
||||
* @param lore
|
||||
* @param flags
|
||||
* @param enchantments
|
||||
*/
|
||||
public PotionBuilder(int data, int amount, String name, List<String> lore, List<ItemFlag> flags,
|
||||
Map<Enchantment, Integer> enchantments) {
|
||||
super(Material.POTION, data, amount, name, lore, flags, enchantments);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param amount
|
||||
* @param data
|
||||
* @param name
|
||||
*/
|
||||
public PotionBuilder(int amount, int data, String name) {
|
||||
super(Material.POTION, amount, data, name);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param amount
|
||||
* @param data
|
||||
*/
|
||||
public PotionBuilder(int amount, int data) {
|
||||
super(Material.POTION, amount, data);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param amount
|
||||
* @param name
|
||||
*/
|
||||
public PotionBuilder(int amount, String name) {
|
||||
super(Material.POTION, amount, name);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param amount
|
||||
*/
|
||||
public PotionBuilder(int amount) {
|
||||
super(Material.POTION, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param flags
|
||||
*/
|
||||
public PotionBuilder(ItemFlag... flags) {
|
||||
super(Material.POTION, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param lore
|
||||
*/
|
||||
public PotionBuilder(String... lore) {
|
||||
super(Material.POTION, lore);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public PotionBuilder(String name) {
|
||||
super(Material.POTION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public PotionBuilder() {
|
||||
super(Material.POTION);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public PotionMeta getMeta() {
|
||||
return (PotionMeta) super.getMeta();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
/**
|
||||
*
|
||||
* @param potionEffectType
|
||||
* @return
|
||||
*/
|
||||
public PotionBuilder effect(PotionEffectType potionEffectType) {
|
||||
this.getMeta().setMainEffect(potionEffectType);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param potionEffectType
|
||||
* @param duration
|
||||
* @param values
|
||||
* @return
|
||||
*/
|
||||
public PotionBuilder effect(PotionEffectType potionEffectType, int duration, int values) {
|
||||
this.getMeta().addCustomEffect(new PotionEffect(potionEffectType, duration, values), true);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package fr.maxlego08.koth.zcore.utils.builder;
|
||||
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
|
||||
public class TimerBuilder {
|
||||
|
||||
public static String getFormatLongDays(long temps) {
|
||||
long totalSecs = temps / 1000L;
|
||||
|
||||
long days = totalSecs / 86400l;
|
||||
long hours = totalSecs % 86400l / 3600l;
|
||||
long minutes = totalSecs % 3600L / 60L;
|
||||
long seconds = totalSecs % 60L;
|
||||
|
||||
String message = Message.TIME_DAY.msg();
|
||||
message = message.replace("%second%", (seconds <= 1 ? Message.FORMAT_SECOND : Message.FORMAT_SECONDS).msg());
|
||||
message = message.replace("%minute%", (minutes <= 1 ? Message.FORMAT_MINUTE : Message.FORMAT_MINUTES).msg());
|
||||
message = message.replace("%hour%", (hours <= 1 ? Message.FORMAT_HOUR : Message.FORMAT_HOURS).msg());
|
||||
message = message.replace("%day%", (days <= 1 ? Message.FORMAT_DAY : Message.FORMAT_DAYS).msg());
|
||||
return format(String.format(message, days, hours, minutes, seconds));
|
||||
}
|
||||
|
||||
public static String getFormatLongHours(long temps) {
|
||||
long totalSecs = temps / 1000L;
|
||||
|
||||
long hours = totalSecs / 3600L;
|
||||
long minutes = totalSecs % 3600L / 60L;
|
||||
long seconds = totalSecs % 60L;
|
||||
|
||||
String message = Message.TIME_HOUR.msg();
|
||||
message = message.replace("%second%", (seconds <= 1 ? Message.FORMAT_SECOND : Message.FORMAT_SECONDS).msg());
|
||||
message = message.replace("%minute%", (minutes <= 1 ? Message.FORMAT_MINUTE : Message.FORMAT_MINUTES).msg());
|
||||
message = message.replace("%hour%", (hours <= 1 ? Message.FORMAT_HOUR : Message.FORMAT_HOURS).msg());
|
||||
return format(String.format(message, hours, minutes, seconds));
|
||||
}
|
||||
|
||||
public static String getFormatLongMinutes(long temps) {
|
||||
|
||||
long totalSecs = temps / 1000L;
|
||||
|
||||
long minutes = totalSecs % 3600L / 60L;
|
||||
long seconds = totalSecs % 60L;
|
||||
|
||||
String message = Message.TIME_MINUTE.msg();
|
||||
message = message.replace("%second%", (seconds <= 1 ? Message.FORMAT_SECOND : Message.FORMAT_SECONDS).msg());
|
||||
message = message.replace("%minute%", (minutes <= 1 ? Message.FORMAT_MINUTE : Message.FORMAT_MINUTES).msg());
|
||||
return format(String.format(message, minutes, seconds));
|
||||
}
|
||||
|
||||
public static String getFormatLongSecondes(long temps) {
|
||||
long totalSecs = temps / 1000L;
|
||||
|
||||
long seconds = totalSecs % 60L;
|
||||
String message = Message.TIME_SECOND.msg();
|
||||
message = message.replace("%second%", (seconds <= 1 ? Message.FORMAT_SECOND : Message.FORMAT_SECONDS).msg());
|
||||
return format(String.format(message, seconds));
|
||||
}
|
||||
|
||||
public static String getStringTime(long second) {
|
||||
if (second < 60) {
|
||||
return (TimerBuilder.getFormatLongSecondes(second * 1000l));
|
||||
} else if (second >= 60 && second < 3600) {
|
||||
return (TimerBuilder.getFormatLongMinutes(second * 1000l));
|
||||
} else if (second >= 3600 && second < 86400) {
|
||||
return (TimerBuilder.getFormatLongHours(second * 1000l));
|
||||
} else {
|
||||
return (TimerBuilder.getFormatLongDays(second * 1000l));
|
||||
}
|
||||
}
|
||||
|
||||
public static String format(String message) {
|
||||
message = message.replace(" 00 " + Message.FORMAT_SECOND.msg(), "");
|
||||
message = message.replace(" 00 " + Message.FORMAT_HOUR.msg(), "");
|
||||
message = message.replace(" 00 " + Message.FORMAT_DAY.msg(), "");
|
||||
message = message.replace(" 00 " + Message.FORMAT_MINUTE.msg(), "");
|
||||
return message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,255 @@
|
|||
package fr.maxlego08.koth.zcore.utils.commands;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class Arguments extends ZUtils {
|
||||
|
||||
protected String[] args;
|
||||
protected int parentCount = 0;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
protected String argAsString(int index) {
|
||||
try {
|
||||
return this.args[index + this.parentCount];
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
protected String argAsString(int index, String defaultValue) {
|
||||
try {
|
||||
return this.args[index + this.parentCount];
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
protected boolean argAsBoolean(int index) {
|
||||
return Boolean.valueOf(argAsString(index));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
protected boolean argAsBoolean(int index, boolean defaultValue) {
|
||||
try {
|
||||
return Boolean.valueOf(argAsString(index));
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
protected int argAsInteger(int index) {
|
||||
return Integer.valueOf(argAsString(index));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
protected int argAsInteger(int index, int defaultValue) {
|
||||
try {
|
||||
return Integer.valueOf(argAsString(index));
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
protected long argAsLong(int index) {
|
||||
return Long.valueOf(argAsString(index));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
protected long argAsLong(int index, long defaultValue) {
|
||||
try {
|
||||
return Long.valueOf(argAsString(index));
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
protected double argAsDouble(int index, double defaultValue) {
|
||||
try {
|
||||
return Double.valueOf(argAsString(index).replace(",", "."));
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
protected double argAsDouble(int index) {
|
||||
return Double.valueOf(argAsString(index).replace(",", "."));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
protected Player argAsPlayer(int index) {
|
||||
return Bukkit.getPlayer(argAsString(index));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
protected Player argAsPlayer(int index, Player defaultValue) {
|
||||
try {
|
||||
return Bukkit.getPlayer(argAsString(index));
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
protected OfflinePlayer argAsOfflinePlayer(int index) {
|
||||
return Bukkit.getOfflinePlayer(argAsString(index));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
protected OfflinePlayer argAsOfflinePlayer(int index, OfflinePlayer defaultValue) {
|
||||
try {
|
||||
return Bukkit.getOfflinePlayer(argAsString(index));
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
protected Location argAsLocation(int index) {
|
||||
return changeStringLocationToLocationEye(argAsString(index));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
protected Location argAsLocation(int index, Location defaultValue) {
|
||||
try {
|
||||
return changeStringLocationToLocationEye(argAsString(index));
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
protected EntityType argAsEntityType(int index) {
|
||||
return EntityType.valueOf(argAsString(index).toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
protected EntityType argAsEntityType(int index, EntityType defaultValue) {
|
||||
try {
|
||||
return EntityType.valueOf(argAsString(index).toUpperCase());
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
protected World argAsWorld(int index) {
|
||||
try {
|
||||
return Bukkit.getWorld(argAsString(index));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
protected World argAsWorld(int index, World world) {
|
||||
try {
|
||||
return Bukkit.getWorld(argAsString(index));
|
||||
} catch (Exception e) {
|
||||
return world;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package fr.maxlego08.koth.zcore.utils.commands;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface CollectionBiConsumer {
|
||||
|
||||
/**
|
||||
* Accept consumer
|
||||
*
|
||||
* @param sender
|
||||
* @param args
|
||||
* @return list of string
|
||||
*/
|
||||
List<String> accept(CommandSender sender, String[] args);
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package fr.maxlego08.koth.zcore.utils.commands;
|
||||
|
||||
public enum CommandType {
|
||||
|
||||
SUCCESS,
|
||||
SYNTAX_ERROR,
|
||||
EXCEPTION_ERROR,
|
||||
DEFAULT,
|
||||
CONTINUE,
|
||||
|
||||
;
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package fr.maxlego08.koth.zcore.utils.commands;
|
||||
|
||||
public enum Tab {
|
||||
|
||||
START,
|
||||
CONTAINS,
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package fr.maxlego08.koth.zcore.utils.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import fr.maxlego08.koth.zcore.ZPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
public class LocationAdapter extends TypeAdapter<Location> {
|
||||
|
||||
private final ZPlugin plugin;
|
||||
private static Type seriType = new TypeToken<Map<String, Object>>() {
|
||||
}.getType();
|
||||
|
||||
private static String NAME = "name";
|
||||
private static String X = "x";
|
||||
private static String Y = "y";
|
||||
private static String Z = "z";
|
||||
private static String YAW = "yaw";
|
||||
private static String PITCH = "pitch";
|
||||
|
||||
/**
|
||||
* @param plugin
|
||||
*/
|
||||
public LocationAdapter(ZPlugin plugin) {
|
||||
super();
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter jsonWriter, Location location) throws IOException {
|
||||
if (location == null) {
|
||||
jsonWriter.nullValue();
|
||||
return;
|
||||
}
|
||||
jsonWriter.value(getRaw(location));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location read(JsonReader jsonReader) throws IOException {
|
||||
if (jsonReader.peek() == JsonToken.NULL) {
|
||||
jsonReader.nextNull();
|
||||
return null;
|
||||
}
|
||||
return fromRaw(jsonReader.nextString());
|
||||
}
|
||||
|
||||
private String getRaw(Location location) {
|
||||
Map<String, Object> serial = new HashMap<String, Object>();
|
||||
serial.put(NAME, location.getWorld().getName());
|
||||
serial.put(X, Double.toString(location.getX()));
|
||||
serial.put(Y, Double.toString(location.getY()));
|
||||
serial.put(Z, Double.toString(location.getZ()));
|
||||
serial.put(YAW, Float.toString(location.getYaw()));
|
||||
serial.put(PITCH, Float.toString(location.getPitch()));
|
||||
return plugin.getGson().toJson(serial);
|
||||
}
|
||||
|
||||
private Location fromRaw(String raw) {
|
||||
Map<String, Object> keys = this.plugin.getGson().fromJson(raw, seriType);
|
||||
World w = Bukkit.getWorld((String) keys.get(NAME));
|
||||
return new Location(w, Double.parseDouble((String) keys.get(X)), Double.parseDouble((String) keys.get(Y)),
|
||||
Double.parseDouble((String) keys.get(Z)), Float.parseFloat((String) keys.get(YAW)),
|
||||
Float.parseFloat((String) keys.get(PITCH)));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package fr.maxlego08.koth.zcore.utils.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
import fr.maxlego08.koth.zcore.ZPlugin;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
public class PotionEffectAdapter extends TypeAdapter<PotionEffect> {
|
||||
|
||||
private final ZPlugin plugin;
|
||||
private static Type seriType = new TypeToken<Map<String, Object>>() {
|
||||
}.getType();
|
||||
|
||||
private static String TYPE = "effect";
|
||||
private static String DURATION = "duration";
|
||||
private static String AMPLIFIER = "amplifier";
|
||||
private static String AMBIENT = "ambient";
|
||||
|
||||
/**
|
||||
* @param plugin
|
||||
*/
|
||||
public PotionEffectAdapter(ZPlugin plugin) {
|
||||
super();
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter jsonWriter, PotionEffect potionEffect) throws IOException {
|
||||
if (potionEffect == null) {
|
||||
jsonWriter.nullValue();
|
||||
return;
|
||||
}
|
||||
jsonWriter.value(getRaw(potionEffect));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PotionEffect read(JsonReader jsonReader) throws IOException {
|
||||
if (jsonReader.peek() == JsonToken.NULL) {
|
||||
jsonReader.nextNull();
|
||||
return null;
|
||||
}
|
||||
return fromRaw(jsonReader.nextString());
|
||||
}
|
||||
|
||||
private String getRaw(PotionEffect potion) {
|
||||
Map<String, Object> serial = potion.serialize();
|
||||
return this.plugin.getGson().toJson(serial);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private PotionEffect fromRaw(String raw) {
|
||||
Map<String, Object> keys = this.plugin.getGson().fromJson(raw, seriType);
|
||||
return new PotionEffect(PotionEffectType.getById(((Double) keys.get(TYPE)).intValue()),
|
||||
((Double) keys.get(DURATION)).intValue(), ((Double) keys.get(AMPLIFIER)).intValue(),
|
||||
(Boolean) keys.get(AMBIENT));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package fr.maxlego08.koth.zcore.utils.interfaces;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface CollectionConsumer<T> {
|
||||
|
||||
Collection<String> accept(T t);
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package fr.maxlego08.koth.zcore.utils.interfaces;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface StringConsumer<T> {
|
||||
|
||||
String accept(T t);
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package fr.maxlego08.koth.zcore.utils.inventory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.material.MaterialData;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class Button extends ZUtils {
|
||||
|
||||
private final int slot;
|
||||
private final String name;
|
||||
private final MaterialData item;
|
||||
private final List<String> lore;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param slot
|
||||
* @param name
|
||||
* @param material
|
||||
* @param data
|
||||
* @param lore
|
||||
*/
|
||||
public Button(int slot, String name, Material material, int data, List<String> lore) {
|
||||
super();
|
||||
this.slot = slot;
|
||||
this.name = name;
|
||||
this.item = new MaterialData(material, (byte) data);
|
||||
this.lore = lore;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param slot
|
||||
* @param name
|
||||
* @param item
|
||||
*/
|
||||
public Button(int slot, String name, Material item) {
|
||||
this(slot, name, item, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param slot
|
||||
* @param name
|
||||
* @param item
|
||||
* @param lore
|
||||
*/
|
||||
public Button(int slot, String name, Material item, String... lore) {
|
||||
this(slot, name, item, 0, Arrays.asList(lore));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param slot
|
||||
* @param name
|
||||
* @param item
|
||||
* @param data
|
||||
* @param lore
|
||||
*/
|
||||
public Button(int slot, String name, Material item, int data, String... lore) {
|
||||
this(slot, name, item, data, Arrays.asList(lore));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the slot
|
||||
*/
|
||||
public int getSlot() {
|
||||
return slot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the item
|
||||
*/
|
||||
public MaterialData getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lore
|
||||
*/
|
||||
public List<String> getLore() {
|
||||
return lore;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package fr.maxlego08.koth.zcore.utils.inventory;
|
||||
|
||||
public enum InventoryResult {
|
||||
|
||||
SUCCESS,
|
||||
ERROR,
|
||||
DEFAULT,
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package fr.maxlego08.koth.zcore.utils.inventory;
|
||||
|
||||
public enum InventorySize {
|
||||
|
||||
FULL_INVENTORY(53, 45, 50, 48, 0),
|
||||
FULL_45_INVENTORY(45, 36, 42, 40, 0),
|
||||
|
||||
;
|
||||
|
||||
private final int size;
|
||||
private final int paginationSize;
|
||||
private final int nextSlot;
|
||||
private final int previousSlot;
|
||||
private final int defaultSlot;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param size
|
||||
* @param paginationSize
|
||||
* @param nextSlot
|
||||
* @param previousSlot
|
||||
* @param defaultSlot
|
||||
*/
|
||||
private InventorySize(int size, int paginationSize, int nextSlot, int previousSlot, int defaultSlot) {
|
||||
this.size = size;
|
||||
this.paginationSize = paginationSize;
|
||||
this.nextSlot = nextSlot;
|
||||
this.previousSlot = previousSlot;
|
||||
this.defaultSlot = defaultSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size
|
||||
*/
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the paginationSize
|
||||
*/
|
||||
public int getPaginationSize() {
|
||||
return paginationSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the nextSlot
|
||||
*/
|
||||
public int getNextSlot() {
|
||||
return nextSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the previousSlot
|
||||
*/
|
||||
public int getPreviousSlot() {
|
||||
return previousSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the defaultSlot
|
||||
*/
|
||||
public int getDefaultSlot() {
|
||||
return defaultSlot;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package fr.maxlego08.koth.zcore.utils.inventory;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class ItemButton {
|
||||
|
||||
private final int slot;
|
||||
private final ItemStack displayItem;
|
||||
private Consumer<InventoryClickEvent> onClick;
|
||||
private Consumer<InventoryClickEvent> onMiddleClick;
|
||||
private Consumer<InventoryClickEvent> onLeftClick;
|
||||
private Consumer<InventoryClickEvent> onRightClick;
|
||||
|
||||
public ItemButton(ItemStack displayItem, int slot) {
|
||||
super();
|
||||
this.displayItem = displayItem;
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
public int getSlot() {
|
||||
return slot;
|
||||
}
|
||||
|
||||
public ItemButton setClick(Consumer<InventoryClickEvent> onClick) {
|
||||
this.onClick = onClick;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemButton setMiddleClick(Consumer<InventoryClickEvent> onMiddleClick) {
|
||||
this.onMiddleClick = onMiddleClick;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param onLeftClick
|
||||
* the onLeftClick to set
|
||||
*/
|
||||
public ItemButton setLeftClick(Consumer<InventoryClickEvent> onLeftClick) {
|
||||
this.onLeftClick = onLeftClick;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param onRightClick
|
||||
* the onRightClick to set
|
||||
*/
|
||||
public ItemButton setRightClick(Consumer<InventoryClickEvent> onRightClick) {
|
||||
this.onRightClick = onRightClick;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStack getDisplayItem() {
|
||||
return displayItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de gérer le click du joueur
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
public void onClick(InventoryClickEvent event) {
|
||||
if (onClick != null)
|
||||
onClick.accept(event);
|
||||
if (event.getClick().equals(ClickType.MIDDLE) && onMiddleClick != null)
|
||||
onMiddleClick.accept(event);
|
||||
else if (event.getClick().equals(ClickType.RIGHT) && onRightClick != null)
|
||||
onRightClick.accept(event);
|
||||
else if (event.getClick().equals(ClickType.LEFT) && onLeftClick != null)
|
||||
onLeftClick.accept(event);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
package fr.maxlego08.koth.zcore.utils.inventory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import fr.maxlego08.koth.KothPlugin;
|
||||
import fr.maxlego08.koth.exceptions.InventoryOpenException;
|
||||
import fr.maxlego08.koth.inventory.VInventory;
|
||||
|
||||
public abstract class PaginateInventory<T> extends VInventory {
|
||||
|
||||
protected List<T> collections;
|
||||
protected final String inventoryName;
|
||||
protected final int inventorySize;
|
||||
protected int paginationSize = 45;
|
||||
protected int nextSlot = 50;
|
||||
protected int previousSlot = 48;
|
||||
protected int defaultSlot = 0;
|
||||
protected boolean isReverse = false;
|
||||
protected boolean disableDefaultClick = false;
|
||||
protected Material previousMaterial = Material.ARROW;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param inventoryName
|
||||
* @param inventorySize
|
||||
*/
|
||||
public PaginateInventory(String inventoryName, int inventorySize) {
|
||||
super();
|
||||
this.inventoryName = inventoryName;
|
||||
this.inventorySize = inventorySize;
|
||||
}
|
||||
|
||||
public PaginateInventory(String inventoryName, InventorySize inventorySize) {
|
||||
this.inventoryName = inventoryName;
|
||||
this.inventorySize = inventorySize.getSize();
|
||||
this.paginationSize = inventorySize.getPaginationSize();
|
||||
this.nextSlot = inventorySize.getNextSlot();
|
||||
this.previousSlot = inventorySize.getPreviousSlot();
|
||||
this.defaultSlot = inventorySize.getDefaultSlot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryResult openInventory(KothPlugin plugin, Player player, int page, Object... args)
|
||||
throws InventoryOpenException {
|
||||
|
||||
if (defaultSlot > inventorySize || nextSlot > inventorySize || previousSlot > inventorySize
|
||||
|| paginationSize > inventorySize)
|
||||
throw new InventoryOpenException("Une erreur est survenue avec la gestion des slots !");
|
||||
|
||||
collections = preOpenInventory();
|
||||
|
||||
if (collections == null)
|
||||
throw new InventoryOpenException("Collection is null");
|
||||
|
||||
super.createInventory(inventoryName.replace("%mp%", String.valueOf(getMaxPage(collections))).replace("%p%",
|
||||
String.valueOf(page)), inventorySize);
|
||||
|
||||
Pagination<T> pagination = new Pagination<>();
|
||||
AtomicInteger slot = new AtomicInteger(defaultSlot);
|
||||
|
||||
List<T> tmpList = isReverse ? pagination.paginateReverse(collections, paginationSize, page)
|
||||
: pagination.paginate(collections, paginationSize, page);
|
||||
|
||||
tmpList.forEach(tmpItem -> {
|
||||
ItemButton button = addItem(slot.getAndIncrement(), buildItem(tmpItem));
|
||||
button.setClick((event) -> onClick(tmpItem, button));
|
||||
});
|
||||
|
||||
if (getPage() != 1)
|
||||
addItem(previousSlot, Material.ARROW, "§f« §7Page précédente")
|
||||
.setClick(event -> createInventory(this.plugin, player, getId(), getPage() - 1, args));
|
||||
if (getPage() != getMaxPage(collections))
|
||||
addItem(nextSlot, Material.ARROW, "§f» §7Page suivante")
|
||||
.setClick(event -> createInventory(this.plugin, player, getId(), getPage() + 1, args));
|
||||
|
||||
postOpenInventory();
|
||||
|
||||
return InventoryResult.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param slot
|
||||
* @return
|
||||
*/
|
||||
protected int slotChange(int slot) {
|
||||
return slot;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param button
|
||||
* @return
|
||||
*/
|
||||
protected ItemButton createButton(ItemButton button) {
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param object
|
||||
* @return
|
||||
*/
|
||||
public abstract ItemStack buildItem(T object);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param object
|
||||
* @param button
|
||||
*/
|
||||
public abstract void onClick(T object, ItemButton button);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public abstract List<T> preOpenInventory();
|
||||
|
||||
/**
|
||||
* Called after create inventory
|
||||
*/
|
||||
public abstract void postOpenInventory();
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package fr.maxlego08.koth.zcore.utils.inventory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Pagination<T> {
|
||||
|
||||
/**
|
||||
* Allows you to sort a list of items according to the number of items and the page
|
||||
* Here the pagination will allow to invert the list of elements
|
||||
* The system can be used to create inventories with several pages for example
|
||||
*
|
||||
* @param list - List of element
|
||||
* @param size - Pagination size
|
||||
* @param page - Current pagination page
|
||||
*/
|
||||
public List<T> paginateReverse(List<T> list, int inventorySize, int page) {
|
||||
List<T> currentList = new ArrayList<>();
|
||||
if (page == 0)
|
||||
page = 1;
|
||||
int idStart = list.size() - 1 - ((page - 1) * inventorySize);
|
||||
int idEnd = idStart - inventorySize;
|
||||
if (idEnd < list.size() - inventorySize && list.size() < inventorySize * page)
|
||||
idEnd = -1;
|
||||
for (int a = idStart; a != idEnd; a--)
|
||||
currentList.add(list.get(a));
|
||||
return currentList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to sort a list of items according to the number of items and the page
|
||||
* The system can be used to create inventories with several pages for example
|
||||
*
|
||||
* @param list - List of element
|
||||
* @param size - Pagination size
|
||||
* @param page - Current pagination page
|
||||
*/
|
||||
public List<T> paginate(List<T> list, int size, int page) {
|
||||
List<T> currentList = new ArrayList<>();
|
||||
if (page <= 0)
|
||||
page = 1;
|
||||
int idStart = 0 + ((page - 1)) * size;
|
||||
int idEnd = idStart + size;
|
||||
if (idEnd > list.size())
|
||||
idEnd = list.size();
|
||||
for (int a = idStart; a != idEnd; a++)
|
||||
currentList.add(list.get(a));
|
||||
return currentList;
|
||||
}
|
||||
|
||||
/**
|
||||
* The pagination will be done on the values of the map
|
||||
*
|
||||
* @param map of element
|
||||
* @parma size
|
||||
* @param page
|
||||
*/
|
||||
public List<T> paginateReverse(Map<?, T> map, int size, int page) {
|
||||
return paginateReverse(new ArrayList<>(map.values()), size, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* The pagination will be done on the values of the map
|
||||
*
|
||||
* @param map of element
|
||||
* @parma size
|
||||
* @param page
|
||||
*/
|
||||
public List<T> paginate(Map<?, T> map, int inventorySize, int page) {
|
||||
return paginate(new ArrayList<>(map.values()), inventorySize, page);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package fr.maxlego08.koth.zcore.utils.loader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
import fr.maxlego08.koth.zcore.utils.inventory.Button;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.material.MaterialData;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ButtonLoader extends ZUtils implements Loader<Button> {
|
||||
|
||||
@Override
|
||||
public Button load(YamlConfiguration configuration, String path) {
|
||||
|
||||
String name = configuration.getString(path + "name") == null ? null
|
||||
: color(configuration.getString(path + "name"));
|
||||
int slot = configuration.getInt(path + "slot", 0);
|
||||
Material item = Material.valueOf(configuration.getString(path + "item"));
|
||||
int data = configuration.getInt(path + "data", 0);
|
||||
List<String> lore = configuration.getStringList(path + "lore");
|
||||
|
||||
return new Button(slot, name, item, data, lore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Button object, YamlConfiguration configuration, String path) {
|
||||
|
||||
configuration.set(path + "name", object.getName() != null ? colorReverse(object.getName()) : null);
|
||||
configuration.set(path + "slot", object.getSlot());
|
||||
configuration.set(path + "lore", object.getLore() == null ? null : object.getLore());
|
||||
MaterialData materialData = object.getItem();
|
||||
configuration.set(path + "material", materialData == null ? null : materialData.getItemType());
|
||||
configuration.set(path + "data", materialData == null ? null : materialData.getData());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
package fr.maxlego08.koth.zcore.utils.loader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import fr.maxlego08.koth.exceptions.ItemEnchantException;
|
||||
import fr.maxlego08.koth.exceptions.ItemFlagException;
|
||||
import fr.maxlego08.koth.zcore.logger.Logger;
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.potion.Potion;
|
||||
import org.bukkit.potion.PotionType;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.nms.NMSUtils;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ItemStackLoader extends ZUtils implements Loader<ItemStack> {
|
||||
|
||||
/**
|
||||
* Load ItemStack
|
||||
*/
|
||||
public ItemStack load(YamlConfiguration configuration, String path) {
|
||||
|
||||
int data = configuration.getInt(path + "data", 0);
|
||||
int amount = configuration.getInt(path + "amount", 1);
|
||||
short durability = (short) configuration.getInt(path + "durability", 0);
|
||||
int modelID = configuration.getInt(path + "modelID", 0);
|
||||
Material material = null;
|
||||
|
||||
int value = configuration.getInt(path + "material", 0);
|
||||
if (value != 0)
|
||||
material = getMaterial(value);
|
||||
|
||||
if (material == null) {
|
||||
String str = configuration.getString(path + "material", null);
|
||||
if (str == null)
|
||||
return null;
|
||||
material = Material.getMaterial(str.toUpperCase());
|
||||
}
|
||||
|
||||
if (modelID < 0)
|
||||
modelID = 0;
|
||||
|
||||
ItemStack item = null;
|
||||
|
||||
if (material == null || material.equals(Material.AIR))
|
||||
return null;
|
||||
|
||||
item = new ItemStack(material, amount, (byte) data);
|
||||
|
||||
if (configuration.contains(path + "url")) {
|
||||
|
||||
item = createSkull(configuration.getString(path + "url"));
|
||||
|
||||
} else if (configuration.contains(path + "potion")) {
|
||||
|
||||
PotionType type = PotionType.valueOf(configuration.getString(path + "potion", "REGEN").toUpperCase());
|
||||
int level = configuration.getInt(path + "level", 1);
|
||||
boolean splash = configuration.getBoolean(path + "splash", false);
|
||||
boolean extended = configuration.getBoolean(path + "extended", false);
|
||||
|
||||
item = new Potion(type, level, splash, extended).toItemStack(amount);
|
||||
|
||||
}
|
||||
|
||||
// Si après tout l'item est null alors fuck off
|
||||
if (item == null)
|
||||
return null;
|
||||
|
||||
if (durability != 0)
|
||||
item.setDurability(durability);
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
|
||||
List<String> tmpLore = configuration.getStringList(path + "lore");
|
||||
if (tmpLore.size() != 0) {
|
||||
List<String> lore = meta.getLore() == null ? new ArrayList<>() : meta.getLore();
|
||||
lore.addAll(color(tmpLore));
|
||||
meta.setLore(lore);
|
||||
}
|
||||
|
||||
String displayName = configuration.getString(path + "name", null);
|
||||
if (displayName != null)
|
||||
meta.setDisplayName(color(displayName));
|
||||
|
||||
List<String> enchants = configuration.getStringList(path + "enchants");
|
||||
|
||||
boolean isGlowing = configuration.getBoolean(path + "glow");
|
||||
|
||||
if (isGlowing && NMSUtils.getNMSVersion() != 1.7) {
|
||||
|
||||
meta.addEnchant(Enchantment.ARROW_DAMAGE, 1, true);
|
||||
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||
|
||||
}
|
||||
|
||||
if (modelID > 0)
|
||||
meta.setCustomModelData(modelID);
|
||||
|
||||
// Permet de charger l'enchantement de l'item
|
||||
if (enchants.size() != 0) {
|
||||
|
||||
for (String enchantString : enchants) {
|
||||
|
||||
try {
|
||||
|
||||
String[] splitEnchant = enchantString.split(",");
|
||||
|
||||
if (splitEnchant.length == 1)
|
||||
throw new ItemEnchantException(
|
||||
"an error occurred while loading the enchantment " + enchantString);
|
||||
|
||||
int level = 0;
|
||||
String enchant = splitEnchant[0];
|
||||
try {
|
||||
level = Integer.valueOf(splitEnchant[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ItemEnchantException(
|
||||
"an error occurred while loading the enchantment " + enchantString);
|
||||
}
|
||||
|
||||
Enchantment enchantment = Enchantment.getByName(enchant);
|
||||
if (enchantment == null)
|
||||
throw new ItemEnchantException(
|
||||
"an error occurred while loading the enchantment " + enchantString);
|
||||
|
||||
if (material.equals(Material.ENCHANTED_BOOK)) {
|
||||
|
||||
((EnchantmentStorageMeta) meta).addStoredEnchant(enchantment, level, true);
|
||||
|
||||
} else
|
||||
meta.addEnchant(enchantment, level, true);
|
||||
|
||||
} catch (ItemEnchantException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
List<String> flags = configuration.getStringList(path + "flags");
|
||||
|
||||
// Permet de charger les différents flags
|
||||
if (flags.size() != 0 && NMSUtils.getNMSVersion() != 1.7) {
|
||||
|
||||
for (String flagString : flags) {
|
||||
|
||||
try {
|
||||
|
||||
ItemFlag flag = getFlag(flagString);
|
||||
|
||||
if (flag == null)
|
||||
throw new ItemFlagException("an error occurred while loading the flag " + flagString);
|
||||
|
||||
meta.addItemFlags(flag);
|
||||
|
||||
} catch (ItemFlagException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
item.setItemMeta(meta);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void save(ItemStack item, YamlConfiguration configuration, String path) {
|
||||
|
||||
if (item == null) {
|
||||
Logger.info("Impossible de sauvegarder l'item car il est null ! Le path: " + path, Logger.LogType.ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
configuration.set(path + "material", item.getType().name());
|
||||
configuration.set(path + "data", item.getData().getData());
|
||||
configuration.set(path + "amount", item.getAmount());
|
||||
configuration.set(path + "durability", item.getDurability());
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta.hasDisplayName())
|
||||
configuration.set(path + "name", meta.getDisplayName().replace("§", "&"));
|
||||
if (meta.hasLore())
|
||||
configuration.set(path + "lore", colorReverse(meta.getLore()));
|
||||
if (NMSUtils.getNMSVersion() != 1.7 && meta.getItemFlags().size() != 0)
|
||||
configuration.set(path + "flags",
|
||||
meta.getItemFlags().stream().map(flag -> flag.name()).collect(Collectors.toList()));
|
||||
if (meta.hasEnchants()) {
|
||||
List<String> enchantList = new ArrayList<>();
|
||||
meta.getEnchants().forEach((enchant, level) -> enchantList.add(enchant.getName() + "," + level));
|
||||
configuration.set(path + "enchants", enchantList);
|
||||
}
|
||||
|
||||
if (meta instanceof EnchantmentStorageMeta && ((EnchantmentStorageMeta) meta).hasStoredEnchants()) {
|
||||
List<String> enchantList = new ArrayList<>();
|
||||
((EnchantmentStorageMeta) meta).getStoredEnchants()
|
||||
.forEach((enchant, level) -> enchantList.add(enchant.getName() + "," + level));
|
||||
|
||||
configuration.set(path + "enchants", enchantList);
|
||||
}
|
||||
if (NMSUtils.hasBarrel() && meta.hasCustomModelData()) {
|
||||
configuration.set(path + "modelID", meta.getCustomModelData());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package fr.maxlego08.koth.zcore.utils.loader;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public interface Loader<T> {
|
||||
|
||||
/**
|
||||
* Load object from yml
|
||||
*
|
||||
* @param configuration
|
||||
* @param path
|
||||
* @return element
|
||||
*/
|
||||
T load(YamlConfiguration configuration, String path);
|
||||
|
||||
/**
|
||||
* Save object to yml
|
||||
*
|
||||
* @param object
|
||||
* @param configuration
|
||||
* @param path
|
||||
*/
|
||||
void save(T object, YamlConfiguration configuration, String path);
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package fr.maxlego08.koth.zcore.utils.map;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
|
||||
public class OptionalHashMap<K, V> extends HashMap<K, V> implements OptionalMap<K, V>{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -1389669310403530512L;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @return {@link Optional}
|
||||
*/
|
||||
public Optional<V> getOptional(K key) {
|
||||
V value = super.getOrDefault(key, null);
|
||||
return value == null ? Optional.empty() : Optional.of(value);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @return true if is present
|
||||
*/
|
||||
public boolean isPresent(K key) {
|
||||
return getOptional(key).isPresent();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package fr.maxlego08.koth.zcore.utils.map;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface OptionalMap<K, V> extends Map<K, V> {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
Optional<V> getOptional(K key);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
boolean isPresent(K key);
|
||||
|
||||
}
|
|
@ -0,0 +1,392 @@
|
|||
package fr.maxlego08.koth.zcore.utils.nms;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.nms.ItemStackUtils.EnumReflectionItemStack;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class ItemStackCompound {
|
||||
|
||||
private final EnumReflectionCompound reflection;
|
||||
|
||||
public ItemStackCompound(EnumReflectionCompound reflection) {
|
||||
super();
|
||||
this.reflection = reflection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de retourner le nbttag
|
||||
*
|
||||
* @param itemStack
|
||||
* @return object
|
||||
* @throws Exception
|
||||
*/
|
||||
public Object getCompound(ItemStack itemStack) throws Exception {
|
||||
Object localItemStackObject = EnumReflectionItemStack.CRAFTITEMSTACK.getClassz()
|
||||
.getMethod("asNMSCopy", new Class[]{ItemStack.class}).invoke(null, new Object[]{itemStack});
|
||||
Object localCompoundObject = localItemStackObject.getClass().getMethod(this.reflection.getMethodGetTag())
|
||||
.invoke(localItemStackObject);
|
||||
if (localCompoundObject != null) {
|
||||
return localCompoundObject;
|
||||
}
|
||||
return EnumReflectionItemStack.NBTTAGCOMPOUND.getClassz().newInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'appliquer le nbttag sur l'itemstack
|
||||
*
|
||||
* @param itemStack
|
||||
* @param compoundObject
|
||||
* @return itemstack
|
||||
* @throws Exception
|
||||
*/
|
||||
public ItemStack applyCompound(ItemStack itemStack, Object compoundObject) throws Exception {
|
||||
Object localItemStackObject = EnumReflectionItemStack.CRAFTITEMSTACK.getClassz()
|
||||
.getMethod("asNMSCopy", new Class[]{ItemStack.class}).invoke(null, new Object[]{itemStack});
|
||||
|
||||
localItemStackObject.getClass()
|
||||
.getMethod(this.reflection.getMethodSetTag(),
|
||||
new Class[]{EnumReflectionItemStack.NBTTAGCOMPOUND.getClassz()})
|
||||
.invoke(localItemStackObject, compoundObject);
|
||||
|
||||
return (ItemStack) EnumReflectionItemStack.CRAFTITEMSTACK.getClassz()
|
||||
.getMethod("asBukkitCopy", new Class[]{EnumReflectionItemStack.ITEMSTACK.getClassz()})
|
||||
.invoke(null, new Object[]{localItemStackObject});
|
||||
}
|
||||
|
||||
public ItemStack setString(ItemStack itemStack, String key, String value) {
|
||||
|
||||
try {
|
||||
Object compoundObject = this.getCompound(itemStack);
|
||||
|
||||
compoundObject.getClass()
|
||||
.getMethod(this.reflection.getMethodSetString(), new Class[]{String.class, String.class})
|
||||
.invoke(compoundObject, new Object[]{key, value});
|
||||
|
||||
return this.applyCompound(itemStack, compoundObject);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public String getString(ItemStack itemStack, String key) {
|
||||
|
||||
try {
|
||||
Object compoundObject = this.getCompound(itemStack);
|
||||
|
||||
return (String) compoundObject.getClass()
|
||||
.getMethod(this.reflection.getMethodGetString(), new Class[]{String.class})
|
||||
.invoke(compoundObject, new Object[]{key});
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public double getDouble(ItemStack itemStack, String key) {
|
||||
|
||||
try {
|
||||
Object compoundObject = this.getCompound(itemStack);
|
||||
|
||||
return (double) compoundObject.getClass()
|
||||
.getMethod(this.reflection.getMethodGetDouble(), new Class[]{String.class})
|
||||
.invoke(compoundObject, new Object[]{key});
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
public long getLong(ItemStack itemStack, String key) {
|
||||
|
||||
try {
|
||||
Object compoundObject = this.getCompound(itemStack);
|
||||
|
||||
return (long) compoundObject.getClass()
|
||||
.getMethod(this.reflection.getMethodGetLong(), new Class[]{String.class})
|
||||
.invoke(compoundObject, new Object[]{key});
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
public int getInt(ItemStack itemStack, String key) {
|
||||
|
||||
try {
|
||||
Object compoundObject = this.getCompound(itemStack);
|
||||
|
||||
return (int) compoundObject.getClass()
|
||||
.getMethod(this.reflection.getMethodGetInt(), new Class[]{String.class})
|
||||
.invoke(compoundObject, new Object[]{key});
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
public float getFloat(ItemStack itemStack, String key) {
|
||||
|
||||
try {
|
||||
Object compoundObject = this.getCompound(itemStack);
|
||||
|
||||
return (float) compoundObject.getClass()
|
||||
.getMethod(this.reflection.getMethodGetFloat(), new Class[]{String.class})
|
||||
.invoke(compoundObject, new Object[]{key});
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
public boolean getBoolean(ItemStack itemStack, String key) {
|
||||
|
||||
try {
|
||||
Object compoundObject = this.getCompound(itemStack);
|
||||
|
||||
return (boolean) compoundObject.getClass()
|
||||
.getMethod(this.reflection.getMethodGetBoolean(), new Class[]{String.class})
|
||||
.invoke(compoundObject, new Object[]{key});
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public ItemStack setInt(ItemStack itemStack, String key, int value) {
|
||||
|
||||
try {
|
||||
Object compoundObject = this.getCompound(itemStack);
|
||||
|
||||
compoundObject.getClass()
|
||||
.getMethod(this.reflection.getMethodSetInt(), new Class[]{String.class, int.class})
|
||||
.invoke(compoundObject, new Object[]{key, value});
|
||||
|
||||
return this.applyCompound(itemStack, compoundObject);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public ItemStack setLong(ItemStack itemStack, String key, long value) {
|
||||
|
||||
try {
|
||||
Object compoundObject = this.getCompound(itemStack);
|
||||
|
||||
compoundObject.getClass()
|
||||
.getMethod(this.reflection.getMethodSetLong(), new Class[]{String.class, long.class})
|
||||
.invoke(compoundObject, new Object[]{key, value});
|
||||
|
||||
return this.applyCompound(itemStack, compoundObject);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public ItemStack setFloat(ItemStack itemStack, String key, float value) {
|
||||
|
||||
try {
|
||||
Object compoundObject = this.getCompound(itemStack);
|
||||
|
||||
compoundObject.getClass()
|
||||
.getMethod(this.reflection.getMethodSetFloat(), new Class[]{String.class, float.class})
|
||||
.invoke(compoundObject, new Object[]{key, value});
|
||||
|
||||
return this.applyCompound(itemStack, compoundObject);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public ItemStack setBoolean(ItemStack itemStack, String key, boolean value) {
|
||||
|
||||
try {
|
||||
Object compoundObject = this.getCompound(itemStack);
|
||||
|
||||
compoundObject.getClass()
|
||||
.getMethod(this.reflection.getMethodSetBoolean(), new Class[]{String.class, boolean.class})
|
||||
.invoke(compoundObject, new Object[]{key, value});
|
||||
|
||||
return this.applyCompound(itemStack, compoundObject);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public ItemStack setDouble(ItemStack itemStack, String key, double value) {
|
||||
|
||||
try {
|
||||
Object compoundObject = this.getCompound(itemStack);
|
||||
|
||||
compoundObject.getClass()
|
||||
.getMethod(this.reflection.getMethodSetDouble(), new Class[]{String.class, double.class})
|
||||
.invoke(compoundObject, new Object[]{key, value});
|
||||
|
||||
return this.applyCompound(itemStack, compoundObject);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a key is contained in the nbttag
|
||||
*
|
||||
* @param itemStack
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public boolean isKey(ItemStack itemStack, String key) {
|
||||
|
||||
try {
|
||||
|
||||
Object nbttagCompound = this.getCompound(itemStack);
|
||||
if (nbttagCompound == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (boolean) nbttagCompound.getClass()
|
||||
.getMethod(this.reflection.getMethodHaskey(), new Class[]{String.class})
|
||||
.invoke(nbttagCompound, new Object[]{key});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public enum EnumReflectionCompound {
|
||||
|
||||
V1_8_8("getTag", "setTag", "hasKey", "getBoolean", "getFloat", "getDouble", "getLong", "getInt", "getString",
|
||||
"setBoolean", "setFloat", "setDouble", "setLong", "setInt", "setString"),
|
||||
V1_18_2("t", "c", "e", "q", "j", "k", "i", "h", "l", "a", "a", "a", "a", "a", "a"),
|
||||
V1_12("v", "c", "e", "q", "j", "k", "i", "h", "l", "a", "a", "a", "a", "a", "a"),
|
||||
V1_19("u", "c", "e", "q", "j", "k", "i", "h", "l", "a", "a", "a", "a", "a", "a"),
|
||||
V_OTHER("s", "c", "e", "q", "j", "k", "i", "h", "l", "a", "a", "a", "a", "a", "a"),
|
||||
|
||||
;
|
||||
|
||||
private final String methodGetTag;
|
||||
private final String methodSetTag;
|
||||
|
||||
private final String methodHaskey;
|
||||
|
||||
private final String methodGetBoolean;
|
||||
private final String methodGetFloat;
|
||||
private final String methodGetDouble;
|
||||
private final String methodGetLong;
|
||||
private final String methodGetInt;
|
||||
private final String methodGetString;
|
||||
|
||||
private final String methodSetBoolean;
|
||||
private final String methodSetFloat;
|
||||
private final String methodSetDouble;
|
||||
private final String methodSetLong;
|
||||
private final String methodSetInt;
|
||||
private final String methodSetString;
|
||||
|
||||
private EnumReflectionCompound(String methodGetTag, String methodSetTag, String methodHaskey,
|
||||
String methodGetBoolean, String methodGetFloat, String methodGetDouble, String methodGetLong,
|
||||
String methodGetInt, String methodGetString, String methodSetBoolean, String methodSetFloat,
|
||||
String methodSetDouble, String methodSetLong, String methodSetInt, String methodSetString) {
|
||||
this.methodGetTag = methodGetTag;
|
||||
this.methodSetTag = methodSetTag;
|
||||
this.methodHaskey = methodHaskey;
|
||||
this.methodGetBoolean = methodGetBoolean;
|
||||
this.methodGetFloat = methodGetFloat;
|
||||
this.methodGetDouble = methodGetDouble;
|
||||
this.methodGetLong = methodGetLong;
|
||||
this.methodGetInt = methodGetInt;
|
||||
this.methodGetString = methodGetString;
|
||||
this.methodSetBoolean = methodSetBoolean;
|
||||
this.methodSetFloat = methodSetFloat;
|
||||
this.methodSetDouble = methodSetDouble;
|
||||
this.methodSetLong = methodSetLong;
|
||||
this.methodSetInt = methodSetInt;
|
||||
this.methodSetString = methodSetString;
|
||||
}
|
||||
|
||||
public String getMethodGetTag() {
|
||||
return methodGetTag;
|
||||
}
|
||||
|
||||
public String getMethodSetTag() {
|
||||
return methodSetTag;
|
||||
}
|
||||
|
||||
public String getMethodHaskey() {
|
||||
return methodHaskey;
|
||||
}
|
||||
|
||||
public String getMethodGetBoolean() {
|
||||
return methodGetBoolean;
|
||||
}
|
||||
|
||||
public String getMethodGetFloat() {
|
||||
return methodGetFloat;
|
||||
}
|
||||
|
||||
public String getMethodGetDouble() {
|
||||
return methodGetDouble;
|
||||
}
|
||||
|
||||
public String getMethodGetLong() {
|
||||
return methodGetLong;
|
||||
}
|
||||
|
||||
public String getMethodGetInt() {
|
||||
return methodGetInt;
|
||||
}
|
||||
|
||||
public String getMethodGetString() {
|
||||
return methodGetString;
|
||||
}
|
||||
|
||||
public String getMethodSetBoolean() {
|
||||
return methodSetBoolean;
|
||||
}
|
||||
|
||||
public String getMethodSetFloat() {
|
||||
return methodSetFloat;
|
||||
}
|
||||
|
||||
public String getMethodSetDouble() {
|
||||
return methodSetDouble;
|
||||
}
|
||||
|
||||
public String getMethodSetLong() {
|
||||
return methodSetLong;
|
||||
}
|
||||
|
||||
public String getMethodSetInt() {
|
||||
return methodSetInt;
|
||||
}
|
||||
|
||||
public String getMethodSetString() {
|
||||
return methodSetString;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
package fr.maxlego08.koth.zcore.utils.nms;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.Base64;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class ItemStackUtils {
|
||||
|
||||
private static final NmsVersion NMS_VERSION = NmsVersion.nmsVersion;
|
||||
private static volatile Map<ItemStack, String> itemstackSerialized = new HashMap<ItemStack, String>();
|
||||
|
||||
/**
|
||||
*
|
||||
* Change {@link ItemStack} to {@link String}
|
||||
*
|
||||
* @param paramItemStack
|
||||
* @return {@link String}
|
||||
*/
|
||||
public static String serializeItemStack(ItemStack paramItemStack) {
|
||||
|
||||
if (paramItemStack == null)
|
||||
return "null";
|
||||
|
||||
if (itemstackSerialized.containsKey(paramItemStack))
|
||||
return itemstackSerialized.get(paramItemStack);
|
||||
|
||||
ByteArrayOutputStream localByteArrayOutputStream = null;
|
||||
try {
|
||||
Class<?> localClass = EnumReflectionItemStack.NBTTAGCOMPOUND.getClassz();
|
||||
Constructor<?> localConstructor = localClass.getConstructor(new Class[0]);
|
||||
Object localObject1 = localConstructor.newInstance(new Object[0]);
|
||||
Object localObject2 = EnumReflectionItemStack.CRAFTITEMSTACK.getClassz()
|
||||
.getMethod("asNMSCopy", new Class[] { ItemStack.class })
|
||||
.invoke(null, new Object[] { paramItemStack });
|
||||
|
||||
if (NMSUtils.isNewNBTVersion()) {
|
||||
EnumReflectionItemStack.ITEMSTACK.getClassz().getMethod("b", new Class[] { localClass })
|
||||
.invoke(localObject2, new Object[] { localObject1 });
|
||||
} else {
|
||||
EnumReflectionItemStack.ITEMSTACK.getClassz().getMethod("save", new Class[] { localClass })
|
||||
.invoke(localObject2, new Object[] { localObject1 });
|
||||
}
|
||||
|
||||
localByteArrayOutputStream = new ByteArrayOutputStream();
|
||||
EnumReflectionItemStack.NBTCOMPRESSEDSTREAMTOOLS.getClassz()
|
||||
.getMethod("a", new Class[] { localClass, OutputStream.class })
|
||||
.invoke(null, new Object[] { localObject1, localByteArrayOutputStream });
|
||||
} catch (Exception localException) {
|
||||
// localException.printStackTrace();
|
||||
}
|
||||
String string = Base64.encode(localByteArrayOutputStream.toByteArray());
|
||||
itemstackSerialized.put(paramItemStack, string);
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Change {@link String} to {@link ItemStack}
|
||||
*
|
||||
* @param paramString
|
||||
* @return {@link ItemStack}
|
||||
*/
|
||||
public static ItemStack deserializeItemStack(String paramString) {
|
||||
|
||||
if (paramString.equals("null"))
|
||||
return null;
|
||||
|
||||
ByteArrayInputStream localByteArrayInputStream = null;
|
||||
try {
|
||||
localByteArrayInputStream = new ByteArrayInputStream(Base64.decode(paramString));
|
||||
} catch (Exception localBase64DecodingException) {
|
||||
}
|
||||
Class<?> localClass1 = EnumReflectionItemStack.NBTTAGCOMPOUND.getClassz();
|
||||
Class<?> localClass2 = EnumReflectionItemStack.ITEMSTACK.getClassz();
|
||||
Object localObject1 = null;
|
||||
ItemStack localItemStack = null;
|
||||
Object localObject2 = null;
|
||||
try {
|
||||
if (NmsVersion.nmsVersion == NmsVersion.V_1_20_4) {
|
||||
|
||||
DataInputStream datainputstream = new DataInputStream(
|
||||
new BufferedInputStream(new GZIPInputStream(localByteArrayInputStream)));
|
||||
localObject1 = EnumReflectionItemStack.NBTCOMPRESSEDSTREAMTOOLS.getClassz()
|
||||
.getMethod("a", new Class[] { DataInput.class }).invoke(null, datainputstream);
|
||||
} else {
|
||||
|
||||
localObject1 = EnumReflectionItemStack.NBTCOMPRESSEDSTREAMTOOLS.getClassz()
|
||||
.getMethod("a", new Class[] { InputStream.class })
|
||||
.invoke(null, localByteArrayInputStream);
|
||||
}
|
||||
|
||||
if (NMS_VERSION == NmsVersion.V_1_11 || NMS_VERSION == NmsVersion.V_1_12) {
|
||||
Constructor<?> localConstructor = localClass2.getConstructor(localClass1);
|
||||
localObject2 = localConstructor.newInstance(localObject1);
|
||||
} else if (!NMS_VERSION.isItemLegacy()) {
|
||||
localObject2 = localClass2.getMethod("a", new Class[] { localClass1 }).invoke(null,
|
||||
localObject1);
|
||||
} else {
|
||||
localObject2 = localClass2.getMethod("createStack", new Class[] { localClass1 }).invoke(null,
|
||||
localObject1);
|
||||
}
|
||||
|
||||
localItemStack = (ItemStack) EnumReflectionItemStack.CRAFTITEMSTACK.getClassz()
|
||||
.getMethod("asBukkitCopy", new Class[] { localClass2 }).invoke(null, new Object[] { localObject2 });
|
||||
} catch (Exception localException) {
|
||||
// localException.printStackTrace();
|
||||
}
|
||||
if (localItemStack != null && !itemstackSerialized.containsKey(localItemStack))
|
||||
itemstackSerialized.put(localItemStack, paramString);
|
||||
return localItemStack;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* public static boolean isUnbreakable(ItemStack itemStack) { try {
|
||||
*
|
||||
* Class<?> localClass = EnumReflectionItemStack.NBTTAGCOMPOUND.getClassz();
|
||||
* Object localObject2 = EnumReflectionItemStack.CRAFTITEMSTACK.getClassz()
|
||||
* .getMethod("asNMSCopy", new Class[] { ItemStack.class }).invoke(null, new
|
||||
* Object[] { itemStack });
|
||||
*
|
||||
* Object nbttag = EnumReflectionItemStack.ITEMSTACK.getClassz()
|
||||
* .getMethod("getTag", new Class[] { localClass }) .invoke(localObject2,
|
||||
* new Object[] { localObject2 });
|
||||
*
|
||||
* } catch (IllegalAccessException | IllegalArgumentException |
|
||||
* InvocationTargetException | NoSuchMethodException | SecurityException e)
|
||||
* { e.printStackTrace(); return false; } }
|
||||
*/
|
||||
|
||||
public enum EnumReflectionItemStack {
|
||||
|
||||
ITEMSTACK("ItemStack", "net.minecraft.world.item.ItemStack"),
|
||||
|
||||
CRAFTITEMSTACK("inventory.CraftItemStack", true),
|
||||
|
||||
NBTCOMPRESSEDSTREAMTOOLS("NBTCompressedStreamTools", "net.minecraft.nbt.NBTCompressedStreamTools"),
|
||||
|
||||
NBTTAGCOMPOUND("NBTTagCompound", "net.minecraft.nbt.NBTTagCompound"),
|
||||
|
||||
;
|
||||
|
||||
private final String oldClassName;
|
||||
private final String newClassName;
|
||||
private final boolean isBukkit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param oldClassName
|
||||
* @param newClassName
|
||||
* @param isBukkit
|
||||
*/
|
||||
private EnumReflectionItemStack(String oldClassName, String newClassName, boolean isBukkit) {
|
||||
this.oldClassName = oldClassName;
|
||||
this.newClassName = newClassName;
|
||||
this.isBukkit = isBukkit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param oldClassName
|
||||
* @param newClassName
|
||||
*/
|
||||
private EnumReflectionItemStack(String oldClassName, String newClassName) {
|
||||
this(oldClassName, newClassName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param oldClassName
|
||||
*/
|
||||
private EnumReflectionItemStack(String oldClassName) {
|
||||
this(oldClassName, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param oldClassName
|
||||
* @param isBukkit
|
||||
*/
|
||||
private EnumReflectionItemStack(String oldClassName, boolean isBukkit) {
|
||||
this(oldClassName, null, isBukkit);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Create class
|
||||
*
|
||||
* @return class
|
||||
*/
|
||||
public Class<?> getClassz() {
|
||||
String nmsPackage = Bukkit.getServer().getClass().getPackage().getName();
|
||||
String nmsVersion = nmsPackage.replace(".", ",").split(",")[3];
|
||||
String var3 = NMSUtils.isNewNMSVersion()
|
||||
? this.isBukkit ? "org.bukkit.craftbukkit." + nmsVersion + "." + this.oldClassName
|
||||
: this.newClassName
|
||||
: (this.isBukkit ? "org.bukkit.craftbukkit." : "net.minecraft.server.") + nmsVersion + "."
|
||||
+ this.oldClassName;
|
||||
Class<?> localClass = null;
|
||||
try {
|
||||
localClass = Class.forName(var3);
|
||||
} catch (ClassNotFoundException localClassNotFoundException) {
|
||||
localClassNotFoundException.printStackTrace();
|
||||
}
|
||||
return localClass;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
package fr.maxlego08.koth.zcore.utils.nms;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class NMSUtils {
|
||||
|
||||
public static double version = getNMSVersion();
|
||||
|
||||
/**
|
||||
* Get minecraft serveur version
|
||||
*
|
||||
* @return version
|
||||
*/
|
||||
public static double getNMSVersion() {
|
||||
if (version != 0)
|
||||
return version;
|
||||
String var1 = Bukkit.getServer().getClass().getPackage().getName();
|
||||
String[] arrayOfString = var1.replace(".", ",").split(",")[3].split("_");
|
||||
String var2 = arrayOfString[0].replace("v", "");
|
||||
String var3 = arrayOfString[1];
|
||||
return version = Double.parseDouble(var2 + "." + var3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if minecraft version has shulker
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean hasShulker() {
|
||||
return !isOneHand();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if minecraft version has barrel
|
||||
*
|
||||
* @return booleab
|
||||
*/
|
||||
public static boolean hasBarrel() {
|
||||
final double version = getNMSVersion();
|
||||
return !(version == 1.7 || version == 1.8 || version == 1.9 || version == 1.10 || version == 1.11
|
||||
|| version == 1.12 || version == 1.13);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if version is granther than 1.13
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isNewVersion() {
|
||||
return !isOldVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if version has one hand
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isOneHand() {
|
||||
return getNMSVersion() == 1.7 || getNMSVersion() == 1.8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check is version is minecraft 1.7
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isVeryOldVersion() {
|
||||
return getNMSVersion() == 1.7;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if version has itemmeta unbreakable
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isUnbreakable() {
|
||||
return version == 1.7 || version == 1.8 || version == 1.9 || version == 1.10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if version is old version of minecraft with old material system
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isOldVersion() {
|
||||
return version == 1.7 || version == 1.8 || version == 1.9 || version == 1.10 || version == 1.12
|
||||
|| version == 1.11;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Check if server vesion is new version
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isNewNMSVersion() {
|
||||
final double version = getNMSVersion();
|
||||
return !(version == 1.7 || version == 1.8 || version == 1.9 || version == 1.10 || version == 1.11
|
||||
|| version == 1.12 || version == 1.13 || version == 1.14 || version == 1.15 || version == 1.16);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Check if server version is new version
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isNewNBTVersion() {
|
||||
final double version = getNMSVersion();
|
||||
return !(version == 1.7 || version == 1.8 || version == 1.9 || version == 1.10 || version == 1.11
|
||||
|| version == 1.12 || version == 1.13 || version == 1.14 || version == 1.15 || version == 1.16
|
||||
|| version == 1.17);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to check if the version has the colors in hex
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isHexColor() {
|
||||
return !(version == 1.7 || version == 1.8 || version == 1.9 || version == 1.10 || version == 1.11
|
||||
|| version == 1.12 || version == 1.13 || version == 1.14 || version == 1.15);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
package fr.maxlego08.koth.zcore.utils.nms;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public enum NmsVersion {
|
||||
|
||||
V_1_8_8(1880),
|
||||
V_1_9(1900),
|
||||
V_1_10(1100),
|
||||
V_1_11(1110),
|
||||
V_1_12(1120),
|
||||
V_1_12_2(1122),
|
||||
V_1_13(1130),
|
||||
V_1_13_1(1131),
|
||||
V_1_13_2(1132),
|
||||
V_1_14(1140),
|
||||
V_1_14_1(1141),
|
||||
V_1_14_2(1142),
|
||||
V_1_14_3(1143),
|
||||
V_1_14_4(1144),
|
||||
V_1_15(1150),
|
||||
V_1_15_1(1151),
|
||||
V_1_15_2(1152),
|
||||
V_1_16(1160),
|
||||
V_1_16_1(1161),
|
||||
V_1_16_2(1162),
|
||||
V_1_16_3(1163),
|
||||
V_1_16_4(1164),
|
||||
V_1_16_5(1165),
|
||||
V_1_17(1170),
|
||||
V_1_17_1(1171),
|
||||
V_1_17_2(1172),
|
||||
V_1_18(1180),
|
||||
V_1_18_1(1181),
|
||||
V_1_18_2(1182),
|
||||
V_1_19(1190),
|
||||
V_1_19_1(1191),
|
||||
V_1_19_2(1192),
|
||||
V_1_20(1200),
|
||||
V_1_20_1(1201),
|
||||
V_1_20_2(1202),
|
||||
V_1_20_3(1204),
|
||||
V_1_20_4(1203),
|
||||
V_1_21(1210),
|
||||
|
||||
;
|
||||
|
||||
public static final NmsVersion nmsVersion = getCurrentVersion();
|
||||
private final int version;
|
||||
|
||||
NmsVersion(int version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current version of the Bukkit server.
|
||||
*
|
||||
* @return The NmsVersion instance corresponding to the current version.
|
||||
*/
|
||||
public static NmsVersion getCurrentVersion() {
|
||||
Matcher matcher = Pattern.compile("(?<version>\\d+\\.\\d+)(?<patch>\\.\\d+)?").matcher(Bukkit.getBukkitVersion());
|
||||
int currentVersion = matcher.find() ? Integer.parseInt(matcher.group("version").replace(".", "") + (matcher.group("patch") != null ? matcher.group("patch").replace(".", "") : "0")) : 0;
|
||||
|
||||
// Returns the version closest to the current version
|
||||
return java.util.Arrays.stream(values()).min(java.util.Comparator.comparingInt(v -> Math.abs(v.version - currentVersion))).orElse(V_1_12_2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current version supports PlayerProfiles.
|
||||
*
|
||||
* @return True if PlayerProfiles are supported, else False.
|
||||
*/
|
||||
public boolean hasPlayerProfiles() {
|
||||
return version >= 1181;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current version uses obfuscated names.
|
||||
*
|
||||
* @return True if names are obfuscated, else False.
|
||||
*/
|
||||
public boolean hasObfuscatedNames() {
|
||||
return version >= 1170;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current version supports components.
|
||||
*
|
||||
* @param isPaper True if the server uses Paper, else False.
|
||||
* @return True if components are supported, else False.
|
||||
*/
|
||||
public boolean isComponent(boolean isPaper) {
|
||||
return isPaper && version >= 1165;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current version is a legacy item version.
|
||||
*
|
||||
* @return True if the version is legacy, else False.
|
||||
*/
|
||||
public boolean isItemLegacy() {
|
||||
return version < 1130;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current version supports PersistentDataContainer.
|
||||
*
|
||||
* @return True if PersistentDataContainer is supported, else False.
|
||||
*/
|
||||
public boolean isPdcVersion() {
|
||||
return version >= 1140;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current version is a legacy version for Skull owners.
|
||||
*
|
||||
* @return True if the version is legacy, else False.
|
||||
*/
|
||||
public boolean isSkullOwnerLegacy() {
|
||||
return version <= 1120;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current version supports CustomModelData.
|
||||
*
|
||||
* @return True if CustomModelData is supported, else False.
|
||||
*/
|
||||
public boolean isCustomModelData() {
|
||||
return version >= 1140;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current version is a hexadecimal version.
|
||||
*
|
||||
* @return True if the version is hexadecimal, else False.
|
||||
*/
|
||||
public boolean isHexVersion() {
|
||||
return version >= 1160;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current version is an Attribute version.
|
||||
*
|
||||
* @return True if the version is Attribute, else False.
|
||||
*/
|
||||
public boolean isAttributeVersion() {
|
||||
return version != 1880;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version number associated with the enumeration.
|
||||
*
|
||||
* @return The version number.
|
||||
*/
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package fr.maxlego08.koth.zcore.utils.players;
|
||||
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.nms.NMSUtils;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ActionBar {
|
||||
|
||||
private static final double nmsVersion = NMSUtils.getNMSVersion();
|
||||
private static Class<?> craftPlayerClass;
|
||||
private static Class<?> packetClass;
|
||||
private static Method getHandleMethod;
|
||||
private static Field playerConnectionField;
|
||||
private static Constructor<?> constructorPacket;
|
||||
private static Constructor<?> constructorComponent;
|
||||
|
||||
static {
|
||||
String nmsVersionAsString = Bukkit.getServer().getClass().getPackage().getName();
|
||||
nmsVersionAsString = nmsVersionAsString.substring(nmsVersionAsString.lastIndexOf(".") + 1);
|
||||
|
||||
try {
|
||||
craftPlayerClass = Class.forName("org.bukkit.craftbukkit." + nmsVersionAsString + ".entity.CraftPlayer");
|
||||
Class<?> packetPlayOutChatClass = Class.forName("net.minecraft.server." + nmsVersionAsString + ".PacketPlayOutChat");
|
||||
packetClass = Class.forName("net.minecraft.server." + nmsVersionAsString + ".Packet");
|
||||
Class<?> iChatBaseComponentClass = Class.forName("net.minecraft.server." + nmsVersionAsString + ".IChatBaseComponent");
|
||||
|
||||
getHandleMethod = craftPlayerClass.getMethod("getHandle");
|
||||
playerConnectionField = getHandleMethod.getReturnType().getField("playerConnection");
|
||||
|
||||
Class<?> chatComponentTextClass = Class.forName("net.minecraft.server." + nmsVersionAsString + ".ChatComponentText");
|
||||
|
||||
constructorComponent = chatComponentTextClass.getConstructor(String.class);
|
||||
constructorPacket = packetPlayOutChatClass.getConstructor(iChatBaseComponentClass, Byte.TYPE);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendActionBar(Player player, String message) {
|
||||
|
||||
if (!player.isOnline()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nmsVersion != 1.7 && nmsVersion != 1.8 && nmsVersion != 1.9) {
|
||||
player.spigot().sendMessage(ChatMessageType.ACTION_BAR,
|
||||
new TextComponent(TextComponent.fromLegacyText(message)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Object craftPlayer = craftPlayerClass.cast(player);
|
||||
Object packet = constructorComponent.newInstance(message);
|
||||
Object packetContent = constructorPacket.newInstance(packet, (byte) 2);
|
||||
Object serverPlayer = getHandleMethod.invoke(craftPlayer);
|
||||
packet = playerConnectionField.get(serverPlayer);
|
||||
Method packetMethod = packet.getClass().getDeclaredMethod("sendPacket", packetClass);
|
||||
packetMethod.invoke(packet, packetContent);
|
||||
} catch (Exception error) {
|
||||
error.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
package fr.maxlego08.koth.zcore.utils.players;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import fr.maxlego08.koth.zcore.utils.interfaces.StringConsumer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarFlag;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
import org.bukkit.boss.BossBar;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class BarApi {
|
||||
|
||||
private final Plugin plugin;
|
||||
private String message;
|
||||
private BarColor color = BarColor.BLUE;
|
||||
private BarStyle style = BarStyle.SOLID;
|
||||
private BarFlag[] flags = new BarFlag[] {};
|
||||
private long delay = 5;
|
||||
private boolean addAll = true;
|
||||
private StringConsumer<Player> consumer;
|
||||
private boolean personnal = false;
|
||||
private Player player;
|
||||
|
||||
public BarApi(Plugin plugin, String message, BarColor color, BarStyle style, BarFlag... flags) {
|
||||
this(plugin);
|
||||
this.message = message;
|
||||
this.color = color;
|
||||
this.style = style;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
public BarApi(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public BarApi(Plugin plugin, String message) {
|
||||
this(plugin);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public BarApi delay(long delay) {
|
||||
this.delay = delay;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BarApi color(BarColor color) {
|
||||
this.color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BarApi style(BarStyle style) {
|
||||
this.style = style;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BarApi flags(BarFlag... flags) {
|
||||
this.flags = flags;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BarApi consumer(StringConsumer<Player> consumer) {
|
||||
this.consumer = consumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BarApi all() {
|
||||
addAll = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BarApi personnal() {
|
||||
personnal = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the message
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the color
|
||||
*/
|
||||
public BarColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the style
|
||||
*/
|
||||
public BarStyle getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the flags
|
||||
*/
|
||||
public BarFlag[] getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
|
||||
if (player != null)
|
||||
startPersonnal(player);
|
||||
else if (personnal)
|
||||
startPersonnal();
|
||||
else {
|
||||
BossBar bar = Bukkit.createBossBar(message, color, style, flags);
|
||||
if (addAll)
|
||||
Bukkit.getOnlinePlayers().forEach(tmpPlayer -> bar.addPlayer(tmpPlayer));
|
||||
barTask(bar, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void startPersonnal() {
|
||||
Bukkit.getOnlinePlayers().forEach(tmpPlayer -> startPersonnal(tmpPlayer));
|
||||
}
|
||||
|
||||
private void startPersonnal(Player player) {
|
||||
|
||||
BossBar bar = Bukkit.createBossBar(consumer != null ? consumer.accept(player) : message, color, style, flags);
|
||||
bar.addPlayer(player);
|
||||
barTask(bar, () -> bar.setTitle(consumer != null ? consumer.accept(player) : message));
|
||||
|
||||
}
|
||||
|
||||
private void barTask(BossBar bar, Runnable runnable) {
|
||||
new Timer().scheduleAtFixedRate(new TimerTask() {
|
||||
|
||||
private double barC = 1.0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
if (!plugin.isEnabled()) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (barC <= 0.0) {
|
||||
cancel();
|
||||
bar.removeAll();
|
||||
return;
|
||||
}
|
||||
|
||||
if (runnable != null)
|
||||
runnable.run();
|
||||
|
||||
bar.setProgress(barC);
|
||||
barC -= 0.001;
|
||||
|
||||
}
|
||||
}, 0, delay);
|
||||
}
|
||||
|
||||
public BarApi user(Player player) {
|
||||
this.player = player;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,734 @@
|
|||
package fr.maxlego08.koth.zcore.utils.plugins;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.logging.Level;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
/**
|
||||
* bStats collects some data for plugin authors.
|
||||
* <p>
|
||||
* Check out https://bStats.org/ to learn more about bStats!
|
||||
*/
|
||||
public class Metrics {
|
||||
|
||||
static {
|
||||
// You can use the property to disable the check in your test environment
|
||||
if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) {
|
||||
// Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D
|
||||
final String defaultPackage = new String(
|
||||
new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'});
|
||||
final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
|
||||
// We want to make sure nobody just copy & pastes the example and use the wrong package names
|
||||
if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) {
|
||||
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The version of this bStats class
|
||||
public static final int B_STATS_VERSION = 1;
|
||||
|
||||
// The url to which the data is sent
|
||||
private static final String URL = "https://bStats.org/submitData/bukkit";
|
||||
|
||||
// Is bStats enabled on this server?
|
||||
private boolean enabled;
|
||||
|
||||
// Should failed requests be logged?
|
||||
private static boolean logFailedRequests;
|
||||
|
||||
// Should the sent data be logged?
|
||||
private static boolean logSentData;
|
||||
|
||||
// Should the response text be logged?
|
||||
private static boolean logResponseStatusText;
|
||||
|
||||
// The uuid of the server
|
||||
private static String serverUUID;
|
||||
|
||||
// The plugin
|
||||
private final Plugin plugin;
|
||||
|
||||
// The plugin id
|
||||
private final int pluginId;
|
||||
|
||||
// A list with all custom charts
|
||||
private final List<CustomChart> charts = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param plugin The plugin which stats should be submitted.
|
||||
* @param pluginId The id of the plugin.
|
||||
* It can be found at <a href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a>
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public Metrics(Plugin plugin, int pluginId) {
|
||||
if (plugin == null) {
|
||||
throw new IllegalArgumentException("Plugin cannot be null!");
|
||||
}
|
||||
this.plugin = plugin;
|
||||
this.pluginId = pluginId;
|
||||
|
||||
// Get the config file
|
||||
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||
File configFile = new File(bStatsFolder, "config.yml");
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
||||
|
||||
// Check if the config file exists
|
||||
if (!config.isSet("serverUuid")) {
|
||||
|
||||
// Add default values
|
||||
config.addDefault("enabled", true);
|
||||
// Every server gets it's unique random id.
|
||||
config.addDefault("serverUuid", UUID.randomUUID().toString());
|
||||
// Should failed request be logged?
|
||||
config.addDefault("logFailedRequests", false);
|
||||
// Should the sent data be logged?
|
||||
config.addDefault("logSentData", false);
|
||||
// Should the response text be logged?
|
||||
config.addDefault("logResponseStatusText", false);
|
||||
|
||||
// Inform the server owners about bStats
|
||||
config.options().header(
|
||||
"bStats collects some data for plugin authors like how many servers are using their plugins.\n" +
|
||||
"To honor their work, you should not disable it.\n" +
|
||||
"This has nearly no effect on the server performance!\n" +
|
||||
"Check out https://bStats.org/ to learn more :)"
|
||||
).copyDefaults(true);
|
||||
try {
|
||||
config.save(configFile);
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
|
||||
// Load the data
|
||||
enabled = config.getBoolean("enabled", true);
|
||||
serverUUID = config.getString("serverUuid");
|
||||
logFailedRequests = config.getBoolean("logFailedRequests", false);
|
||||
logSentData = config.getBoolean("logSentData", false);
|
||||
logResponseStatusText = config.getBoolean("logResponseStatusText", false);
|
||||
|
||||
if (enabled) {
|
||||
boolean found = false;
|
||||
// Search for all other bStats Metrics classes to see if we are the first one
|
||||
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||
try {
|
||||
service.getField("B_STATS_VERSION"); // Our identifier :)
|
||||
found = true; // We aren't the first
|
||||
break;
|
||||
} catch (NoSuchFieldException ignored) { }
|
||||
}
|
||||
// Register our service
|
||||
Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal);
|
||||
if (!found) {
|
||||
// We are the first!
|
||||
startSubmitting();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if bStats is enabled.
|
||||
*
|
||||
* @return Whether bStats is enabled or not.
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom chart.
|
||||
*
|
||||
* @param chart The chart to add.
|
||||
*/
|
||||
public void addCustomChart(CustomChart chart) {
|
||||
if (chart == null) {
|
||||
throw new IllegalArgumentException("Chart cannot be null!");
|
||||
}
|
||||
charts.add(chart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the Scheduler which submits our data every 30 minutes.
|
||||
*/
|
||||
private void startSubmitting() {
|
||||
final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!plugin.isEnabled()) { // Plugin was disabled
|
||||
timer.cancel();
|
||||
return;
|
||||
}
|
||||
// Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler
|
||||
// Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;)
|
||||
Bukkit.getScheduler().runTask(plugin, () -> submitData());
|
||||
}
|
||||
}, 1000 * 60 * 5, 1000 * 60 * 30);
|
||||
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
|
||||
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
|
||||
// WARNING: Just don't do it!
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plugin specific data.
|
||||
* This method is called using Reflection.
|
||||
*
|
||||
* @return The plugin specific data.
|
||||
*/
|
||||
public JsonObject getPluginData() {
|
||||
JsonObject data = new JsonObject();
|
||||
|
||||
String pluginName = "zAuctionHouseV2";
|
||||
String pluginVersion = plugin.getDescription().getVersion();
|
||||
|
||||
data.addProperty("pluginName", pluginName); // Append the name of the plugin
|
||||
data.addProperty("id", pluginId); // Append the id of the plugin
|
||||
data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin
|
||||
JsonArray customCharts = new JsonArray();
|
||||
for (CustomChart customChart : charts) {
|
||||
// Add the data of the custom charts
|
||||
JsonObject chart = customChart.getRequestJsonObject();
|
||||
if (chart == null) { // If the chart is null, we skip it
|
||||
continue;
|
||||
}
|
||||
customCharts.add(chart);
|
||||
}
|
||||
data.add("customCharts", customCharts);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server specific data.
|
||||
*
|
||||
* @return The server specific data.
|
||||
*/
|
||||
private JsonObject getServerData() {
|
||||
// Minecraft specific data
|
||||
int playerAmount;
|
||||
try {
|
||||
// Around MC 1.8 the return type was changed to a collection from an array,
|
||||
// This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
|
||||
Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
|
||||
playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class)
|
||||
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
|
||||
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
|
||||
} catch (Exception e) {
|
||||
playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed
|
||||
}
|
||||
int onlineMode = Bukkit.getOnlineMode() ? 1 : 0;
|
||||
String bukkitVersion = Bukkit.getVersion();
|
||||
String bukkitName = Bukkit.getName();
|
||||
|
||||
// OS/Java specific data
|
||||
String javaVersion = System.getProperty("java.version");
|
||||
String osName = System.getProperty("os.name");
|
||||
String osArch = System.getProperty("os.arch");
|
||||
String osVersion = System.getProperty("os.version");
|
||||
int coreCount = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
JsonObject data = new JsonObject();
|
||||
|
||||
data.addProperty("serverUUID", serverUUID);
|
||||
|
||||
data.addProperty("playerAmount", playerAmount);
|
||||
data.addProperty("onlineMode", onlineMode);
|
||||
data.addProperty("bukkitVersion", bukkitVersion);
|
||||
data.addProperty("bukkitName", bukkitName);
|
||||
|
||||
data.addProperty("javaVersion", javaVersion);
|
||||
data.addProperty("osName", osName);
|
||||
data.addProperty("osArch", osArch);
|
||||
data.addProperty("osVersion", osVersion);
|
||||
data.addProperty("coreCount", coreCount);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the data and sends it afterwards.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private void submitData() {
|
||||
final JsonObject data = getServerData();
|
||||
|
||||
JsonArray pluginData = new JsonArray();
|
||||
// Search for all other bStats Metrics classes to get their plugin data
|
||||
for (Class<?> service : Bukkit.getServicesManager().getKnownServices()) {
|
||||
try {
|
||||
service.getField("B_STATS_VERSION"); // Our identifier :)
|
||||
|
||||
for (RegisteredServiceProvider<?> provider : Bukkit.getServicesManager().getRegistrations(service)) {
|
||||
try {
|
||||
Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider());
|
||||
if (plugin instanceof JsonObject) {
|
||||
pluginData.add((JsonObject) plugin);
|
||||
} else { // old bstats version compatibility
|
||||
try {
|
||||
Class<?> jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject");
|
||||
if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) {
|
||||
Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString");
|
||||
jsonStringGetter.setAccessible(true);
|
||||
String jsonString = (String) jsonStringGetter.invoke(plugin);
|
||||
JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject();
|
||||
pluginData.add(object);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
// minecraft version 1.14+
|
||||
if (logFailedRequests) {
|
||||
this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { }
|
||||
}
|
||||
} catch (NoSuchFieldException ignored) { }
|
||||
}
|
||||
|
||||
data.add("plugins", pluginData);
|
||||
|
||||
// Create a new thread for the connection to the bStats server
|
||||
new Thread(() -> {
|
||||
try {
|
||||
// Send the data
|
||||
sendData(plugin, data);
|
||||
} catch (Exception e) {
|
||||
// Something went wrong! :(
|
||||
if (logFailedRequests) {
|
||||
plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the data to the bStats server.
|
||||
*
|
||||
* @param plugin Any plugin. It's just used to get a logger instance.
|
||||
* @param data The data to send.
|
||||
* @throws Exception If the request failed.
|
||||
*/
|
||||
private static void sendData(Plugin plugin, JsonObject data) throws Exception {
|
||||
if (data == null) {
|
||||
throw new IllegalArgumentException("Data cannot be null!");
|
||||
}
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
throw new IllegalAccessException("This method must not be called from the main thread!");
|
||||
}
|
||||
if (logSentData) {
|
||||
plugin.getLogger().info("Sending data to bStats: " + data);
|
||||
}
|
||||
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
|
||||
|
||||
// Compress the data to save bandwidth
|
||||
byte[] compressedData = compress(data.toString());
|
||||
|
||||
// Add headers
|
||||
connection.setRequestMethod("POST");
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
|
||||
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
|
||||
connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
|
||||
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
|
||||
|
||||
// Send data
|
||||
connection.setDoOutput(true);
|
||||
try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
|
||||
outputStream.write(compressedData);
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (logResponseStatusText) {
|
||||
plugin.getLogger().info("Sent data to bStats and received response: " + builder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gzips the given String.
|
||||
*
|
||||
* @param str The string to gzip.
|
||||
* @return The gzipped String.
|
||||
* @throws IOException If the compression failed.
|
||||
*/
|
||||
private static byte[] compress(final String str) throws IOException {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
|
||||
gzip.write(str.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom chart.
|
||||
*/
|
||||
public static abstract class CustomChart {
|
||||
|
||||
// The id of the chart
|
||||
final String chartId;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
*/
|
||||
CustomChart(String chartId) {
|
||||
if (chartId == null || chartId.isEmpty()) {
|
||||
throw new IllegalArgumentException("ChartId cannot be null or empty!");
|
||||
}
|
||||
this.chartId = chartId;
|
||||
}
|
||||
|
||||
private JsonObject getRequestJsonObject() {
|
||||
JsonObject chart = new JsonObject();
|
||||
chart.addProperty("chartId", chartId);
|
||||
try {
|
||||
JsonObject data = getChartData();
|
||||
if (data == null) {
|
||||
// If the data is null we don't send the chart.
|
||||
return null;
|
||||
}
|
||||
chart.add("data", data);
|
||||
} catch (Throwable t) {
|
||||
if (logFailedRequests) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return chart;
|
||||
}
|
||||
|
||||
protected abstract JsonObject getChartData() throws Exception;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom simple pie.
|
||||
*/
|
||||
public static class SimplePie extends CustomChart {
|
||||
|
||||
private final Callable<String> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimplePie(String chartId, Callable<String> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
String value = callable.call();
|
||||
if (value == null || value.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.addProperty("value", value);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom advanced pie.
|
||||
*/
|
||||
public static class AdvancedPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
JsonObject values = new JsonObject();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
continue; // Skip this invalid
|
||||
}
|
||||
allSkipped = false;
|
||||
values.addProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom drilldown pie.
|
||||
*/
|
||||
public static class DrilldownPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Map<String, Integer>>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
JsonObject values = new JsonObject();
|
||||
Map<String, Map<String, Integer>> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean reallyAllSkipped = true;
|
||||
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||
JsonObject value = new JsonObject();
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
|
||||
value.addProperty(valueEntry.getKey(), valueEntry.getValue());
|
||||
allSkipped = false;
|
||||
}
|
||||
if (!allSkipped) {
|
||||
reallyAllSkipped = false;
|
||||
values.add(entryValues.getKey(), value);
|
||||
}
|
||||
}
|
||||
if (reallyAllSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom single line chart.
|
||||
*/
|
||||
public static class SingleLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Integer> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SingleLineChart(String chartId, Callable<Integer> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
int value = callable.call();
|
||||
if (value == 0) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.addProperty("value", value);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom multi line chart.
|
||||
*/
|
||||
public static class MultiLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
JsonObject values = new JsonObject();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
continue; // Skip this invalid
|
||||
}
|
||||
allSkipped = false;
|
||||
values.addProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom simple bar chart.
|
||||
*/
|
||||
public static class SimpleBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
JsonObject values = new JsonObject();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
JsonArray categoryValues = new JsonArray();
|
||||
categoryValues.add(new JsonPrimitive(entry.getValue()));
|
||||
values.add(entry.getKey(), categoryValues);
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom advanced bar chart.
|
||||
*/
|
||||
public static class AdvancedBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, int[]>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject getChartData() throws Exception {
|
||||
JsonObject data = new JsonObject();
|
||||
JsonObject values = new JsonObject();
|
||||
Map<String, int[]> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, int[]> entry : map.entrySet()) {
|
||||
if (entry.getValue().length == 0) {
|
||||
continue; // Skip this invalid
|
||||
}
|
||||
allSkipped = false;
|
||||
JsonArray categoryValues = new JsonArray();
|
||||
for (int categoryValue : entry.getValue()) {
|
||||
categoryValues.add(new JsonPrimitive(categoryValue));
|
||||
}
|
||||
values.add(entry.getKey(), categoryValues);
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.add("values", values);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package fr.maxlego08.koth.zcore.utils.plugins;
|
||||
|
||||
public enum Plugins {
|
||||
|
||||
VAULT("Vault"),
|
||||
ESSENTIALS("Essentials"),
|
||||
HEADDATABASE("HeadDatabase"),
|
||||
PLACEHOLDER("PlaceholderAPI"),
|
||||
CITIZENS("Citizens"),
|
||||
TRANSLATIONAPI("TranslationAPI"),
|
||||
ZTRANSLATOR("zTranslator"),
|
||||
|
||||
;
|
||||
|
||||
private final String name;
|
||||
|
||||
private Plugins(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
package fr.maxlego08.koth.zcore.utils.plugins;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import fr.maxlego08.koth.zcore.enums.Message;
|
||||
import fr.maxlego08.koth.zcore.logger.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Maxlego08
|
||||
*
|
||||
*/
|
||||
public class VersionChecker implements Listener {
|
||||
|
||||
private final String URL_API = "https://groupez.dev/api/v1/resource/version/%s";
|
||||
private final String URL_RESOURCE = "https://groupez.dev/resources/%s";
|
||||
private final Plugin plugin;
|
||||
private final int pluginID;
|
||||
private boolean useLastVersion = false;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param plugin
|
||||
* @param pluginID
|
||||
*/
|
||||
public VersionChecker(Plugin plugin, int pluginID) {
|
||||
super();
|
||||
this.plugin = plugin;
|
||||
this.pluginID = pluginID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to check if the plugin version is up to date.
|
||||
*/
|
||||
public void useLastVersion() {
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(this, this.plugin); // Register
|
||||
// event
|
||||
|
||||
String pluginVersion = plugin.getDescription().getVersion();
|
||||
AtomicBoolean atomicBoolean = new AtomicBoolean();
|
||||
this.getVersion(version -> {
|
||||
|
||||
long ver = Long.valueOf(version.replace(".", ""));
|
||||
long plVersion = Long.valueOf(pluginVersion.replace(".", ""));
|
||||
atomicBoolean.set(plVersion >= ver);
|
||||
this.useLastVersion = atomicBoolean.get();
|
||||
if (atomicBoolean.get())
|
||||
Logger.info("No update available.");
|
||||
else {
|
||||
Logger.info("New update available. Your version: " + pluginVersion + ", latest version: " + version);
|
||||
Logger.info("Download plugin here: " + String.format(URL_RESOURCE, this.pluginID));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onConnect(PlayerJoinEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
if (!useLastVersion && event.getPlayer().hasPermission("zplugin.notifs")) {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String prefix = Message.PREFIX.getMessage();
|
||||
player.sendMessage(prefix
|
||||
+ "§cYou do not use the latest version of the plugin! Thank you for taking the latest version to avoid any risk of problem!");
|
||||
player.sendMessage(prefix + "§fDownload plugin here: §a" + String.format(URL_RESOURCE, pluginID));
|
||||
}
|
||||
}.runTaskLater(plugin, 20 * 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get version by plugin id
|
||||
*
|
||||
* @param consumer
|
||||
* - Do something after
|
||||
*/
|
||||
public void getVersion(Consumer<String> consumer) {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> {
|
||||
final String apiURL = String.format(URL_API, this.pluginID);
|
||||
try {
|
||||
URL url = new URL(apiURL);
|
||||
URLConnection hc = url.openConnection();
|
||||
hc.setRequestProperty("User-Agent",
|
||||
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2");
|
||||
Scanner scanner = new Scanner(hc.getInputStream());
|
||||
if (scanner.hasNext())
|
||||
consumer.accept(scanner.next());
|
||||
scanner.close();
|
||||
|
||||
} catch (IOException exception) {
|
||||
this.plugin.getLogger().info("Cannot look for updates: " + exception.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package fr.maxlego08.koth.zcore.utils.storage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
|
||||
public class DiscUtils {
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONSTANTS
|
||||
// -------------------------------------------- //
|
||||
|
||||
private final static String UTF8 = "UTF-8";
|
||||
|
||||
// -------------------------------------------- //
|
||||
// BYTE
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static byte[] readBytes(File file) throws IOException {
|
||||
int length = (int) file.length();
|
||||
byte[] output = new byte[length];
|
||||
InputStream in = new FileInputStream(file);
|
||||
int offset = 0;
|
||||
while (offset < length) {
|
||||
offset += in.read(output, offset, (length - offset));
|
||||
}
|
||||
in.close();
|
||||
return output;
|
||||
}
|
||||
|
||||
public static void writeBytes(File file, byte[] bytes) throws IOException {
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
out.write(bytes);
|
||||
out.close();
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// STRING
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static void write(File file, String content) throws IOException {
|
||||
writeBytes(file, utf8(content));
|
||||
}
|
||||
|
||||
public static String read(File file) throws IOException {
|
||||
return utf8(readBytes(file));
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CATCH
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static boolean writeCatch(File file, String content) {
|
||||
try {
|
||||
write(file, content);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String readCatch(File file) {
|
||||
try {
|
||||
return read(file);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// DOWNLOAD
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static boolean downloadUrl(String urlstring, File file) {
|
||||
try {
|
||||
URL url = new URL(urlstring);
|
||||
ReadableByteChannel rbc = Channels.newChannel(url.openStream());
|
||||
@SuppressWarnings("resource")
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.getChannel().transferFrom(rbc, 0, 1 << 24);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean downloadUrl(String urlstring, String filename) {
|
||||
return downloadUrl(urlstring, new File(filename));
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// FILE DELETION
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static boolean deleteRecursive(File path) throws FileNotFoundException {
|
||||
if (!path.exists())
|
||||
throw new FileNotFoundException(path.getAbsolutePath());
|
||||
boolean ret = true;
|
||||
if (path.isDirectory()) {
|
||||
for (File f : path.listFiles()) {
|
||||
ret = ret && deleteRecursive(f);
|
||||
}
|
||||
}
|
||||
return ret && path.delete();
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// UTF8 ENCODE AND DECODE
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static byte[] utf8(String string) {
|
||||
try {
|
||||
return string.getBytes(UTF8);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String utf8(byte[] bytes) {
|
||||
try {
|
||||
return new String(bytes, UTF8);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package fr.maxlego08.koth.zcore.utils.storage;
|
||||
|
||||
public interface NoReloadable {
|
||||
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
package fr.maxlego08.koth.zcore.utils.storage;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import fr.maxlego08.koth.zcore.ZPlugin;
|
||||
import fr.maxlego08.koth.zcore.enums.Folder;
|
||||
import fr.maxlego08.koth.zcore.logger.Logger;
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
|
||||
public class Persist extends ZUtils {
|
||||
|
||||
private ZPlugin p;
|
||||
|
||||
public Persist(ZPlugin p) {
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ //
|
||||
// GET NAME - What should we call this type of object?
|
||||
// ------------------------------------------------------------ //
|
||||
|
||||
public static String getName(Class<?> clazz) {
|
||||
return clazz.getSimpleName().toLowerCase();
|
||||
}
|
||||
|
||||
public static String getName(Object o) {
|
||||
return getName(o.getClass());
|
||||
}
|
||||
|
||||
public static String getName(Type type) {
|
||||
return getName(type.getClass());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ //
|
||||
// GET FILE - In which file would we like to store this object?
|
||||
// ------------------------------------------------------------ //
|
||||
|
||||
public File getFile(String name) {
|
||||
return new File(p.getDataFolder(), name + ".json");
|
||||
}
|
||||
|
||||
public File getFile(Class<?> clazz) {
|
||||
return getFile(getName(clazz));
|
||||
}
|
||||
|
||||
public File getFile(Object obj) {
|
||||
return getFile(getName(obj));
|
||||
}
|
||||
|
||||
public File getFile(Type type) {
|
||||
return getFile(getName(type));
|
||||
}
|
||||
|
||||
// NICE WRAPPERS
|
||||
|
||||
public <T> T loadOrSaveDefault(T def, Class<T> clazz) {
|
||||
return loadOrSaveDefault(def, clazz, getFile(clazz));
|
||||
}
|
||||
|
||||
public <T> T loadOrSaveDefault(T def, Class<T> clazz, String name) {
|
||||
return loadOrSaveDefault(def, clazz, getFile(name));
|
||||
}
|
||||
|
||||
public <T> T loadOrSaveDefault(T def, Class<T> clazz, Folder folder, String name) {
|
||||
return loadOrSaveDefault(def, clazz, getFile(folder.toFolder() + File.separator + name));
|
||||
}
|
||||
|
||||
public <T> T loadOrSaveDefault(T def, Class<T> clazz, File file) {
|
||||
if (!file.exists()) {
|
||||
p.getLog().log("Creating default: " + file, Logger.LogType.SUCCESS);
|
||||
this.save(def, file);
|
||||
return def;
|
||||
}
|
||||
|
||||
T loaded = this.load(clazz, file);
|
||||
|
||||
if (loaded == null) {
|
||||
p.getLog().log("Using default as I failed to load: " + file, Logger.LogType.WARNING);
|
||||
|
||||
/*
|
||||
* Create new config backup
|
||||
*/
|
||||
|
||||
File backup = new File(file.getPath() + "_bad");
|
||||
if (backup.exists())
|
||||
backup.delete();
|
||||
p.getLog().log("Backing up copy of bad file to: " + backup, Logger.LogType.WARNING);
|
||||
|
||||
file.renameTo(backup);
|
||||
|
||||
return def;
|
||||
} else {
|
||||
|
||||
p.getLog().log(file.getAbsolutePath() + " loaded successfully !", Logger.LogType.SUCCESS);
|
||||
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
// SAVE
|
||||
|
||||
public boolean save(Object instance) {
|
||||
return save(instance, getFile(instance));
|
||||
}
|
||||
|
||||
public boolean save(Object instance, String name) {
|
||||
return save(instance, getFile(name));
|
||||
}
|
||||
|
||||
public boolean save(Object instance, Folder folder, String name) {
|
||||
return save(instance, getFile(folder.toFolder() + File.separator + name));
|
||||
}
|
||||
|
||||
public boolean save(Object instance, File file) {
|
||||
|
||||
try {
|
||||
|
||||
boolean b = DiscUtils.writeCatch(file, p.getGson().toJson(instance));
|
||||
p.getLog().log(file.getAbsolutePath() + " successfully saved !", Logger.LogType.SUCCESS);
|
||||
return b;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
p.getLog().log("cannot save file " + file.getAbsolutePath(), Logger.LogType.ERROR);
|
||||
e.printStackTrace();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// LOAD BY CLASS
|
||||
|
||||
public <T> T load(Class<T> clazz) {
|
||||
return load(clazz, getFile(clazz));
|
||||
}
|
||||
|
||||
public <T> T load(Class<T> clazz, String name) {
|
||||
return load(clazz, getFile(name));
|
||||
}
|
||||
|
||||
public <T> T load(Class<T> clazz, File file) {
|
||||
String content = DiscUtils.readCatch(file);
|
||||
if (content == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
T instance = p.getGson().fromJson(content, clazz);
|
||||
return instance;
|
||||
} catch (Exception ex) { // output the error message rather than full
|
||||
// stack trace; error parsing the file, most
|
||||
// likely
|
||||
p.getLog().log(ex.getMessage(), Logger.LogType.ERROR);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// LOAD BY TYPE
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T load(Type typeOfT, String name) {
|
||||
return (T) load(typeOfT, getFile(name));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T load(Type typeOfT, File file) {
|
||||
String content = DiscUtils.readCatch(file);
|
||||
if (content == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return (T) p.getGson().fromJson(content, typeOfT);
|
||||
} catch (Exception ex) { // output the error message rather than full
|
||||
// stack trace; error parsing the file, most
|
||||
// likely
|
||||
p.getLog().log(ex.getMessage(), Logger.LogType.ERROR);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package fr.maxlego08.koth.zcore.utils.storage;
|
||||
|
||||
/**
|
||||
* The Savable interface represents objects that can be saved and loaded using a provided Persist object.
|
||||
* Implement this interface in classes that need to be serialized and deserialized.
|
||||
*/
|
||||
public interface Savable {
|
||||
|
||||
/**
|
||||
* Saves the state of the object using the provided Persist object.
|
||||
*
|
||||
* @param persist The Persist object used to save the state.
|
||||
*/
|
||||
void save(Persist persist);
|
||||
|
||||
/**
|
||||
* Loads the state of the object from the provided Persist object.
|
||||
*
|
||||
* @param persist The Persist object used to load the state.
|
||||
*/
|
||||
void load(Persist persist);
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package fr.maxlego08.koth.zcore.utils.yaml;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import fr.maxlego08.koth.zcore.logger.Logger;
|
||||
import fr.maxlego08.koth.zcore.utils.ZUtils;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public abstract class YamlUtils extends ZUtils {
|
||||
|
||||
protected transient final JavaPlugin plugin;
|
||||
|
||||
/**
|
||||
* @param plugin
|
||||
*/
|
||||
public YamlUtils(JavaPlugin plugin) {
|
||||
super();
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return file confirguration
|
||||
*/
|
||||
protected FileConfiguration getConfig() {
|
||||
return plugin.getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get config
|
||||
*
|
||||
* @param path
|
||||
* @return {@link YamlConfiguration}
|
||||
*/
|
||||
protected YamlConfiguration getConfig(File file) {
|
||||
if (file == null)
|
||||
return null;
|
||||
return YamlConfiguration.loadConfiguration(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get config
|
||||
*
|
||||
* @param path
|
||||
* @return {@link YamlConfiguration}
|
||||
* @throws InventoryFileNotFoundException
|
||||
*/
|
||||
protected YamlConfiguration getConfig(String path) {
|
||||
File file = new File(plugin.getDataFolder() + "/" + path);
|
||||
if (!file.exists())
|
||||
return null;
|
||||
return getConfig(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send info to console
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
protected void info(String message) {
|
||||
Logger.info(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send success to console
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
protected void success(String message) {
|
||||
Logger.info(message, Logger.LogType.SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send error to console
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
protected void error(String message) {
|
||||
Logger.info(message, Logger.LogType.ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send warn to console
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
protected void warn(String message) {
|
||||
Logger.info(message, Logger.LogType.WARNING);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
name: zKoth
|
||||
author: Maxlego08
|
||||
main: fr.maxlego08.koth.KothPlugin
|
||||
website: https://www.spigotmc.org/resources/76749/
|
||||
description: Default plugin developed by GroupeZ
|
||||
version: 3.0.0
|
||||
api-version: 1.13
|
||||
commands:
|
Loading…
Reference in New Issue