🎉 Start V3

This commit is contained in:
Maxlego08 2024-02-22 10:19:15 +01:00
commit 3c051e1588
85 changed files with 12616 additions and 0 deletions

674
LICENSE Normal file
View File

@ -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>.

28
README.md Normal file
View File

@ -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

108
pom.xml Normal file
View File

@ -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>

View File

@ -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();
}
}

View File

@ -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();
}
}
}

View File

@ -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());
}
});
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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()));
}
}
}

View File

@ -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) {
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,7 @@
package fr.maxlego08.koth.placeholder;
@FunctionalInterface
public interface ReturnBiConsumer<T, G, C> {
C accept(T t, G g);
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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);
}
});
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,14 @@
package fr.maxlego08.koth.zcore.enums;
public enum Folder {
UTILS,
;
public String toFolder(){
return name().toLowerCase();
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,11 @@
package fr.maxlego08.koth.zcore.enums;
public enum MessageType {
ACTION,
TCHAT,
TITLE,
CENTER,
NONE,
}

View File

@ -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;
}
}

View File

@ -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("<&>", "§");
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}

View File

@ -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(), ' '));
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}
}

View File

@ -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);
}
}

View File

@ -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";
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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");
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}

View File

@ -0,0 +1,13 @@
package fr.maxlego08.koth.zcore.utils.commands;
public enum CommandType {
SUCCESS,
SYNTAX_ERROR,
EXCEPTION_ERROR,
DEFAULT,
CONTINUE,
;
}

View File

@ -0,0 +1,8 @@
package fr.maxlego08.koth.zcore.utils.commands;
public enum Tab {
START,
CONTAINS,
}

View File

@ -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)));
}
}

View File

@ -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));
}
}

View File

@ -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);
}

View File

@ -0,0 +1,8 @@
package fr.maxlego08.koth.zcore.utils.interfaces;
@FunctionalInterface
public interface StringConsumer<T> {
String accept(T t);
}

View File

@ -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;
}
}

View File

@ -0,0 +1,9 @@
package fr.maxlego08.koth.zcore.utils.inventory;
public enum InventoryResult {
SUCCESS,
ERROR,
DEFAULT,
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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());
}
}
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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());
}
});
}
}

View File

@ -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;
}
}
}

View File

@ -0,0 +1,5 @@
package fr.maxlego08.koth.zcore.utils.storage;
public interface NoReloadable {
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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: