Initial commit
This commit is contained in:
commit
e3422f22c6
325 changed files with 16892 additions and 0 deletions
BIN
.github/znpc.png
vendored
Normal file
BIN
.github/znpc.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
46
.gitignore
vendored
Normal file
46
.gitignore
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
/.idea/*
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/libraries/
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
out/
|
||||||
|
!**/src/main/**/out/
|
||||||
|
!**/src/test/**/out/
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
bin/
|
||||||
|
!**/src/main/**/bin/
|
||||||
|
!**/src/test/**/bin/
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Mac OS ###
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
/plugin/run/
|
||||||
|
/.idea/
|
674
LICENSE
Normal file
674
LICENSE
Normal 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>.
|
49
README.md
Normal file
49
README.md
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
# ZNPCsPlus [](https://discord.gg/MAZz6XpPcg) [](https://ci.pyr.lol/job/ZNPCsPlus/)
|
||||||
|
[]((https://bstats.org/plugin/bukkit/ZNPCsPlus/18244/)) []((https://bstats.org/plugin/bukkit/ZNPCsPlus/18244/)) []((https://www.spigotmc.org/resources/znpcsplus.109380/))
|
||||||
|
|
||||||
|
[ZNPCsPlus](https://www.spigotmc.org/resources/znpcsplus.109380/) is a Spigot plugin that is used to create fake entities
|
||||||
|
that players can interact with to perform actions like switching servers on a network or executing commands.
|
||||||
|
|
||||||
|
This plugin is a remake of a plugin called ZNPCs, we originally started because the maintainer of ZNPCs decided to announce that he was
|
||||||
|
[dropping support for the plugin](https://github.com/Pyrbu/ZNPCsPlus/blob/2.X/.github/znpc.png?raw=true).
|
||||||
|
|
||||||
|
Looking for up-to-date builds of the plugin? Check out our [Jenkins](https://ci.pyr.lol/job/ZNPCsPlus/)
|
||||||
|
|
||||||
|
## Why is it so good?
|
||||||
|
- 100% Packet Based - Nothing is ran on the main thread
|
||||||
|
- Performance & stability oriented code
|
||||||
|
- Support for all versions from 1.8 to 1.20.4
|
||||||
|
- Support for multiple different storage options
|
||||||
|
- Intuitive command system
|
||||||
|
|
||||||
|
### Requirements, Extensions & Supported Software
|
||||||
|
Requirements:
|
||||||
|
- Java 8+
|
||||||
|
- Minecraft 1.8 - 1.21
|
||||||
|
|
||||||
|
Supported Softwares:
|
||||||
|
- Spigot ([Website](https://www.spigotmc.org/))
|
||||||
|
- Paper ([Github](https://github.com/PaperMC/Paper)) ([Website](https://papermc.io/software/paper))
|
||||||
|
- Folia ([Github](https://github.com/PaperMC/Folia)) ([Website](https://papermc.io/software/folia))
|
||||||
|
- ArcLight ([Github](https://github.com/IzzelAliz/Arclight))
|
||||||
|
|
||||||
|
Optional Dependencies/Extensions:
|
||||||
|
- PlaceholderAPI
|
||||||
|
|
||||||
|
## Found a bug?
|
||||||
|
Open an issue in the GitHub [issue tracker](https://github.com/Pyrbu/ZNPCsPlus/issues) or join our [support discord](https://discord.gg/MAZz6XpPcg)
|
||||||
|
|
||||||
|
## BStats
|
||||||
|
[](https://bstats.org/plugin/bukkit/ZNPCsPlus/18244/)
|
||||||
|
|
||||||
|
#### Like what you see? Want the project to continue improving? Consider starring the repository & leaving a positive review on [Spigot](https://www.spigotmc.org/resources/znpcsplus.109380/)!
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
- [PacketEvents 2.0](https://github.com/retrooper/packetevents) - Packet library
|
||||||
|
- [Minecraft Wiki Protocol (formally wiki.vg)](https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Main_Page) - Minecraft protocol documentation
|
||||||
|
- [gson](https://github.com/google/gson) - JSON parsing library made by Google
|
||||||
|
- [Mineskin.org](https://mineskin.org/) - Website for raw skin file uploads
|
||||||
|
- [adventure](https://docs.advntr.dev/) - Minecraft text api
|
||||||
|
- [DazzleConf](https://github.com/A248/DazzleConf) - Configuration library
|
||||||
|
- [Director](https://github.com/Pyrbu/Director) - Command library
|
||||||
|
- [PlaceholderAPI](https://github.com/PlaceholderAPI/PlaceholderAPI) - Universal string placeholder library
|
35
api/build.gradle
Normal file
35
api/build.gradle
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
plugins {
|
||||||
|
id "java"
|
||||||
|
id "maven-publish"
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
withSourcesJar()
|
||||||
|
withJavadocJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
mavenJava(MavenPublication) {
|
||||||
|
from components.java
|
||||||
|
artifactId = "znpcsplus-api"
|
||||||
|
|
||||||
|
pom {
|
||||||
|
name.set("znpcsplus-api")
|
||||||
|
description.set("The API for the ZNPCsPlus plugin")
|
||||||
|
url.set("https://github.com/Pyrbu/ZNPCsPlus")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
Map<String, String> systemProperties = System.getenv()
|
||||||
|
credentials {
|
||||||
|
if (systemProperties.containsKey("DIST_USERNAME")) username systemProperties.get("DIST_USERNAME")
|
||||||
|
if (systemProperties.containsKey("DIST_PASSWORD")) password systemProperties.get("DIST_PASSWORD")
|
||||||
|
}
|
||||||
|
// If the BUILD_ID enviroment variable is present that means its a Jenkins build & that it should go into the snapshots repo
|
||||||
|
url = systemProperties.containsKey("BUILD_ID") ? uri("https://repo.pyr.lol/snapshots/") : uri("https://repo.pyr.lol/releases/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
api/src/main/java/lol/pyr/znpcsplus/api/NpcApi.java
Normal file
56
api/src/main/java/lol/pyr/znpcsplus/api/NpcApi.java
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package lol.pyr.znpcsplus.api;
|
||||||
|
|
||||||
|
import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry;
|
||||||
|
import lol.pyr.znpcsplus.api.interaction.ActionFactory;
|
||||||
|
import lol.pyr.znpcsplus.api.interaction.ActionRegistry;
|
||||||
|
import lol.pyr.znpcsplus.api.npc.NpcRegistry;
|
||||||
|
import lol.pyr.znpcsplus.api.npc.NpcTypeRegistry;
|
||||||
|
import lol.pyr.znpcsplus.api.serialization.NpcSerializerRegistry;
|
||||||
|
import lol.pyr.znpcsplus.api.skin.SkinDescriptorFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main API class for ZNPCsPlus.
|
||||||
|
*/
|
||||||
|
public interface NpcApi {
|
||||||
|
/**
|
||||||
|
* Gets the NPC registry.
|
||||||
|
* @return the NPC registry
|
||||||
|
*/
|
||||||
|
NpcRegistry getNpcRegistry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the NPC type registry.
|
||||||
|
* @return the NPC type registry
|
||||||
|
*/
|
||||||
|
NpcTypeRegistry getNpcTypeRegistry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the entity property registry.
|
||||||
|
* @return the entity property registry
|
||||||
|
*/
|
||||||
|
EntityPropertyRegistry getPropertyRegistry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the action registry.
|
||||||
|
* @return the action registry
|
||||||
|
*/
|
||||||
|
ActionRegistry getActionRegistry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the action factory.
|
||||||
|
* @return the action factory
|
||||||
|
*/
|
||||||
|
ActionFactory getActionFactory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the skin descriptor factory.
|
||||||
|
* @return the skin descriptor factory
|
||||||
|
*/
|
||||||
|
SkinDescriptorFactory getSkinDescriptorFactory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the npc serializer registry.
|
||||||
|
* @return the npc serializer registry
|
||||||
|
*/
|
||||||
|
NpcSerializerRegistry getNpcSerializerRegistry();
|
||||||
|
}
|
50
api/src/main/java/lol/pyr/znpcsplus/api/NpcApiProvider.java
Normal file
50
api/src/main/java/lol/pyr/znpcsplus/api/NpcApiProvider.java
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package lol.pyr.znpcsplus.api;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.plugin.ServicePriority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for the registered api instance
|
||||||
|
*/
|
||||||
|
public class NpcApiProvider {
|
||||||
|
private static NpcApi api = null;
|
||||||
|
|
||||||
|
private NpcApiProvider() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static method that returns the api instance of the plugin
|
||||||
|
*
|
||||||
|
* @return The instance of the api for the ZNPCsPlus plugin
|
||||||
|
*/
|
||||||
|
public static NpcApi get() {
|
||||||
|
if (api == null) throw new IllegalStateException(
|
||||||
|
"ZNPCsPlus plugin isn't enabled yet!\n" +
|
||||||
|
"Please add it to your plugin.yml as a depend or softdepend."
|
||||||
|
);
|
||||||
|
return api;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method used to register the main instance of the plugin as the api provider
|
||||||
|
* You probably shouldn't call this method under any circumstances
|
||||||
|
*
|
||||||
|
* @param plugin Instance of the ZNPCsPlus plugin
|
||||||
|
* @param api Instance of the ZNPCsPlus api
|
||||||
|
*/
|
||||||
|
public static void register(Plugin plugin, NpcApi api) {
|
||||||
|
NpcApiProvider.api = api;
|
||||||
|
Bukkit.getServicesManager().register(NpcApi.class, api, plugin, ServicePriority.Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method used to unregister the plugin from the provider when the plugin shuts down
|
||||||
|
* You probably shouldn't call this method under any circumstances
|
||||||
|
*/
|
||||||
|
public static void unregister() {
|
||||||
|
Bukkit.getServicesManager().unregister(api);
|
||||||
|
NpcApiProvider.api = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package lol.pyr.znpcsplus.api;
|
||||||
|
|
||||||
|
import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.plugin.ServicePriority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for the registered entity property registry instance
|
||||||
|
*/
|
||||||
|
public class NpcPropertyRegistryProvider {
|
||||||
|
private static EntityPropertyRegistry registry = null;
|
||||||
|
|
||||||
|
private NpcPropertyRegistryProvider() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static method that returns the entity property registry instance of the plugin
|
||||||
|
*
|
||||||
|
* @return The instance of the entity property registry for the ZNPCsPlus plugin
|
||||||
|
*/
|
||||||
|
public static EntityPropertyRegistry get() {
|
||||||
|
if (registry == null) throw new IllegalStateException(
|
||||||
|
"ZNPCsPlus plugin isn't loaded yet!\n" +
|
||||||
|
"Please add it to your plugin.yml as a depend or softdepend."
|
||||||
|
);
|
||||||
|
return registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method used to register the main instance of the plugin as the entity property registry provider
|
||||||
|
* You probably shouldn't call this method under any circumstances
|
||||||
|
*
|
||||||
|
* @param plugin Instance of the ZNPCsPlus plugin
|
||||||
|
* @param api Instance of the ZNPCsPlus entity property registry
|
||||||
|
*/
|
||||||
|
public static void register(Plugin plugin, EntityPropertyRegistry api) {
|
||||||
|
NpcPropertyRegistryProvider.registry = api;
|
||||||
|
Bukkit.getServicesManager().register(EntityPropertyRegistry.class, registry, plugin, ServicePriority.Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method used to unregister the plugin from the provider when the plugin shuts down
|
||||||
|
* You probably shouldn't call this method under any circumstances
|
||||||
|
*/
|
||||||
|
public static void unregister() {
|
||||||
|
Bukkit.getServicesManager().unregister(registry);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package lol.pyr.znpcsplus.api.entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that represents a unique property
|
||||||
|
* @param <T> The type of the value of this property
|
||||||
|
*/
|
||||||
|
public interface EntityProperty<T> {
|
||||||
|
/**
|
||||||
|
* The default value of this property, if this is provided in {@link PropertyHolder#setProperty(EntityProperty, Object)}
|
||||||
|
* as the value the property will be removed from the holder
|
||||||
|
*
|
||||||
|
* @return The default value of this property
|
||||||
|
*/
|
||||||
|
T getDefaultValue();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The name of this property
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Whether this property can be modified by players using commands
|
||||||
|
*/
|
||||||
|
boolean isPlayerModifiable();
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package lol.pyr.znpcsplus.api.entity;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class responsible for providing entity property keys
|
||||||
|
* Some property keys are only registered in certain situations for example different minecraft versions
|
||||||
|
*/
|
||||||
|
public interface EntityPropertyRegistry {
|
||||||
|
/**
|
||||||
|
* @return All of the possible property keys
|
||||||
|
*/
|
||||||
|
Collection<EntityProperty<?>> getAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a property key by it's name
|
||||||
|
*
|
||||||
|
* @param name The name of a property key
|
||||||
|
* @return The property key corresponding to the name or null if there is none
|
||||||
|
*/
|
||||||
|
EntityProperty<?> getByName(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a property key by it's name and automatically cast the property to the proper type
|
||||||
|
* If you don't know the type of the property you are requesting use {@link EntityPropertyRegistry#getByName(String)} instead
|
||||||
|
*
|
||||||
|
* @param name The name of a property key
|
||||||
|
* @param type The class of the expected type of the returned property key
|
||||||
|
* @return The property key corresponding to the name
|
||||||
|
* @param <T> The expected type of the returned property key
|
||||||
|
*/
|
||||||
|
<T> EntityProperty<T> getByName(String name, Class<T> type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a dummy property that can be used to store unique information per npc<br>
|
||||||
|
* Note: Properties registered this way will be player-modifiable by default
|
||||||
|
*
|
||||||
|
* @param name The name of the new property
|
||||||
|
* @param type The type of the new property
|
||||||
|
* @deprecated Use {@link #registerDummy(String, Class, boolean)} instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default void registerDummy(String name, Class<?> type) {
|
||||||
|
registerDummy(name, type, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a dummy property that can be used to store unique information per npc
|
||||||
|
*
|
||||||
|
* @param name The name of the new property
|
||||||
|
* @param type The type of the new property
|
||||||
|
* @param playerModifiable Whether this property can be modified by players using commands
|
||||||
|
*/
|
||||||
|
void registerDummy(String name, Class<?> type, boolean playerModifiable);
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package lol.pyr.znpcsplus.api.entity;
|
||||||
|
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents classes that have property values attatched to them
|
||||||
|
*/
|
||||||
|
public interface PropertyHolder {
|
||||||
|
/**
|
||||||
|
* Method used to get the value of a property from a property holder
|
||||||
|
*
|
||||||
|
* @param key Unique key representing a property
|
||||||
|
* @return The value associated with the provided property key and this holder
|
||||||
|
* @param <T> The type of the property value
|
||||||
|
*/
|
||||||
|
<T> T getProperty(EntityProperty<T> key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method used to check if a property holder has a value set for a specific property key
|
||||||
|
*
|
||||||
|
* @param key Unique key representing a property
|
||||||
|
* @return Whether this holder has a value set for the provided key
|
||||||
|
*/
|
||||||
|
boolean hasProperty(EntityProperty<?> key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method used to set a value for the provided key on this property holder
|
||||||
|
*
|
||||||
|
* @param key Unique key representing a property
|
||||||
|
* @param value The value to assign to the property key on this holder
|
||||||
|
* @param <T> The type of the property value
|
||||||
|
*/
|
||||||
|
<T> void setProperty(EntityProperty<T> key, T value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Weird fix which is sadly required in order to not decrease performance
|
||||||
|
* when using item properties, read https://github.com/Pyrbu/ZNPCsPlus/pull/129#issuecomment-1948777764
|
||||||
|
*
|
||||||
|
* @param key Unique key representing a property
|
||||||
|
* @param value The value to assign to the property key on this holder
|
||||||
|
*/
|
||||||
|
void setItemProperty(EntityProperty<?> key, ItemStack value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Weird fix which is sadly required in order to not decrease performance
|
||||||
|
* when using item properties, read https://github.com/Pyrbu/ZNPCsPlus/pull/129#issuecomment-1948777764
|
||||||
|
*
|
||||||
|
* @param key Unique key representing a property
|
||||||
|
* @return the {@link ItemStack} associated with the provided property key and this holder
|
||||||
|
*/
|
||||||
|
ItemStack getItemProperty(EntityProperty<?> key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method used to get a set of all of the property keys that this holder has a value for
|
||||||
|
*
|
||||||
|
* @return Set of property keys
|
||||||
|
*/
|
||||||
|
Set<EntityProperty<?>> getAppliedProperties();
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package lol.pyr.znpcsplus.api.event;
|
||||||
|
|
||||||
|
import lol.pyr.znpcsplus.api.event.util.CancellableNpcEvent;
|
||||||
|
import lol.pyr.znpcsplus.api.npc.NpcEntry;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event called when an NPC is despawned for a player
|
||||||
|
* Note: This event is async
|
||||||
|
*/
|
||||||
|
public class NpcDespawnEvent extends CancellableNpcEvent implements Cancellable {
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param player The player involved in the event
|
||||||
|
* @param entry The NPC entry involved in the event
|
||||||
|
*/
|
||||||
|
public NpcDespawnEvent(Player player, NpcEntry entry) {
|
||||||
|
super(player, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package lol.pyr.znpcsplus.api.event;
|
||||||
|
|
||||||
|
import lol.pyr.znpcsplus.api.event.util.CancellableNpcEvent;
|
||||||
|
import lol.pyr.znpcsplus.api.interaction.InteractionType;
|
||||||
|
import lol.pyr.znpcsplus.api.npc.NpcEntry;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event called when an NPC is interacted with by a player
|
||||||
|
* Note: This event is async
|
||||||
|
*/
|
||||||
|
public class NpcInteractEvent extends CancellableNpcEvent implements Cancellable {
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
private final InteractionType clickType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param player The player involved in the event
|
||||||
|
* @param entry The NPC entry involved in the event
|
||||||
|
* @param clickType The type of interaction. See {@link InteractionType}
|
||||||
|
*/
|
||||||
|
public NpcInteractEvent(Player player, NpcEntry entry, InteractionType clickType) {
|
||||||
|
super(player, entry);
|
||||||
|
this.clickType = clickType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of interaction. See {@link InteractionType}
|
||||||
|
* @return The type of interaction
|
||||||
|
*/
|
||||||
|
public InteractionType getClickType() {
|
||||||
|
return clickType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package lol.pyr.znpcsplus.api.event;
|
||||||
|
|
||||||
|
import lol.pyr.znpcsplus.api.event.util.CancellableNpcEvent;
|
||||||
|
import lol.pyr.znpcsplus.api.npc.NpcEntry;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event called when an NPC is spawned for a player
|
||||||
|
* Note: This event is async
|
||||||
|
*/
|
||||||
|
public class NpcSpawnEvent extends CancellableNpcEvent implements Cancellable {
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param player The player involved in the event
|
||||||
|
* @param entry The NPC entry involved in the event
|
||||||
|
*/
|
||||||
|
public NpcSpawnEvent(Player player, NpcEntry entry) {
|
||||||
|
super(player, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package lol.pyr.znpcsplus.api.event.util;
|
||||||
|
|
||||||
|
import lol.pyr.znpcsplus.api.npc.NpcEntry;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all NPC events that can be cancelled
|
||||||
|
*/
|
||||||
|
public abstract class CancellableNpcEvent extends NpcEvent implements Cancellable {
|
||||||
|
private boolean cancelled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param player The player involved in the event
|
||||||
|
* @param entry The NPC entry involved in the event
|
||||||
|
*/
|
||||||
|
public CancellableNpcEvent(Player player, NpcEntry entry) {
|
||||||
|
super(player, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean cancel) {
|
||||||
|
cancelled = cancel;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package lol.pyr.znpcsplus.api.event.util;
|
||||||
|
|
||||||
|
import lol.pyr.znpcsplus.api.npc.Npc;
|
||||||
|
import lol.pyr.znpcsplus.api.npc.NpcEntry;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all NPC events
|
||||||
|
*/
|
||||||
|
public abstract class NpcEvent extends Event {
|
||||||
|
private final NpcEntry entry;
|
||||||
|
private final Player player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param player The player involved in the event
|
||||||
|
* @param entry The NPC entry involved in the event
|
||||||
|
*/
|
||||||
|
public NpcEvent(Player player, NpcEntry entry) {
|
||||||
|
super(true); // All events are async since 99% of the plugin is async
|
||||||
|
this.entry = entry;
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the player involved in the event
|
||||||
|
* @return The player involved in the event
|
||||||
|
*/
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the NPC entry involved in the event
|
||||||
|
* @return The NPC entry involved in the event
|
||||||
|
*/
|
||||||
|
public NpcEntry getEntry() {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the NPC involved in the event
|
||||||
|
* @return The NPC involved in the event
|
||||||
|
*/
|
||||||
|
public Npc getNpc() {
|
||||||
|
return entry.getNpc();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package lol.pyr.znpcsplus.api.hologram;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a hologram
|
||||||
|
*/
|
||||||
|
public interface Hologram {
|
||||||
|
/**
|
||||||
|
* Adds a line to the hologram
|
||||||
|
* Note: to add an item line, pass "item:<item>" as the line
|
||||||
|
* @param line The line to add
|
||||||
|
*/
|
||||||
|
void addLine(String line);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a line from the hologram
|
||||||
|
* @param index The index of the line to get
|
||||||
|
* @return The line at the index
|
||||||
|
*/
|
||||||
|
String getLine(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a line from the hologram
|
||||||
|
* @param index The index of the line to remove
|
||||||
|
*/
|
||||||
|
void removeLine(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all lines from the hologram
|
||||||
|
*/
|
||||||
|
void clearLines();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a line into the hologram
|
||||||
|
* @param index The index to insert the line at
|
||||||
|
* @param line The line to insert
|
||||||
|
*/
|
||||||
|
void insertLine(int index, String line);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of lines in the hologram
|
||||||
|
* @return The number of lines in the hologram
|
||||||
|
*/
|
||||||
|
int lineCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the refresh delay of the hologram
|
||||||
|
* @return The refresh delay of the hologram
|
||||||
|
*/
|
||||||
|
long getRefreshDelay();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the refresh delay of the hologram
|
||||||
|
* @param delay The delay to set
|
||||||
|
*/
|
||||||
|
void setRefreshDelay(long delay);
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package lol.pyr.znpcsplus.api.interaction;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public interface ActionFactory {
|
||||||
|
InteractionAction createConsoleCommandAction(String command, InteractionType interactionType, long cooldown, long delay);
|
||||||
|
InteractionAction createMessageAction(String message, InteractionType interactionType, long cooldown, long delay);
|
||||||
|
InteractionAction createPlayerChatAction(String message, InteractionType interactionType, long cooldown, long delay);
|
||||||
|
InteractionAction createPlayerCommandAction(String command, InteractionType interactionType, long cooldown, long delay);
|
||||||
|
InteractionAction createSwitchServerAction(String server, InteractionType interactionType, long cooldown, long delay);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package lol.pyr.znpcsplus.api.interaction;
|
||||||
|
|
||||||
|
public interface ActionRegistry {
|
||||||
|
void register(InteractionActionType<?> type);
|
||||||
|
|
||||||
|
void unregister(Class<? extends InteractionAction> clazz);
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
package lol.pyr.znpcsplus.api.interaction;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all NPC interactions
|
||||||
|
*/
|
||||||
|
public abstract class InteractionAction {
|
||||||
|
/**
|
||||||
|
* The unique ID of this interaction
|
||||||
|
*/
|
||||||
|
private final UUID id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cooldown of this interaction in seconds
|
||||||
|
*/
|
||||||
|
private final long cooldown;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The delay of this interaction in ticks
|
||||||
|
*/
|
||||||
|
private final long delay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this interaction
|
||||||
|
*/
|
||||||
|
private final InteractionType interactionType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cooldown The cooldown of this interaction in seconds
|
||||||
|
* @param delay The delay of this interaction in ticks
|
||||||
|
* @param interactionType The type of this interaction
|
||||||
|
*/
|
||||||
|
protected InteractionAction(long cooldown, long delay, InteractionType interactionType) {
|
||||||
|
this.interactionType = interactionType;
|
||||||
|
this.id = UUID.randomUUID();
|
||||||
|
this.cooldown = cooldown;
|
||||||
|
this.delay = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The unique ID of this interaction
|
||||||
|
*/
|
||||||
|
public UUID getUuid() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The cooldown of this interaction in seconds
|
||||||
|
*/
|
||||||
|
public long getCooldown() {
|
||||||
|
return cooldown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The delay of this interaction in ticks
|
||||||
|
*/
|
||||||
|
public long getDelay() {
|
||||||
|
return delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The type of this interaction
|
||||||
|
*/
|
||||||
|
public InteractionType getInteractionType() {
|
||||||
|
return interactionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs this interaction
|
||||||
|
* @param player The player that triggered this interaction
|
||||||
|
*/
|
||||||
|
public abstract void run(Player player);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package lol.pyr.znpcsplus.api.interaction;
|
||||||
|
|
||||||
|
public interface InteractionActionType<T> {
|
||||||
|
String serialize(T obj);
|
||||||
|
T deserialize(String str);
|
||||||
|
Class<T> getActionClass();
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package lol.pyr.znpcsplus.api.interaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of interaction
|
||||||
|
* ANY_CLICK: Any click type
|
||||||
|
* LEFT_CLICK: Only left clicks
|
||||||
|
* RIGHT_CLICK: Only right clicks
|
||||||
|
*/
|
||||||
|
public enum InteractionType {
|
||||||
|
ANY_CLICK,
|
||||||
|
LEFT_CLICK,
|
||||||
|
RIGHT_CLICK
|
||||||
|
}
|
212
api/src/main/java/lol/pyr/znpcsplus/api/npc/Npc.java
Normal file
212
api/src/main/java/lol/pyr/znpcsplus/api/npc/Npc.java
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
package lol.pyr.znpcsplus.api.npc;
|
||||||
|
|
||||||
|
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||||
|
import lol.pyr.znpcsplus.api.hologram.Hologram;
|
||||||
|
import lol.pyr.znpcsplus.api.interaction.InteractionAction;
|
||||||
|
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all NPCs
|
||||||
|
*/
|
||||||
|
public interface Npc extends PropertyHolder {
|
||||||
|
/**
|
||||||
|
* Sets the npc type of this NPC
|
||||||
|
* @param type The {@link NpcType} to set
|
||||||
|
*/
|
||||||
|
void setType(NpcType type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The {@link NpcType} of this NPC
|
||||||
|
*/
|
||||||
|
NpcType getType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the location of this NPC
|
||||||
|
* @return The {@link NpcLocation} of this NPC
|
||||||
|
*/
|
||||||
|
NpcLocation getLocation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the location of this NPC
|
||||||
|
* @param location The {@link NpcLocation} to set
|
||||||
|
*/
|
||||||
|
void setLocation(NpcLocation location);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the world of this NPC
|
||||||
|
* @param world The bukkit world to set
|
||||||
|
*/
|
||||||
|
void setWorld(World world);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the world of this NPC
|
||||||
|
* @param name The name world to set
|
||||||
|
*/
|
||||||
|
void setWorld(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the hologram of this NPC
|
||||||
|
* @return The {@link Hologram} of this NPC
|
||||||
|
*/
|
||||||
|
Hologram getHologram();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if the npc is enabled or not, i.e. if it should be visible to players
|
||||||
|
* @param enabled If the npc should be enabled
|
||||||
|
*/
|
||||||
|
void setEnabled(boolean enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the npc is enabled or not, i.e. if it should be visible to players
|
||||||
|
* @return If the npc is enabled or not
|
||||||
|
*/
|
||||||
|
boolean isEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the unique ID of this NPC
|
||||||
|
* @return The unique ID of this NPC
|
||||||
|
*/
|
||||||
|
UUID getUuid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link World} this NPC is in
|
||||||
|
* Note: can be null if the world is unloaded or does not exist
|
||||||
|
* @return The {@link World} this NPC is in
|
||||||
|
*/
|
||||||
|
World getWorld();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the world this NPC is in
|
||||||
|
* Unlike {@link Npc#getWorld()} this will never be null
|
||||||
|
* @return The name of the world this NPC is in
|
||||||
|
*/
|
||||||
|
String getWorldName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of actions for this NPC
|
||||||
|
* @return The {@link List} of {@link InteractionAction}s for this NPC
|
||||||
|
*/
|
||||||
|
List<? extends InteractionAction> getActions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an action from this NPC
|
||||||
|
* @param index The index of the action to remove
|
||||||
|
*/
|
||||||
|
void removeAction(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an action to this NPC
|
||||||
|
* @param action The {@link InteractionAction} to add
|
||||||
|
*/
|
||||||
|
void addAction(InteractionAction action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits an action for this NPC
|
||||||
|
* @param index The index of the action to edit
|
||||||
|
* @param action The {@link InteractionAction} to set
|
||||||
|
*/
|
||||||
|
void editAction(int index, InteractionAction action);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all actions from this NPC
|
||||||
|
*/
|
||||||
|
void clearActions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if this NPC is visible to a player
|
||||||
|
* @param player The {@link Player} to check
|
||||||
|
* @return If this NPC is visible to the player
|
||||||
|
*/
|
||||||
|
boolean isVisibleTo(Player player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides this NPC from a player
|
||||||
|
* @param player The {@link Player} to hide from
|
||||||
|
*/
|
||||||
|
void hide(Player player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows this NPC to a player
|
||||||
|
* @param player The {@link Player} to show to
|
||||||
|
* @return A future that completes when the npc is fully shown to the player
|
||||||
|
*/
|
||||||
|
CompletableFuture<Void> show(Player player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respawns this NPC for a player
|
||||||
|
* @param player The {@link Player} to respawn for
|
||||||
|
* @return A future that completes when the npc is fully respawned
|
||||||
|
*/
|
||||||
|
CompletableFuture<Void> respawn(Player player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the head rotation of this NPC for a player
|
||||||
|
* @param player The {@link Player} to set the head rotation for
|
||||||
|
* @param yaw The yaw to set
|
||||||
|
* @param pitch The pitch to set
|
||||||
|
*/
|
||||||
|
void setHeadRotation(Player player, float yaw, float pitch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the head rotation of this NPC for all players/viewers
|
||||||
|
* @param yaw The yaw to set
|
||||||
|
* @param pitch The pitch to set
|
||||||
|
*/
|
||||||
|
void setHeadRotation(float yaw, float pitch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The entity id of the packet entity that this npc object represents
|
||||||
|
*/
|
||||||
|
int getPacketEntityId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The set of players that can currently see this npc
|
||||||
|
*/
|
||||||
|
Set<Player> getViewers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swings the entity's hand
|
||||||
|
* @param offHand Should the hand be the offhand
|
||||||
|
*/
|
||||||
|
void swingHand(boolean offHand);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the passengers of this npc
|
||||||
|
* @return The list of entity ids of the passengers
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Nullable List<Integer> getPassengers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a passenger to this npc
|
||||||
|
* @param entityId The entity id of the passenger to add
|
||||||
|
*/
|
||||||
|
void addPassenger(int entityId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a passenger from this npc
|
||||||
|
* @param entityId The entity id of the passenger to remove
|
||||||
|
*/
|
||||||
|
void removePassenger(int entityId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the vehicle entity id of this npc
|
||||||
|
* @return The entity id of the vehicle
|
||||||
|
*/
|
||||||
|
@Nullable Integer getVehicleId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the vehicle id of this npc
|
||||||
|
* @param vehicleId The entity id of the vehicle
|
||||||
|
*/
|
||||||
|
void setVehicleId(Integer vehicleId);
|
||||||
|
}
|
56
api/src/main/java/lol/pyr/znpcsplus/api/npc/NpcEntry.java
Normal file
56
api/src/main/java/lol/pyr/znpcsplus/api/npc/NpcEntry.java
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package lol.pyr.znpcsplus.api.npc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all NPC entries
|
||||||
|
* An NPC entry is a wrapper around an NPC that contains additional information
|
||||||
|
*/
|
||||||
|
public interface NpcEntry {
|
||||||
|
/**
|
||||||
|
* Gets the ID of this NPC entry
|
||||||
|
* @return The ID of this NPC entry
|
||||||
|
*/
|
||||||
|
String getId();
|
||||||
|
/**
|
||||||
|
* Gets the NPC of this NPC entry
|
||||||
|
* @return The {@link Npc} of this NPC entry
|
||||||
|
*/
|
||||||
|
Npc getNpc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if this NPC entry is processed or not
|
||||||
|
* @return If this NPC entry is processed or not
|
||||||
|
*/
|
||||||
|
boolean isProcessed();
|
||||||
|
/**
|
||||||
|
* Sets if this NPC entry is processed or not
|
||||||
|
* @param value If this NPC entry is processed or not
|
||||||
|
*/
|
||||||
|
void setProcessed(boolean value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If this NPC entry SHOULD be saved into the storage or not
|
||||||
|
*/
|
||||||
|
boolean isSave();
|
||||||
|
/**
|
||||||
|
* Sets if this NPC should be saved or not
|
||||||
|
* @param value If this NPC entry should be saved or not
|
||||||
|
*/
|
||||||
|
void setSave(boolean value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if this NPC can be modified by commands
|
||||||
|
* @return {@code true} if this NPC can be modified by commands, {@code false} otherwise
|
||||||
|
*/
|
||||||
|
boolean isAllowCommandModification();
|
||||||
|
/**
|
||||||
|
* Sets if this NPC can be modified by commands
|
||||||
|
* @param value {@code true} if this NPC can be modified by commands, {@code false} otherwise
|
||||||
|
*/
|
||||||
|
void setAllowCommandModification(boolean value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables everything for this NPC entry
|
||||||
|
* That is, it makes the NPC processed, saveable, and allows command modification
|
||||||
|
*/
|
||||||
|
void enableEverything();
|
||||||
|
}
|
90
api/src/main/java/lol/pyr/znpcsplus/api/npc/NpcRegistry.java
Normal file
90
api/src/main/java/lol/pyr/znpcsplus/api/npc/NpcRegistry.java
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
package lol.pyr.znpcsplus.api.npc;
|
||||||
|
|
||||||
|
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all NPC registries
|
||||||
|
*/
|
||||||
|
public interface NpcRegistry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all NPC entries
|
||||||
|
* @return All NPC entries
|
||||||
|
*/
|
||||||
|
Collection<? extends NpcEntry> getAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all NPC IDs
|
||||||
|
* @return All NPC IDs
|
||||||
|
*/
|
||||||
|
Collection<String> getAllIds();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all NPC entries that are player made
|
||||||
|
* @return All player made NPC entries
|
||||||
|
*/
|
||||||
|
Collection<? extends NpcEntry> getAllPlayerMade();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets IDs of all player made NPCs
|
||||||
|
* @return IDs of all player made NPCs
|
||||||
|
*/
|
||||||
|
Collection<String> getAllPlayerMadeIds();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new NPC entry
|
||||||
|
* @param id The ID of the NPC entry
|
||||||
|
* @param world The {@link World} of the NPC entry
|
||||||
|
* @param type The {@link NpcType} of the NPC entry
|
||||||
|
* @param location The {@link NpcLocation} of the NPC entry
|
||||||
|
* @return The entry of the newly created npc
|
||||||
|
*/
|
||||||
|
NpcEntry create(String id, World world, NpcType type, NpcLocation location);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an NPC entry by its ID
|
||||||
|
* @param id The ID of the NPC entry
|
||||||
|
* @return The NPC entry
|
||||||
|
*/
|
||||||
|
NpcEntry getById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an NPC entry by its UUID
|
||||||
|
* @param uuid The UUID of the NPC entry
|
||||||
|
* @return The NPC entry
|
||||||
|
*/
|
||||||
|
NpcEntry getByUuid(UUID uuid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an NPC entry by its ID
|
||||||
|
* @param id The ID of the NPC entry
|
||||||
|
*/
|
||||||
|
void delete(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an NPC entry by its UUID
|
||||||
|
* @param uuid The UUID of the NPC entry
|
||||||
|
*/
|
||||||
|
void delete(UUID uuid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register an NPC to this registry
|
||||||
|
* NpcEntry instances can be obtained through the NpcSerializer classes
|
||||||
|
* @param entry The npc to be registered
|
||||||
|
*/
|
||||||
|
void register(NpcEntry entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reload all saveable npcs from storage
|
||||||
|
*/
|
||||||
|
void reload();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save all saveable npcs to storage
|
||||||
|
*/
|
||||||
|
void save();
|
||||||
|
}
|
29
api/src/main/java/lol/pyr/znpcsplus/api/npc/NpcType.java
Normal file
29
api/src/main/java/lol/pyr/znpcsplus/api/npc/NpcType.java
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package lol.pyr.znpcsplus.api.npc;
|
||||||
|
|
||||||
|
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a type of NPC.
|
||||||
|
* This defines the {@link org.bukkit.entity.EntityType} of the NPC, as well as the properties that are allowed to be set on the NPC.
|
||||||
|
*/
|
||||||
|
public interface NpcType {
|
||||||
|
/**
|
||||||
|
* The name of the NPC type.
|
||||||
|
* @return The name of the NPC type.
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The offset of the hologram above the NPC.
|
||||||
|
* @return the offset
|
||||||
|
*/
|
||||||
|
double getHologramOffset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of properties that are allowed to be set on the NPC.
|
||||||
|
* @return allowed properties
|
||||||
|
*/
|
||||||
|
Set<EntityProperty<?>> getAllowedProperties();
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package lol.pyr.znpcsplus.api.npc;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base for NpcType registries.
|
||||||
|
*/
|
||||||
|
public interface NpcTypeRegistry {
|
||||||
|
/**
|
||||||
|
* Gets a NPC type by name.
|
||||||
|
* @param name The name of the NPC type.
|
||||||
|
* @return The type that is represented by the name or null if it doesnt exist
|
||||||
|
*/
|
||||||
|
NpcType getByName(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all NPC types.
|
||||||
|
* @return all of the npc types
|
||||||
|
*/
|
||||||
|
Collection<NpcType> getAll();
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package lol.pyr.znpcsplus.api.serialization;
|
||||||
|
|
||||||
|
import lol.pyr.znpcsplus.api.npc.NpcEntry;
|
||||||
|
|
||||||
|
public interface NpcSerializer<T> {
|
||||||
|
/**
|
||||||
|
* Serialize an npc into the type of this serializer
|
||||||
|
* @param entry The npc entry
|
||||||
|
* @return The serialized class
|
||||||
|
*/
|
||||||
|
T serialize(NpcEntry entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize an npc from a serialized class
|
||||||
|
* Note: This npc will not be registered, you need to also register it using the NpcRegistry#register(NpcEntry) method
|
||||||
|
* @param model The serialized class
|
||||||
|
* @return The deserialized NpcEntry
|
||||||
|
*/
|
||||||
|
NpcEntry deserialize(T model);
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package lol.pyr.znpcsplus.api.serialization;
|
||||||
|
|
||||||
|
public interface NpcSerializerRegistry {
|
||||||
|
/**
|
||||||
|
* Get an NpcSerializer that serializes npcs into the provided class
|
||||||
|
* @param clazz The class to serialize into
|
||||||
|
* @return The npc serializer instance
|
||||||
|
* @param <T> The type of the class that the serializer serializes into
|
||||||
|
*/
|
||||||
|
<T> NpcSerializer<T> getSerializer(Class<T> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register an NpcSerializer to be used by other plugins
|
||||||
|
* @param clazz The class that the serializer serializes into
|
||||||
|
* @param serializer The serializer itself
|
||||||
|
* @param <T> The type of the class that the serializer serializes into
|
||||||
|
*/
|
||||||
|
<T> void registerSerializer(Class<T> clazz, NpcSerializer<T> serializer);
|
||||||
|
}
|
6
api/src/main/java/lol/pyr/znpcsplus/api/skin/Skin.java
Normal file
6
api/src/main/java/lol/pyr/znpcsplus/api/skin/Skin.java
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package lol.pyr.znpcsplus.api.skin;
|
||||||
|
|
||||||
|
public interface Skin {
|
||||||
|
String getTexture();
|
||||||
|
String getSignature();
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package lol.pyr.znpcsplus.api.skin;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
public interface SkinDescriptor {
|
||||||
|
CompletableFuture<? extends Skin> fetch(Player player);
|
||||||
|
Skin fetchInstant(Player player);
|
||||||
|
boolean supportsInstant(Player player);
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package lol.pyr.znpcsplus.api.skin;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory for creating skin descriptors.
|
||||||
|
*/
|
||||||
|
public interface SkinDescriptorFactory {
|
||||||
|
SkinDescriptor createMirrorDescriptor();
|
||||||
|
SkinDescriptor createRefreshingDescriptor(String playerName);
|
||||||
|
SkinDescriptor createRefreshingDescriptor(UUID playerUUID);
|
||||||
|
SkinDescriptor createStaticDescriptor(String playerName);
|
||||||
|
SkinDescriptor createStaticDescriptor(String texture, String signature);
|
||||||
|
SkinDescriptor createUrlDescriptor(String url, String variant);
|
||||||
|
SkinDescriptor createUrlDescriptor(URL url, String variant);
|
||||||
|
SkinDescriptor createFileDescriptor(String path);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum ArmadilloState {
|
||||||
|
IDLE,
|
||||||
|
ROLLING,
|
||||||
|
SCARED,
|
||||||
|
UNROLLING
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum AttachDirection {
|
||||||
|
DOWN,
|
||||||
|
UP,
|
||||||
|
NORTH,
|
||||||
|
SOUTH,
|
||||||
|
WEST,
|
||||||
|
EAST
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum AxolotlVariant {
|
||||||
|
LUCY,
|
||||||
|
WILD,
|
||||||
|
GOLD,
|
||||||
|
CYAN,
|
||||||
|
BLUE
|
||||||
|
}
|
14
api/src/main/java/lol/pyr/znpcsplus/util/BlockState.java
Normal file
14
api/src/main/java/lol/pyr/znpcsplus/util/BlockState.java
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public class BlockState {
|
||||||
|
private final int globalId;
|
||||||
|
|
||||||
|
public BlockState(int globalId) {
|
||||||
|
this.globalId = globalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGlobalId() {
|
||||||
|
return globalId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
api/src/main/java/lol/pyr/znpcsplus/util/CatVariant.java
Normal file
15
api/src/main/java/lol/pyr/znpcsplus/util/CatVariant.java
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum CatVariant {
|
||||||
|
TABBY,
|
||||||
|
BLACK,
|
||||||
|
RED,
|
||||||
|
SIAMESE,
|
||||||
|
BRITISH_SHORTHAIR,
|
||||||
|
CALICO,
|
||||||
|
PERSIAN,
|
||||||
|
RAGDOLL,
|
||||||
|
WHITE,
|
||||||
|
JELLIE,
|
||||||
|
ALL_BLACK
|
||||||
|
}
|
16
api/src/main/java/lol/pyr/znpcsplus/util/CreeperState.java
Normal file
16
api/src/main/java/lol/pyr/znpcsplus/util/CreeperState.java
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum CreeperState {
|
||||||
|
IDLE(-1),
|
||||||
|
FUSE(1);
|
||||||
|
|
||||||
|
private final int state;
|
||||||
|
|
||||||
|
CreeperState(int state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
6
api/src/main/java/lol/pyr/znpcsplus/util/FoxVariant.java
Normal file
6
api/src/main/java/lol/pyr/znpcsplus/util/FoxVariant.java
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum FoxVariant {
|
||||||
|
RED,
|
||||||
|
SNOW
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum FrogVariant {
|
||||||
|
TEMPERATE,
|
||||||
|
WARM,
|
||||||
|
COLD
|
||||||
|
}
|
8
api/src/main/java/lol/pyr/znpcsplus/util/HorseArmor.java
Normal file
8
api/src/main/java/lol/pyr/znpcsplus/util/HorseArmor.java
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum HorseArmor {
|
||||||
|
NONE,
|
||||||
|
IRON,
|
||||||
|
GOLD,
|
||||||
|
DIAMOND
|
||||||
|
}
|
11
api/src/main/java/lol/pyr/znpcsplus/util/HorseColor.java
Normal file
11
api/src/main/java/lol/pyr/znpcsplus/util/HorseColor.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum HorseColor {
|
||||||
|
WHITE,
|
||||||
|
CREAMY,
|
||||||
|
CHESTNUT,
|
||||||
|
BROWN,
|
||||||
|
BLACK,
|
||||||
|
GRAY,
|
||||||
|
DARK_BROWN
|
||||||
|
}
|
9
api/src/main/java/lol/pyr/znpcsplus/util/HorseStyle.java
Normal file
9
api/src/main/java/lol/pyr/znpcsplus/util/HorseStyle.java
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum HorseStyle {
|
||||||
|
NONE,
|
||||||
|
WHITE,
|
||||||
|
WHITEFIELD,
|
||||||
|
WHITE_DOTS,
|
||||||
|
BLACK_DOTS
|
||||||
|
}
|
9
api/src/main/java/lol/pyr/znpcsplus/util/HorseType.java
Normal file
9
api/src/main/java/lol/pyr/znpcsplus/util/HorseType.java
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum HorseType {
|
||||||
|
HORSE,
|
||||||
|
DONKEY,
|
||||||
|
MULE,
|
||||||
|
ZOMBIE,
|
||||||
|
SKELETON
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum LlamaVariant {
|
||||||
|
CREAMY,
|
||||||
|
WHITE,
|
||||||
|
BROWN,
|
||||||
|
GRAY
|
||||||
|
}
|
7
api/src/main/java/lol/pyr/znpcsplus/util/LookType.java
Normal file
7
api/src/main/java/lol/pyr/znpcsplus/util/LookType.java
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum LookType {
|
||||||
|
FIXED,
|
||||||
|
CLOSEST_PLAYER,
|
||||||
|
PER_PLAYER
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum MooshroomVariant {
|
||||||
|
RED,
|
||||||
|
BROWN;
|
||||||
|
|
||||||
|
public static String getVariantName(MooshroomVariant variant) {
|
||||||
|
return variant.name().toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
20
api/src/main/java/lol/pyr/znpcsplus/util/NamedColor.java
Normal file
20
api/src/main/java/lol/pyr/znpcsplus/util/NamedColor.java
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum NamedColor {
|
||||||
|
BLACK,
|
||||||
|
DARK_BLUE,
|
||||||
|
DARK_GREEN,
|
||||||
|
DARK_AQUA,
|
||||||
|
DARK_RED,
|
||||||
|
DARK_PURPLE,
|
||||||
|
GOLD,
|
||||||
|
GRAY,
|
||||||
|
DARK_GRAY,
|
||||||
|
BLUE,
|
||||||
|
GREEN,
|
||||||
|
AQUA,
|
||||||
|
RED,
|
||||||
|
LIGHT_PURPLE,
|
||||||
|
YELLOW,
|
||||||
|
WHITE
|
||||||
|
}
|
112
api/src/main/java/lol/pyr/znpcsplus/util/NpcLocation.java
Normal file
112
api/src/main/java/lol/pyr/znpcsplus/util/NpcLocation.java
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.util.NumberConversions;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class NpcLocation {
|
||||||
|
private final double x;
|
||||||
|
private final double y;
|
||||||
|
private final double z;
|
||||||
|
private final float yaw;
|
||||||
|
private final float pitch;
|
||||||
|
|
||||||
|
public NpcLocation(double x, double y, double z, float yaw, float pitch) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.yaw = yaw;
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NpcLocation(Location location) {
|
||||||
|
this(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX() {
|
||||||
|
return this.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBlockX() {
|
||||||
|
return (int) getX();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY() {
|
||||||
|
return this.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBlockY() {
|
||||||
|
return (int) getY();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getZ() {
|
||||||
|
return this.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBlockZ() {
|
||||||
|
return (int) getZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getYaw() {
|
||||||
|
return this.yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPitch() {
|
||||||
|
return this.pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NpcLocation centered() {
|
||||||
|
return new NpcLocation(Math.floor(x) + 0.5, y, Math.floor(z) + 0.5, yaw, pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location toBukkitLocation(World world) {
|
||||||
|
return new Location(world, this.x, this.y, this.z, this.yaw, this.pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NpcLocation withY(double y) {
|
||||||
|
return new NpcLocation(x, y, z, yaw, pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final double _2PI = 2 * Math.PI;
|
||||||
|
|
||||||
|
public NpcLocation lookingAt(Location loc) {
|
||||||
|
return lookingAt(new NpcLocation(loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
public NpcLocation lookingAt(NpcLocation loc) {
|
||||||
|
final double x = loc.getX() - this.x;
|
||||||
|
final double z = loc.getZ() - this.z;
|
||||||
|
final double y = loc.getY() - this.y;
|
||||||
|
|
||||||
|
if (x == 0 && z == 0) return new NpcLocation(this.x, this.y, this.z, this.yaw, y > 0 ? -90 : 90);
|
||||||
|
|
||||||
|
double x2 = NumberConversions.square(x);
|
||||||
|
double z2 = NumberConversions.square(z);
|
||||||
|
double xz = Math.sqrt(x2 + z2);
|
||||||
|
|
||||||
|
double theta = Math.atan2(-x, z);
|
||||||
|
float yaw = (float) Math.toDegrees((theta + _2PI) % _2PI);
|
||||||
|
float pitch = (float) Math.toDegrees(Math.atan(-y / xz));
|
||||||
|
|
||||||
|
return new NpcLocation(this.x, this.y, this.z, yaw, pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
NpcLocation that = (NpcLocation) o;
|
||||||
|
return Double.compare(that.x, x) == 0 &&
|
||||||
|
Double.compare(that.y, y) == 0 &&
|
||||||
|
Double.compare(that.z, z) == 0 &&
|
||||||
|
Float.compare(that.yaw, yaw) == 0 &&
|
||||||
|
Float.compare(that.pitch, pitch) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(x, y, z, yaw, pitch);
|
||||||
|
}
|
||||||
|
}
|
27
api/src/main/java/lol/pyr/znpcsplus/util/NpcPose.java
Normal file
27
api/src/main/java/lol/pyr/znpcsplus/util/NpcPose.java
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
// TODO: Seperate this out into multiple classes and multiple properties depending on the npc type
|
||||||
|
// TODO: For example USING_TONGUE is only for the frog type but its usable everywhere
|
||||||
|
|
||||||
|
// TODO #2: Add some backwards compatibility to some of these, like for example CROUCHING can be done
|
||||||
|
// TODO #2: on older versions using the general Entity number 0 bitmask
|
||||||
|
public enum NpcPose {
|
||||||
|
STANDING,
|
||||||
|
FALL_FLYING,
|
||||||
|
SLEEPING,
|
||||||
|
SWIMMING,
|
||||||
|
SPIN_ATTACK,
|
||||||
|
CROUCHING,
|
||||||
|
LONG_JUMPING,
|
||||||
|
DYING,
|
||||||
|
CROAKING,
|
||||||
|
USING_TONGUE,
|
||||||
|
SITTING,
|
||||||
|
ROARING,
|
||||||
|
SNIFFING,
|
||||||
|
EMERGING,
|
||||||
|
DIGGING,
|
||||||
|
SLIDING,
|
||||||
|
SHOOTING,
|
||||||
|
INHALING,
|
||||||
|
}
|
8
api/src/main/java/lol/pyr/znpcsplus/util/OcelotType.java
Normal file
8
api/src/main/java/lol/pyr/znpcsplus/util/OcelotType.java
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum OcelotType {
|
||||||
|
OCELOT,
|
||||||
|
TUXEDO,
|
||||||
|
TABBY,
|
||||||
|
SIAMESE,
|
||||||
|
}
|
11
api/src/main/java/lol/pyr/znpcsplus/util/PandaGene.java
Normal file
11
api/src/main/java/lol/pyr/znpcsplus/util/PandaGene.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum PandaGene {
|
||||||
|
NORMAL,
|
||||||
|
LAZY,
|
||||||
|
WORRIED,
|
||||||
|
PLAYFUL,
|
||||||
|
BROWN,
|
||||||
|
WEAK,
|
||||||
|
AGGRESSIVE
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum ParrotVariant {
|
||||||
|
RED_BLUE,
|
||||||
|
BLUE,
|
||||||
|
GREEN,
|
||||||
|
YELLOW_BLUE,
|
||||||
|
GRAY
|
||||||
|
}
|
7
api/src/main/java/lol/pyr/znpcsplus/util/PuffState.java
Normal file
7
api/src/main/java/lol/pyr/znpcsplus/util/PuffState.java
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum PuffState {
|
||||||
|
DEFLATED,
|
||||||
|
HALF_INFLATED,
|
||||||
|
FULLY_INFLATED,
|
||||||
|
}
|
22
api/src/main/java/lol/pyr/znpcsplus/util/RabbitType.java
Normal file
22
api/src/main/java/lol/pyr/znpcsplus/util/RabbitType.java
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum RabbitType {
|
||||||
|
BROWN(0),
|
||||||
|
WHITE(1),
|
||||||
|
BLACK(2),
|
||||||
|
BLACK_AND_WHITE(3),
|
||||||
|
GOLD(4),
|
||||||
|
SALT_AND_PEPPER(5),
|
||||||
|
THE_KILLER_BUNNY(99),
|
||||||
|
TOAST(100);
|
||||||
|
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
RabbitType(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
11
api/src/main/java/lol/pyr/znpcsplus/util/SkeletonType.java
Normal file
11
api/src/main/java/lol/pyr/znpcsplus/util/SkeletonType.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum SkeletonType {
|
||||||
|
NORMAL,
|
||||||
|
WITHER,
|
||||||
|
STRAY;
|
||||||
|
|
||||||
|
public byte getLegacyId() {
|
||||||
|
return (byte) ordinal();
|
||||||
|
}
|
||||||
|
}
|
11
api/src/main/java/lol/pyr/znpcsplus/util/SnifferState.java
Normal file
11
api/src/main/java/lol/pyr/znpcsplus/util/SnifferState.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum SnifferState {
|
||||||
|
IDLING,
|
||||||
|
FEELING_HAPPY,
|
||||||
|
SCENTING,
|
||||||
|
SNIFFING,
|
||||||
|
SEARCHING,
|
||||||
|
DIGGING,
|
||||||
|
RISING
|
||||||
|
}
|
10
api/src/main/java/lol/pyr/znpcsplus/util/SpellType.java
Normal file
10
api/src/main/java/lol/pyr/znpcsplus/util/SpellType.java
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum SpellType {
|
||||||
|
NONE,
|
||||||
|
SUMMON_VEX,
|
||||||
|
ATTACK,
|
||||||
|
WOLOLO,
|
||||||
|
DISAPPEAR,
|
||||||
|
BLINDNESS,
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
import org.bukkit.DyeColor;
|
||||||
|
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
|
public class TropicalFishVariant {
|
||||||
|
|
||||||
|
private final TropicalFishPattern pattern;
|
||||||
|
private final DyeColor bodyColor;
|
||||||
|
private final DyeColor patternColor;
|
||||||
|
|
||||||
|
public TropicalFishVariant(TropicalFishPattern pattern, DyeColor bodyColor, DyeColor patternColor) {
|
||||||
|
this.pattern = pattern;
|
||||||
|
this.bodyColor = bodyColor;
|
||||||
|
this.patternColor = patternColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getVariant() {
|
||||||
|
return pattern.getId() & '\uffff' | (bodyColor.ordinal() & 255) << 16 | (patternColor.ordinal() & 255) << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TropicalFishPattern {
|
||||||
|
KOB(0, 0),
|
||||||
|
SUNSTREAK(0, 1),
|
||||||
|
SNOOPER(0, 2),
|
||||||
|
DASHER(0, 3),
|
||||||
|
BRINELY(0, 4),
|
||||||
|
SPOTTY(0, 5),
|
||||||
|
FLOPPER(1, 0),
|
||||||
|
STRIPEY(1, 1),
|
||||||
|
GLITTER(1, 2),
|
||||||
|
BLOCKFISH(1, 3),
|
||||||
|
BETTY(1, 4),
|
||||||
|
CLAYFISH(1, 5);
|
||||||
|
|
||||||
|
private final int size;
|
||||||
|
private final int id;
|
||||||
|
private static final IntFunction<TropicalFishPattern> BY_ID = (id) -> {
|
||||||
|
for (TropicalFishPattern pattern : values()) {
|
||||||
|
if (pattern.id == id) {
|
||||||
|
return pattern;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
TropicalFishPattern(int size, int pattern) {
|
||||||
|
this.size = size;
|
||||||
|
this.id = size | pattern << 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TropicalFishPattern fromVariant(int variant) {
|
||||||
|
return BY_ID.apply(variant & '\uffff');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private TropicalFishPattern pattern;
|
||||||
|
private DyeColor bodyColor;
|
||||||
|
private DyeColor patternColor;
|
||||||
|
|
||||||
|
public Builder() {
|
||||||
|
this.pattern = TropicalFishPattern.KOB;
|
||||||
|
this.bodyColor = DyeColor.WHITE;
|
||||||
|
this.patternColor = DyeColor.WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder pattern(TropicalFishPattern pattern) {
|
||||||
|
this.pattern = pattern;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder bodyColor(DyeColor bodyColor) {
|
||||||
|
this.bodyColor = bodyColor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder patternColor(DyeColor patternColor) {
|
||||||
|
this.patternColor = patternColor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder fromInt(int variant) {
|
||||||
|
Builder builder = new Builder();
|
||||||
|
builder.pattern = TropicalFishPattern.fromVariant(variant);
|
||||||
|
builder.bodyColor = DyeColor.values()[(variant >> 16) & 0xFF];
|
||||||
|
builder.patternColor = DyeColor.values()[(variant >> 24) & 0xFF];
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TropicalFishVariant build() {
|
||||||
|
return new TropicalFishVariant(pattern, bodyColor, patternColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
api/src/main/java/lol/pyr/znpcsplus/util/Vector3f.java
Normal file
46
api/src/main/java/lol/pyr/znpcsplus/util/Vector3f.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public class Vector3f {
|
||||||
|
private final float x;
|
||||||
|
private final float y;
|
||||||
|
private final float z;
|
||||||
|
|
||||||
|
public Vector3f() {
|
||||||
|
this.x = 0.0F;
|
||||||
|
this.y = 0.0F;
|
||||||
|
this.z = 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3f(float x, float y, float z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3f(String s) {
|
||||||
|
String[] split = s.split(",");
|
||||||
|
this.x = Float.parseFloat(split[0]);
|
||||||
|
this.y = Float.parseFloat(split[1]);
|
||||||
|
this.z = Float.parseFloat(split[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getX() {
|
||||||
|
return this.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getY() {
|
||||||
|
return this.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getZ() {
|
||||||
|
return this.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return this.x + "," + this.y + "," + this.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3f zero() {
|
||||||
|
return new Vector3f();
|
||||||
|
}
|
||||||
|
}
|
46
api/src/main/java/lol/pyr/znpcsplus/util/Vector3i.java
Normal file
46
api/src/main/java/lol/pyr/znpcsplus/util/Vector3i.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public class Vector3i {
|
||||||
|
private final int x;
|
||||||
|
private final int y;
|
||||||
|
private final int z;
|
||||||
|
|
||||||
|
public Vector3i(int x, int y, int z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX() {
|
||||||
|
return this.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getY() {
|
||||||
|
return this.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getZ() {
|
||||||
|
return this.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return this.x + "," + this.y + "," + this.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toPrettyString() {
|
||||||
|
return "(" + this.x + ", " + this.y + ", " + this.z + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3i fromString(String s) {
|
||||||
|
String[] split = s.split(",");
|
||||||
|
if (split.length < 3) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return new Vector3i(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2]));
|
||||||
|
} catch (NumberFormatException var3) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum VillagerLevel {
|
||||||
|
STONE,
|
||||||
|
IRON,
|
||||||
|
GOLD,
|
||||||
|
EMERALD,
|
||||||
|
DIAMOND
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum VillagerProfession {
|
||||||
|
NONE(0, 0),
|
||||||
|
ARMORER(1, 3),
|
||||||
|
BUTCHER(2, 4),
|
||||||
|
CARTOGRAPHER(3, 1),
|
||||||
|
CLERIC(4, 2),
|
||||||
|
FARMER(5, 0),
|
||||||
|
FISHERMAN(6, 0),
|
||||||
|
FLETCHER(7, 0),
|
||||||
|
LEATHER_WORKER(8, 4),
|
||||||
|
LIBRARIAN(9, 1),
|
||||||
|
MASON(10),
|
||||||
|
NITWIT(11, 5),
|
||||||
|
SHEPHERD(12, 0),
|
||||||
|
TOOL_SMITH(13, 3),
|
||||||
|
WEAPON_SMITH(14, 3);
|
||||||
|
|
||||||
|
private final int id;
|
||||||
|
private final int legacyId;
|
||||||
|
|
||||||
|
VillagerProfession(int id) {
|
||||||
|
this.id = id;
|
||||||
|
this.legacyId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VillagerProfession(int id, int legacyId) {
|
||||||
|
this.id = id;
|
||||||
|
this.legacyId = legacyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLegacyId() {
|
||||||
|
return legacyId;
|
||||||
|
}
|
||||||
|
}
|
20
api/src/main/java/lol/pyr/znpcsplus/util/VillagerType.java
Normal file
20
api/src/main/java/lol/pyr/znpcsplus/util/VillagerType.java
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum VillagerType {
|
||||||
|
DESERT(0),
|
||||||
|
JUNGLE(1),
|
||||||
|
PLAINS(2),
|
||||||
|
SAVANNA(3),
|
||||||
|
SNOW(4),
|
||||||
|
SWAMP(5),
|
||||||
|
TAIGA(6);
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
VillagerType(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
23
api/src/main/java/lol/pyr/znpcsplus/util/WoldVariant.java
Normal file
23
api/src/main/java/lol/pyr/znpcsplus/util/WoldVariant.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum WoldVariant {
|
||||||
|
PALE(3),
|
||||||
|
SPOTTED(6),
|
||||||
|
SNOWY(5),
|
||||||
|
BLACK(1),
|
||||||
|
ASHEN(0),
|
||||||
|
RUSTY(4),
|
||||||
|
WOODS(8),
|
||||||
|
CHESTNUT(2),
|
||||||
|
STRIPED(7);
|
||||||
|
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
WoldVariant(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
11
api/src/main/java/lol/pyr/znpcsplus/util/ZombieType.java
Normal file
11
api/src/main/java/lol/pyr/znpcsplus/util/ZombieType.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
|
public enum ZombieType {
|
||||||
|
ZOMBIE,
|
||||||
|
FARMER,
|
||||||
|
LIBRARIAN,
|
||||||
|
PRIEST,
|
||||||
|
BLACKSMITH,
|
||||||
|
BUTCHER,
|
||||||
|
HUSK
|
||||||
|
}
|
37
build.gradle
Normal file
37
build.gradle
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
subprojects {
|
||||||
|
apply plugin: "java"
|
||||||
|
|
||||||
|
group "lol.pyr"
|
||||||
|
version "2.1.0" + (System.getenv().containsKey("BUILD_ID") ? "-SNAPSHOT" : "")
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain.languageVersion.set(JavaLanguageVersion.of(8))
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly "org.jetbrains:annotations:26.0.1"
|
||||||
|
compileOnly "org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT"
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
url "https://hub.spigotmc.org/nexus/content/repositories/snapshots/"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url "https://repo.codemc.io/repository/maven-releases/"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url "https://libraries.minecraft.net"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url "https://repo.papermc.io/repository/maven-public/"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url "https://repo.extendedclip.com/content/repositories/placeholderapi/"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url "https://repo.pyr.lol/releases"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
234
gradlew
vendored
Executable file
234
gradlew
vendored
Executable file
|
@ -0,0 +1,234 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
89
gradlew.bat
vendored
Normal file
89
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
71
plugin/build.gradle
Normal file
71
plugin/build.gradle
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
plugins {
|
||||||
|
id "java"
|
||||||
|
id "com.github.johnrengelman.shadow" version "8.1.1"
|
||||||
|
id "xyz.jpenilla.run-paper" version "2.2.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
runServer {
|
||||||
|
javaLauncher = javaToolchains.launcherFor {
|
||||||
|
languageVersion = JavaLanguageVersion.of(21)
|
||||||
|
}
|
||||||
|
minecraftVersion "1.21.4"
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
expand("version": version)
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly "me.clip:placeholderapi:2.11.6" // Placeholder support
|
||||||
|
implementation "com.google.code.gson:gson:2.10.1" // JSON parsing
|
||||||
|
implementation "org.bstats:bstats-bukkit:3.0.2" // Plugin stats
|
||||||
|
implementation "com.github.retrooper:packetevents-spigot:2.9.1" // Packets
|
||||||
|
implementation "space.arim.dazzleconf:dazzleconf-ext-snakeyaml:1.2.1" // Configs
|
||||||
|
implementation "lol.pyr:director-adventure:2.1.2" // Commands
|
||||||
|
|
||||||
|
// Fancy text library
|
||||||
|
implementation "net.kyori:adventure-platform-bukkit:4.3.4"
|
||||||
|
implementation "net.kyori:adventure-text-minimessage:4.17.0"
|
||||||
|
|
||||||
|
implementation project(":api")
|
||||||
|
}
|
||||||
|
|
||||||
|
ext {
|
||||||
|
gitBranch = System.getenv('GIT_BRANCH') ?: ''
|
||||||
|
gitCommitHash = System.getenv('GIT_COMMIT') ?: ''
|
||||||
|
buildId = System.getenv('BUILD_ID') ?: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJar {
|
||||||
|
archivesBaseName = "ZNPCsPlus"
|
||||||
|
archiveClassifier.set ""
|
||||||
|
|
||||||
|
manifest {
|
||||||
|
if (gitBranch?.trim()) {
|
||||||
|
attributes('Git-Branch': gitBranch)
|
||||||
|
}
|
||||||
|
if (gitCommitHash?.trim()) {
|
||||||
|
attributes('Git-Commit': gitCommitHash)
|
||||||
|
}
|
||||||
|
if (buildId?.trim()) {
|
||||||
|
attributes('Build-Id': buildId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relocate "org.objectweb.asm", "lol.pyr.znpcsplus.libraries.asm"
|
||||||
|
relocate "me.lucko.jarrelocator", "lol.pyr.znpcsplus.libraries.jarrelocator"
|
||||||
|
|
||||||
|
relocate "org.bstats", "lol.pyr.znpcsplus.libraries.bstats"
|
||||||
|
relocate "net.kyori", "lol.pyr.znpcsplus.libraries.kyori"
|
||||||
|
relocate "org.checkerframework", "lol.pyr.znpcsplus.libraries.checkerframework"
|
||||||
|
relocate "com.google.gson", "lol.pyr.znpcsplus.libraries.gson"
|
||||||
|
relocate "com.github.retrooper.packetevents", "lol.pyr.znpcsplus.libraries.packetevents.api"
|
||||||
|
relocate "io.github.retrooper.packetevents", "lol.pyr.znpcsplus.libraries.packetevents.impl"
|
||||||
|
relocate "org.yaml.snakeyaml", "lol.pyr.znpcsplus.libraries.snakeyaml"
|
||||||
|
relocate "space.arim.dazzleconf", "lol.pyr.znpcsplus.libraries.dazzleconf"
|
||||||
|
relocate "lol.pyr.director", "lol.pyr.znpcsplus.libraries.command"
|
||||||
|
|
||||||
|
minimize()
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.assemble.dependsOn shadowJar
|
361
plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java
Normal file
361
plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java
Normal file
|
@ -0,0 +1,361 @@
|
||||||
|
package lol.pyr.znpcsplus;
|
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.PacketEvents;
|
||||||
|
import com.github.retrooper.packetevents.PacketEventsAPI;
|
||||||
|
import com.github.retrooper.packetevents.event.PacketListenerPriority;
|
||||||
|
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||||
|
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandManager;
|
||||||
|
import lol.pyr.director.adventure.command.MultiCommand;
|
||||||
|
import lol.pyr.director.adventure.parse.primitive.BooleanParser;
|
||||||
|
import lol.pyr.director.adventure.parse.primitive.DoubleParser;
|
||||||
|
import lol.pyr.director.adventure.parse.primitive.FloatParser;
|
||||||
|
import lol.pyr.director.adventure.parse.primitive.IntegerParser;
|
||||||
|
import lol.pyr.director.common.message.Message;
|
||||||
|
import lol.pyr.znpcsplus.api.NpcApiProvider;
|
||||||
|
import lol.pyr.znpcsplus.api.NpcPropertyRegistryProvider;
|
||||||
|
import lol.pyr.znpcsplus.api.interaction.InteractionType;
|
||||||
|
import lol.pyr.znpcsplus.commands.*;
|
||||||
|
import lol.pyr.znpcsplus.commands.action.*;
|
||||||
|
import lol.pyr.znpcsplus.commands.hologram.*;
|
||||||
|
import lol.pyr.znpcsplus.commands.property.PropertyRemoveCommand;
|
||||||
|
import lol.pyr.znpcsplus.commands.property.PropertySetCommand;
|
||||||
|
import lol.pyr.znpcsplus.commands.storage.ImportCommand;
|
||||||
|
import lol.pyr.znpcsplus.commands.storage.LoadAllCommand;
|
||||||
|
import lol.pyr.znpcsplus.commands.storage.MigrateCommand;
|
||||||
|
import lol.pyr.znpcsplus.commands.storage.SaveAllCommand;
|
||||||
|
import lol.pyr.znpcsplus.config.ConfigManager;
|
||||||
|
import lol.pyr.znpcsplus.conversion.DataImporterRegistry;
|
||||||
|
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||||
|
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.interaction.ActionFactoryImpl;
|
||||||
|
import lol.pyr.znpcsplus.interaction.ActionRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.interaction.InteractionPacketListener;
|
||||||
|
import lol.pyr.znpcsplus.npc.*;
|
||||||
|
import lol.pyr.znpcsplus.packets.*;
|
||||||
|
import lol.pyr.znpcsplus.parsers.*;
|
||||||
|
import lol.pyr.znpcsplus.scheduling.FoliaScheduler;
|
||||||
|
import lol.pyr.znpcsplus.scheduling.SpigotScheduler;
|
||||||
|
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||||
|
import lol.pyr.znpcsplus.serialization.NpcSerializerRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
|
||||||
|
import lol.pyr.znpcsplus.skin.cache.SkinCacheCleanTask;
|
||||||
|
import lol.pyr.znpcsplus.storage.NpcStorageType;
|
||||||
|
import lol.pyr.znpcsplus.tasks.HologramRefreshTask;
|
||||||
|
import lol.pyr.znpcsplus.tasks.NpcProcessorTask;
|
||||||
|
import lol.pyr.znpcsplus.tasks.ViewableHideOnLeaveListener;
|
||||||
|
import lol.pyr.znpcsplus.updater.UpdateChecker;
|
||||||
|
import lol.pyr.znpcsplus.updater.UpdateNotificationListener;
|
||||||
|
import lol.pyr.znpcsplus.user.ClientPacketListener;
|
||||||
|
import lol.pyr.znpcsplus.user.UserListener;
|
||||||
|
import lol.pyr.znpcsplus.user.UserManager;
|
||||||
|
import lol.pyr.znpcsplus.util.*;
|
||||||
|
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
import org.bstats.bukkit.Metrics;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.plugin.PluginDescriptionFile;
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ZNpcsPlus {
|
||||||
|
private final LegacyComponentSerializer textSerializer = LegacyComponentSerializer.builder()
|
||||||
|
.character('&')
|
||||||
|
.hexCharacter('#')
|
||||||
|
.hexColors().build();
|
||||||
|
|
||||||
|
private final List<Runnable> shutdownTasks = new ArrayList<>();
|
||||||
|
private final PacketEventsAPI<Plugin> packetEvents;
|
||||||
|
private final ZNpcsPlusBootstrap bootstrap;
|
||||||
|
|
||||||
|
private final ConfigManager configManager;
|
||||||
|
private final MojangSkinCache skinCache;
|
||||||
|
private final EntityPropertyRegistryImpl propertyRegistry;
|
||||||
|
|
||||||
|
public ZNpcsPlus(ZNpcsPlusBootstrap bootstrap) {
|
||||||
|
this.bootstrap = bootstrap;
|
||||||
|
packetEvents = SpigotPacketEventsBuilder.build(bootstrap);
|
||||||
|
PacketEvents.setAPI(packetEvents);
|
||||||
|
packetEvents.getSettings().checkForUpdates(false);
|
||||||
|
packetEvents.load();
|
||||||
|
|
||||||
|
configManager = new ConfigManager(getDataFolder());
|
||||||
|
skinCache = new MojangSkinCache(configManager, new File(getDataFolder(), "skins"));
|
||||||
|
propertyRegistry = new EntityPropertyRegistryImpl(skinCache, configManager);
|
||||||
|
|
||||||
|
NpcPropertyRegistryProvider.register(bootstrap, propertyRegistry);
|
||||||
|
shutdownTasks.add(NpcPropertyRegistryProvider::unregister);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void log(String str) {
|
||||||
|
Bukkit.getConsoleSender().sendMessage(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onEnable() {
|
||||||
|
getDataFolder().mkdirs();
|
||||||
|
|
||||||
|
log(ChatColor.YELLOW + " ___ __ __ __");
|
||||||
|
log(ChatColor.YELLOW + " _/ |\\ | |__) | (__` " + ChatColor.GOLD + "__|__ " + ChatColor.YELLOW + getDescription().getName() + " " + ChatColor.GOLD + "v" + getDescription().getVersion());
|
||||||
|
log(ChatColor.YELLOW + " /__ | \\| | |__ .__) " + ChatColor.GOLD + " | " + ChatColor.GRAY + "Maintained with " + ChatColor.RED + "\u2764 " + ChatColor.GRAY + " by Pyr#6969");
|
||||||
|
log("");
|
||||||
|
|
||||||
|
PluginManager pluginManager = Bukkit.getPluginManager();
|
||||||
|
long before = System.currentTimeMillis();
|
||||||
|
|
||||||
|
log(ChatColor.WHITE + " * Initializing libraries...");
|
||||||
|
|
||||||
|
packetEvents.init();
|
||||||
|
|
||||||
|
BukkitAudiences adventure = BukkitAudiences.create(bootstrap);
|
||||||
|
shutdownTasks.add(adventure::close);
|
||||||
|
|
||||||
|
log(ChatColor.WHITE + " * Initializing components...");
|
||||||
|
|
||||||
|
TaskScheduler scheduler = FoliaUtil.isFolia() ? new FoliaScheduler(bootstrap) : new SpigotScheduler(bootstrap);
|
||||||
|
shutdownTasks.add(scheduler::cancelAll);
|
||||||
|
|
||||||
|
|
||||||
|
PacketFactory packetFactory = setupPacketFactory(scheduler, propertyRegistry, configManager);
|
||||||
|
propertyRegistry.registerTypes(packetFactory, textSerializer, scheduler);
|
||||||
|
|
||||||
|
BungeeConnector bungeeConnector = new BungeeConnector(bootstrap);
|
||||||
|
ActionRegistryImpl actionRegistry = new ActionRegistryImpl();
|
||||||
|
ActionFactoryImpl actionFactory = new ActionFactoryImpl(scheduler, adventure, textSerializer, bungeeConnector);
|
||||||
|
NpcTypeRegistryImpl typeRegistry = new NpcTypeRegistryImpl();
|
||||||
|
NpcSerializerRegistryImpl serializerRegistry = new NpcSerializerRegistryImpl(packetFactory, configManager, actionRegistry, typeRegistry, propertyRegistry, textSerializer);
|
||||||
|
NpcRegistryImpl npcRegistry = new NpcRegistryImpl(configManager, this, packetFactory, actionRegistry,
|
||||||
|
scheduler, typeRegistry, propertyRegistry, serializerRegistry, textSerializer);
|
||||||
|
shutdownTasks.add(npcRegistry::unload);
|
||||||
|
|
||||||
|
UserManager userManager = new UserManager();
|
||||||
|
shutdownTasks.add(userManager::shutdown);
|
||||||
|
|
||||||
|
DataImporterRegistry importerRegistry = new DataImporterRegistry(configManager, adventure,
|
||||||
|
scheduler, packetFactory, textSerializer, typeRegistry, getDataFolder().getParentFile(),
|
||||||
|
propertyRegistry, skinCache, npcRegistry, bungeeConnector);
|
||||||
|
|
||||||
|
log(ChatColor.WHITE + " * Registering components...");
|
||||||
|
|
||||||
|
bungeeConnector.registerChannel();
|
||||||
|
shutdownTasks.add(bungeeConnector::unregisterChannel);
|
||||||
|
|
||||||
|
typeRegistry.registerDefault(packetEvents, propertyRegistry);
|
||||||
|
actionRegistry.registerTypes(scheduler, adventure, textSerializer, bungeeConnector);
|
||||||
|
packetEvents.getEventManager().registerListener(new InteractionPacketListener(userManager, npcRegistry, typeRegistry, scheduler), PacketListenerPriority.MONITOR);
|
||||||
|
packetEvents.getEventManager().registerListener(new ClientPacketListener(configManager), PacketListenerPriority.LOWEST);
|
||||||
|
new Metrics(bootstrap, 18244);
|
||||||
|
pluginManager.registerEvents(new UserListener(userManager), bootstrap);
|
||||||
|
|
||||||
|
registerCommands(npcRegistry, skinCache, adventure, actionRegistry,
|
||||||
|
typeRegistry, propertyRegistry, importerRegistry, configManager, packetFactory, serializerRegistry);
|
||||||
|
|
||||||
|
log(ChatColor.WHITE + " * Starting tasks...");
|
||||||
|
if (configManager.getConfig().checkForUpdates()) {
|
||||||
|
UpdateChecker updateChecker = new UpdateChecker(getDescription());
|
||||||
|
scheduler.runDelayedTimerAsync(updateChecker, 5L, 6000L);
|
||||||
|
pluginManager.registerEvents(new UpdateNotificationListener(this, adventure, updateChecker, scheduler), bootstrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduler.runDelayedTimerAsync(new NpcProcessorTask(npcRegistry, propertyRegistry, userManager), 60L, 3L);
|
||||||
|
scheduler.runDelayedTimerAsync(new HologramRefreshTask(npcRegistry), 60L, 20L);
|
||||||
|
scheduler.runDelayedTimerAsync(new SkinCacheCleanTask(skinCache), 1200, 1200);
|
||||||
|
pluginManager.registerEvents(new ViewableHideOnLeaveListener(), bootstrap);
|
||||||
|
|
||||||
|
log(ChatColor.WHITE + " * Loading data...");
|
||||||
|
npcRegistry.reload();
|
||||||
|
if (configManager.getConfig().autoSaveEnabled()) shutdownTasks.add(npcRegistry::save);
|
||||||
|
|
||||||
|
if (bootstrap.movedLegacy()) {
|
||||||
|
log(ChatColor.WHITE + " * Converting legacy data...");
|
||||||
|
try {
|
||||||
|
Collection<NpcEntryImpl> entries = importerRegistry.getImporter("znpcsplus_legacy").importData();
|
||||||
|
npcRegistry.registerAll(entries);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
log(ChatColor.RED + " * Legacy data conversion failed! Check conversion.log for more info.");
|
||||||
|
try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(new File(getDataFolder(), "conversion.log").toPath(), StandardOpenOption.CREATE_NEW))) {
|
||||||
|
exception.printStackTrace(writer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log(ChatColor.DARK_RED + " * Critical error! Writing to conversion.log failed.");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NpcApiProvider.register(bootstrap, new ZNpcsPlusApi(npcRegistry, typeRegistry, propertyRegistry, actionRegistry, actionFactory, skinCache, serializerRegistry));
|
||||||
|
log(ChatColor.WHITE + " * Loading complete! (" + (System.currentTimeMillis() - before) + "ms)");
|
||||||
|
log("");
|
||||||
|
|
||||||
|
if (configManager.getConfig().debugEnabled()) {
|
||||||
|
World world = Bukkit.getWorld("world");
|
||||||
|
if (world == null) world = Bukkit.getWorlds().get(0);
|
||||||
|
int i = 0;
|
||||||
|
for (NpcTypeImpl type : typeRegistry.getAllImpl()) {
|
||||||
|
NpcEntryImpl entry = npcRegistry.create("debug_npc_" + i, world, type, new NpcLocation(i * 3, 200, 0, 0, 0));
|
||||||
|
entry.setProcessed(true);
|
||||||
|
NpcImpl npc = entry.getNpc();
|
||||||
|
npc.getHologram().addTextLineComponent(Component.text("Hello, World!", TextColor.color(255, 0, 0)));
|
||||||
|
npc.getHologram().addTextLineComponent(Component.text("Hello, World!", TextColor.color(0, 255, 0)));
|
||||||
|
npc.getHologram().addTextLineComponent(Component.text("Hello, World!", TextColor.color(0, 0, 255)));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDisable() {
|
||||||
|
NpcApiProvider.unregister();
|
||||||
|
for (Runnable runnable : shutdownTasks) try {
|
||||||
|
runnable.run();
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
bootstrap.getLogger().severe("One of the registered shutdown tasks threw an exception:");
|
||||||
|
throwable.printStackTrace();
|
||||||
|
}
|
||||||
|
shutdownTasks.clear();
|
||||||
|
PacketEvents.getAPI().terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PacketFactory setupPacketFactory(TaskScheduler scheduler, EntityPropertyRegistryImpl propertyRegistry, ConfigManager configManager) {
|
||||||
|
HashMap<ServerVersion, LazyLoader<? extends PacketFactory>> versions = new HashMap<>();
|
||||||
|
versions.put(ServerVersion.V_1_8, LazyLoader.of(() -> new V1_8PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer, configManager)));
|
||||||
|
versions.put(ServerVersion.V_1_17, LazyLoader.of(() -> new V1_17PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer, configManager)));
|
||||||
|
versions.put(ServerVersion.V_1_19_3, LazyLoader.of(() -> new V1_19_3PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer, configManager)));
|
||||||
|
versions.put(ServerVersion.V_1_20_2, LazyLoader.of(() -> new V1_20_2PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer, configManager)));
|
||||||
|
versions.put(ServerVersion.V_1_21_3, LazyLoader.of(() -> new V1_21_3PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer, configManager)));
|
||||||
|
versions.put(ServerVersion.V_1_21_7, LazyLoader.of(() -> new V1_21_7PacketFactory(scheduler, packetEvents, propertyRegistry, textSerializer, configManager)));
|
||||||
|
|
||||||
|
ServerVersion version = packetEvents.getServerManager().getVersion();
|
||||||
|
if (versions.containsKey(version)) return versions.get(version).get();
|
||||||
|
for (ServerVersion v : ServerVersion.reversedValues()) {
|
||||||
|
if (v.isNewerThan(version)) continue;
|
||||||
|
if (!versions.containsKey(v)) continue;
|
||||||
|
return versions.get(v).get();
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Unsupported version!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerCommands(NpcRegistryImpl npcRegistry, MojangSkinCache skinCache, BukkitAudiences adventure,
|
||||||
|
ActionRegistryImpl actionRegistry, NpcTypeRegistryImpl typeRegistry,
|
||||||
|
EntityPropertyRegistryImpl propertyRegistry, DataImporterRegistry importerRegistry,
|
||||||
|
ConfigManager configManager, PacketFactory packetFactory, NpcSerializerRegistryImpl serializerRegistry) {
|
||||||
|
|
||||||
|
Message<CommandContext> incorrectUsageMessage = context -> context.send(Component.text("Incorrect usage: /" + context.getUsage(), NamedTextColor.RED));
|
||||||
|
CommandManager manager = new CommandManager(bootstrap, adventure, incorrectUsageMessage);
|
||||||
|
|
||||||
|
manager.registerParser(NpcTypeImpl.class, new NpcTypeParser(incorrectUsageMessage, typeRegistry));
|
||||||
|
manager.registerParser(NpcEntryImpl.class, new NpcEntryParser(npcRegistry, incorrectUsageMessage));
|
||||||
|
manager.registerParser(EntityPropertyImpl.class, new EntityPropertyParser(incorrectUsageMessage, propertyRegistry));
|
||||||
|
manager.registerParser(Integer.class, new IntegerParser(incorrectUsageMessage));
|
||||||
|
manager.registerParser(Double.class, new DoubleParser(incorrectUsageMessage));
|
||||||
|
manager.registerParser(Float.class, new FloatParser(incorrectUsageMessage));
|
||||||
|
manager.registerParser(Boolean.class, new BooleanParser(incorrectUsageMessage));
|
||||||
|
manager.registerParser(NamedColor.class, new NamedColorParser(incorrectUsageMessage));
|
||||||
|
manager.registerParser(InteractionType.class, new InteractionTypeParser(incorrectUsageMessage));
|
||||||
|
manager.registerParser(Color.class, new ColorParser(incorrectUsageMessage));
|
||||||
|
manager.registerParser(Vector3f.class, new Vector3fParser(incorrectUsageMessage));
|
||||||
|
manager.registerParser(String.class, new StringParser(incorrectUsageMessage));
|
||||||
|
manager.registerParser(Vector3i.class, new Vector3iParser(incorrectUsageMessage));
|
||||||
|
|
||||||
|
// TODO: Need to find a better way to do this
|
||||||
|
registerEnumParser(manager, NpcPose.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, DyeColor.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, CatVariant.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, CreeperState.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, ParrotVariant.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, SpellType.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, FoxVariant.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, FrogVariant.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, VillagerType.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, VillagerProfession.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, VillagerLevel.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, AxolotlVariant.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, HorseType.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, HorseStyle.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, HorseColor.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, HorseArmor.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, LlamaVariant.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, MooshroomVariant.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, OcelotType.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, PandaGene.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, PuffState.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, LookType.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, TropicalFishVariant.TropicalFishPattern.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, SnifferState.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, RabbitType.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, AttachDirection.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, Sound.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, ArmadilloState.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, WoldVariant.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, NpcStorageType.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, SkeletonType.class, incorrectUsageMessage);
|
||||||
|
|
||||||
|
manager.registerCommand("npc", new MultiCommand(bootstrap.loadHelpMessage("root"))
|
||||||
|
.addSubcommand("center", new CenterCommand(npcRegistry))
|
||||||
|
.addSubcommand("create", new CreateCommand(npcRegistry, typeRegistry))
|
||||||
|
.addSubcommand("clone", new CloneCommand(npcRegistry))
|
||||||
|
.addSubcommand("reloadconfig", new ReloadConfigCommand(configManager))
|
||||||
|
.addSubcommand("toggle", new ToggleCommand(npcRegistry))
|
||||||
|
.addSubcommand("skin", new SkinCommand(skinCache, npcRegistry, typeRegistry, propertyRegistry))
|
||||||
|
.addSubcommand("delete", new DeleteCommand(npcRegistry, adventure))
|
||||||
|
.addSubcommand("move", new MoveCommand(npcRegistry))
|
||||||
|
.addSubcommand("teleport", new TeleportCommand(npcRegistry))
|
||||||
|
.addSubcommand("list", new ListCommand(npcRegistry))
|
||||||
|
.addSubcommand("near", new NearCommand(npcRegistry))
|
||||||
|
.addSubcommand("type", new TypeCommand(npcRegistry, typeRegistry))
|
||||||
|
.addSubcommand("setlocation", new SetLocationCommand(npcRegistry))
|
||||||
|
.addSubcommand("lookatme", new LookAtMeCommand(npcRegistry))
|
||||||
|
.addSubcommand("setrotation", new SetRotationCommand(npcRegistry))
|
||||||
|
.addSubcommand("changeid", new ChangeIdCommand(npcRegistry))
|
||||||
|
.addSubcommand("property", new MultiCommand(bootstrap.loadHelpMessage("property"))
|
||||||
|
.addSubcommand("set", new PropertySetCommand(npcRegistry))
|
||||||
|
.addSubcommand("remove", new PropertyRemoveCommand(npcRegistry)))
|
||||||
|
.addSubcommand("storage", new MultiCommand(bootstrap.loadHelpMessage("storage"))
|
||||||
|
.addSubcommand("save", new SaveAllCommand(npcRegistry))
|
||||||
|
.addSubcommand("reload", new LoadAllCommand(npcRegistry))
|
||||||
|
.addSubcommand("import", new ImportCommand(npcRegistry, importerRegistry))
|
||||||
|
.addSubcommand("migrate", new MigrateCommand(configManager, this, packetFactory, actionRegistry, typeRegistry, propertyRegistry, textSerializer, npcRegistry.getStorage(), configManager.getConfig().storageType(), npcRegistry, serializerRegistry)))
|
||||||
|
.addSubcommand("holo", new MultiCommand(bootstrap.loadHelpMessage("holo"))
|
||||||
|
.addSubcommand("add", new HoloAddCommand(npcRegistry))
|
||||||
|
.addSubcommand("additem", new HoloAddItemCommand(npcRegistry))
|
||||||
|
.addSubcommand("delete", new HoloDeleteCommand(npcRegistry))
|
||||||
|
.addSubcommand("info", new HoloInfoCommand(npcRegistry))
|
||||||
|
.addSubcommand("insert", new HoloInsertCommand(npcRegistry))
|
||||||
|
.addSubcommand("insertitem", new HoloInsertItemCommand(npcRegistry))
|
||||||
|
.addSubcommand("set", new HoloSetCommand(npcRegistry))
|
||||||
|
.addSubcommand("setitem", new HoloSetItemCommand(npcRegistry))
|
||||||
|
.addSubcommand("offset", new HoloOffsetCommand(npcRegistry))
|
||||||
|
.addSubcommand("refreshdelay", new HoloRefreshDelayCommand(npcRegistry)))
|
||||||
|
.addSubcommand("action", new MultiCommand(bootstrap.loadHelpMessage("action"))
|
||||||
|
.addSubcommand("add", new ActionAddCommand(npcRegistry, actionRegistry))
|
||||||
|
.addSubcommand("clear", new ActionClearCommand(npcRegistry))
|
||||||
|
.addSubcommand("delete", new ActionDeleteCommand(npcRegistry))
|
||||||
|
.addSubcommand("edit", new ActionEditCommand(npcRegistry, actionRegistry))
|
||||||
|
.addSubcommand("list", new ActionListCommand(npcRegistry)))
|
||||||
|
.addSubcommand("version", new VersionCommand(this))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Enum<T>> void registerEnumParser(CommandManager manager, Class<T> clazz, Message<CommandContext> message) {
|
||||||
|
manager.registerParser(clazz, new EnumParser<>(clazz, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getDataFolder() {
|
||||||
|
return bootstrap.getDataFolder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PluginDescriptionFile getDescription() {
|
||||||
|
return bootstrap.getDescription();
|
||||||
|
}
|
||||||
|
}
|
73
plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlusApi.java
Normal file
73
plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlusApi.java
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package lol.pyr.znpcsplus;
|
||||||
|
|
||||||
|
import lol.pyr.znpcsplus.api.NpcApi;
|
||||||
|
import lol.pyr.znpcsplus.api.entity.EntityPropertyRegistry;
|
||||||
|
import lol.pyr.znpcsplus.api.interaction.ActionFactory;
|
||||||
|
import lol.pyr.znpcsplus.api.interaction.ActionRegistry;
|
||||||
|
import lol.pyr.znpcsplus.api.npc.NpcRegistry;
|
||||||
|
import lol.pyr.znpcsplus.api.npc.NpcTypeRegistry;
|
||||||
|
import lol.pyr.znpcsplus.api.skin.SkinDescriptorFactory;
|
||||||
|
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.interaction.ActionFactoryImpl;
|
||||||
|
import lol.pyr.znpcsplus.interaction.ActionRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.serialization.NpcSerializerRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.skin.SkinDescriptorFactoryImpl;
|
||||||
|
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
|
||||||
|
|
||||||
|
public class ZNpcsPlusApi implements NpcApi {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
private final NpcTypeRegistryImpl typeRegistry;
|
||||||
|
private final EntityPropertyRegistryImpl propertyRegistry;
|
||||||
|
private final ActionRegistryImpl actionRegistry;
|
||||||
|
private final ActionFactoryImpl actionFactory;
|
||||||
|
private final SkinDescriptorFactoryImpl skinDescriptorFactory;
|
||||||
|
private final NpcSerializerRegistryImpl npcSerializerRegistry;
|
||||||
|
|
||||||
|
public ZNpcsPlusApi(NpcRegistryImpl npcRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, ActionRegistryImpl actionRegistry, ActionFactoryImpl actionFactory, MojangSkinCache skinCache, NpcSerializerRegistryImpl npcSerializerRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
this.typeRegistry = typeRegistry;
|
||||||
|
this.propertyRegistry = propertyRegistry;
|
||||||
|
this.actionRegistry = actionRegistry;
|
||||||
|
this.actionFactory = actionFactory;
|
||||||
|
this.skinDescriptorFactory = new SkinDescriptorFactoryImpl(skinCache);
|
||||||
|
this.npcSerializerRegistry = npcSerializerRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NpcRegistry getNpcRegistry() {
|
||||||
|
return npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NpcTypeRegistry getNpcTypeRegistry() {
|
||||||
|
return typeRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityPropertyRegistry getPropertyRegistry() {
|
||||||
|
return propertyRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRegistry getActionRegistry() {
|
||||||
|
return actionRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionFactory getActionFactory() {
|
||||||
|
return actionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SkinDescriptorFactory getSkinDescriptorFactory() {
|
||||||
|
return skinDescriptorFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NpcSerializerRegistryImpl getNpcSerializerRegistry() {
|
||||||
|
return npcSerializerRegistry;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package lol.pyr.znpcsplus;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.common.message.Message;
|
||||||
|
import lol.pyr.znpcsplus.util.FileUtil;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class ZNpcsPlusBootstrap extends JavaPlugin {
|
||||||
|
private ZNpcsPlus zNpcsPlus;
|
||||||
|
private boolean legacy;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
legacy = new File(getDataFolder(), "data.json").isFile() && !new File(getDataFolder(), "data").isDirectory();
|
||||||
|
if (legacy) try {
|
||||||
|
Files.move(getDataFolder().toPath(), new File(getDataFolder().getParentFile(), "ZNPCsPlusLegacy").toPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLogger().severe(ChatColor.RED + "Failed to move legacy data folder! Plugin will disable.");
|
||||||
|
e.printStackTrace();
|
||||||
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
zNpcsPlus = new ZNpcsPlus(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
if (zNpcsPlus != null) zNpcsPlus.onEnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
if (zNpcsPlus != null) zNpcsPlus.onDisable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static Pattern EMBEDDED_FILE_PATTERN = Pattern.compile("\\{@(.*?)}");
|
||||||
|
|
||||||
|
private String loadMessageFile(String file) {
|
||||||
|
Reader reader = getTextResource("messages/" + file + ".txt");
|
||||||
|
if (reader == null) throw new RuntimeException(file + ".txt is missing from ZNPCsPlus jar!");
|
||||||
|
String text = FileUtil.dumpReaderAsString(reader);
|
||||||
|
Matcher matcher = EMBEDDED_FILE_PATTERN.matcher(text);
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
int lastMatchEnd = 0;
|
||||||
|
while (matcher.find()) {
|
||||||
|
builder.append(text, lastMatchEnd, matcher.start());
|
||||||
|
lastMatchEnd = matcher.end();
|
||||||
|
builder.append(loadMessageFile(matcher.group(1)));
|
||||||
|
}
|
||||||
|
builder.append(text, lastMatchEnd, text.length());
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Message<CommandContext> loadHelpMessage(String name) {
|
||||||
|
Component component = MiniMessage.miniMessage().deserialize(loadMessageFile(name));
|
||||||
|
return context -> context.send(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean movedLegacy() {
|
||||||
|
return legacy;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CenterCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public CenterCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " center <id>");
|
||||||
|
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||||
|
npc.setLocation(npc.getLocation().centered());
|
||||||
|
context.send(Component.text("NPC has been centered on it's current block.", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ChangeIdCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public ChangeIdCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " changeid <old> <new>");
|
||||||
|
NpcEntryImpl old = context.parse(NpcEntryImpl.class);
|
||||||
|
String newId = context.popString();
|
||||||
|
if (npcRegistry.getById(newId) != null) context.halt(Component.text("There is already an npc with the new id you have provided", NamedTextColor.RED));
|
||||||
|
npcRegistry.switchIds(old.getId(), newId);
|
||||||
|
context.send(Component.text("Npc's id changed to " + newId.toLowerCase(), NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CloneCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public CloneCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " clone <id> <new id>");
|
||||||
|
Player player = context.ensureSenderIsPlayer();
|
||||||
|
|
||||||
|
String id = context.popString();
|
||||||
|
if (npcRegistry.getById(id) == null) context.halt(Component.text("NPC with ID " + id + " does not exist.", NamedTextColor.RED));
|
||||||
|
String newId = context.popString();
|
||||||
|
if (npcRegistry.getById(newId) != null) context.halt(Component.text("NPC with ID " + newId + " already exists.", NamedTextColor.RED));
|
||||||
|
|
||||||
|
npcRegistry.clone(id, newId, player.getWorld(), new NpcLocation(player.getLocation()));
|
||||||
|
|
||||||
|
context.send(Component.text("Cloned NPC with ID " + id + " to ID " + newId + ".", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcTypeImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CreateCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
private final NpcTypeRegistryImpl typeRegistry;
|
||||||
|
|
||||||
|
public CreateCommand(NpcRegistryImpl npcRegistry, NpcTypeRegistryImpl typeRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
this.typeRegistry = typeRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " create <id> [<type>]");
|
||||||
|
Player player = context.ensureSenderIsPlayer();
|
||||||
|
|
||||||
|
String id = context.popString();
|
||||||
|
if (npcRegistry.getById(id) != null) context.halt(Component.text("NPC with that ID already exists.", NamedTextColor.RED));
|
||||||
|
|
||||||
|
NpcTypeImpl type;
|
||||||
|
if (context.argSize() == 1) {
|
||||||
|
type = context.parse(NpcTypeImpl.class);
|
||||||
|
} else {
|
||||||
|
type = typeRegistry.getByName("player");
|
||||||
|
}
|
||||||
|
|
||||||
|
NpcEntryImpl entry = npcRegistry.create(id, player.getWorld(), type, new NpcLocation(player.getLocation()));
|
||||||
|
entry.enableEverything();
|
||||||
|
|
||||||
|
context.send(Component.text("Created a " + type.getName() + " NPC with ID " + id + ".", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
if (context.argSize() == 2) return context.suggestStream(typeRegistry.getAllImpl().stream().map(NpcTypeImpl::getName));
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DeleteCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
private final BukkitAudiences adventure;
|
||||||
|
|
||||||
|
public DeleteCommand(NpcRegistryImpl npcRegistry, BukkitAudiences adventure) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
this.adventure = adventure;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " delete <id>");
|
||||||
|
NpcEntryImpl entry = context.parse(NpcEntryImpl.class);
|
||||||
|
npcRegistry.delete(entry.getId());
|
||||||
|
adventure.sender(context.getSender()).sendMessage(Component.text("Deleted NPC with ID: " + entry.getId(), NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
public class ListCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public ListCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
Component component = Component.text("Npc List:", NamedTextColor.GOLD).appendNewline();
|
||||||
|
for (String id : npcRegistry.getModifiableIds()) {
|
||||||
|
NpcImpl npc = npcRegistry.getById(id).getNpc();
|
||||||
|
NpcLocation location = npc.getLocation();
|
||||||
|
component = component.append(Component.text("ID: " + id, npc.isEnabled() ? NamedTextColor.GREEN : NamedTextColor.RED))
|
||||||
|
.append(Component.text(" | ", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text("Type: ", NamedTextColor.GREEN))
|
||||||
|
.append(Component.text(npc.getType().getName(), NamedTextColor.GREEN))
|
||||||
|
.append(Component.text(" | ", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text("Location: " + npc.getWorldName() + " X:" + location.getBlockX() + " Y:" + location.getBlockY() + " Z:" + location.getBlockZ(), NamedTextColor.GREEN))
|
||||||
|
.append(Component.text(" | ", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text("[TELEPORT]", NamedTextColor.DARK_GREEN).clickEvent(ClickEvent.runCommand("/znpcs teleport " + id)))
|
||||||
|
.appendNewline();
|
||||||
|
}
|
||||||
|
context.send(component);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class LookAtMeCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public LookAtMeCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " lookatme <id>");
|
||||||
|
Player player = context.ensureSenderIsPlayer();
|
||||||
|
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||||
|
npc.setLocation(npc.getLocation().lookingAt(player.getLocation()));
|
||||||
|
context.send(Component.text("NPC is now looking at you.", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class MoveCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public MoveCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " move <id>");
|
||||||
|
Player player = context.ensureSenderIsPlayer();
|
||||||
|
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||||
|
npc.setLocation(new NpcLocation(player.getLocation()));
|
||||||
|
if (!Objects.equals(npc.getWorld(), player.getWorld())) npc.setWorld(player.getWorld());
|
||||||
|
context.send(Component.text("NPC moved to your current location.", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class NearCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public NearCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " near <radius>");
|
||||||
|
Player player = context.ensureSenderIsPlayer();
|
||||||
|
int raw = context.parse(Integer.class);
|
||||||
|
double radius = Math.pow(raw, 2);
|
||||||
|
|
||||||
|
List<NpcEntryImpl> entries = npcRegistry.getAllModifiable().stream()
|
||||||
|
.filter(entry -> Objects.equals(entry.getNpc().getWorld(), player.getWorld()))
|
||||||
|
.filter(entry -> {
|
||||||
|
Location loc = entry.getNpc().getBukkitLocation();
|
||||||
|
return loc != null && loc.distanceSquared(player.getLocation()) < radius;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (entries.isEmpty()) context.halt(Component.text("There are no npcs within " + raw + " blocks around you.", NamedTextColor.RED));
|
||||||
|
|
||||||
|
Component component = Component.text("All NPCs that are within " + raw + " blocks from you:", NamedTextColor.GOLD).appendNewline();
|
||||||
|
for (NpcEntryImpl entry : entries) {
|
||||||
|
NpcImpl npc = entry.getNpc();
|
||||||
|
NpcLocation location = npc.getLocation();
|
||||||
|
component = component.append(Component.text("ID: " + entry.getId(), npc.isEnabled() ? NamedTextColor.GREEN : NamedTextColor.RED))
|
||||||
|
.append(Component.text(" | ", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text("Type: ", NamedTextColor.GREEN))
|
||||||
|
.append(Component.text(npc.getType().getName(), NamedTextColor.GREEN))
|
||||||
|
.append(Component.text(" | ", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text("Location: " + npc.getWorldName() + " X:" + location.getBlockX() + " Y:" + location.getBlockY() + " Z:" + location.getBlockZ(), NamedTextColor.GREEN))
|
||||||
|
.append(Component.text(" | ", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text("[TELEPORT]", NamedTextColor.DARK_GREEN).clickEvent(ClickEvent.runCommand("/znpcs teleport " + entry.getId())))
|
||||||
|
.appendNewline();
|
||||||
|
}
|
||||||
|
context.send(component);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.config.ConfigManager;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
public class ReloadConfigCommand implements CommandHandler {
|
||||||
|
private final ConfigManager configManager;
|
||||||
|
|
||||||
|
public ReloadConfigCommand(ConfigManager configManager) {
|
||||||
|
this.configManager = configManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
configManager.reload();
|
||||||
|
context.send(Component.text("Plugin configuration reloaded successfully", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SetLocationCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public SetLocationCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " setlocation <id> <x> <y> <z>");
|
||||||
|
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||||
|
double x = parseLocation(context.popString(), npc.getLocation().getX());
|
||||||
|
double y = parseLocation(context.popString(), npc.getLocation().getY());
|
||||||
|
double z = parseLocation(context.popString(), npc.getLocation().getZ());
|
||||||
|
npc.setLocation(new NpcLocation(x, y, z, npc.getLocation().getYaw(), npc.getLocation().getPitch()));
|
||||||
|
context.send(Component.text("NPC has been moved to " + x + ", " + y + ", " + z + ".", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
NpcImpl npc = context.suggestionParse(0, NpcEntryImpl.class).getNpc();
|
||||||
|
if (context.argSize() == 2) return Arrays.asList(String.valueOf(npc.getLocation().getX()), "~");
|
||||||
|
else if (context.argSize() == 3) return Arrays.asList(String.valueOf(npc.getLocation().getY()), "~");
|
||||||
|
else if (context.argSize() == 4) return Arrays.asList(String.valueOf(npc.getLocation().getZ()), "~");
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double parseLocation(String input, double current) throws CommandExecutionException {
|
||||||
|
if (input.equals("~")) return current;
|
||||||
|
if (input.startsWith("~")) {
|
||||||
|
try {
|
||||||
|
return current + Double.parseDouble(input.substring(1));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new CommandExecutionException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Double.parseDouble(input);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SetRotationCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public SetRotationCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " setrotation <id> <yaw> <pitch>");
|
||||||
|
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||||
|
float yaw = parseRotation(context.popString(), npc.getLocation().getYaw());
|
||||||
|
float pitch = parseRotation(context.popString(), npc.getLocation().getPitch());
|
||||||
|
if (pitch < -90 || pitch > 90) {
|
||||||
|
pitch = Math.min(Math.max(pitch, -90), 90);
|
||||||
|
context.send(Component.text("Warning: pitch is outside of the -90 to 90 range. It has been normalized to " + pitch + ".", NamedTextColor.YELLOW));
|
||||||
|
}
|
||||||
|
npc.setLocation(new NpcLocation(npc.getLocation().getX(), npc.getLocation().getY(), npc.getLocation().getZ(), yaw, pitch));
|
||||||
|
context.send(Component.text("NPC has been rotated to " + yaw + ", " + pitch + ".", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
NpcImpl npc = context.suggestionParse(0, NpcEntryImpl.class).getNpc();
|
||||||
|
if (context.argSize() == 2) return Arrays.asList(String.valueOf(npc.getLocation().getYaw()), "~");
|
||||||
|
else if (context.argSize() == 3) return Arrays.asList(String.valueOf(npc.getLocation().getPitch()), "~");
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float parseRotation(String input, float current) throws CommandExecutionException {
|
||||||
|
if (input.equals("~")) return current;
|
||||||
|
if (input.startsWith("~")) {
|
||||||
|
try {
|
||||||
|
return current + Float.parseFloat(input.substring(1));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new CommandExecutionException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Float.parseFloat(input);
|
||||||
|
}
|
||||||
|
}
|
143
plugin/src/main/java/lol/pyr/znpcsplus/commands/SkinCommand.java
Normal file
143
plugin/src/main/java/lol/pyr/znpcsplus/commands/SkinCommand.java
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
|
||||||
|
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
|
||||||
|
import lol.pyr.znpcsplus.skin.descriptor.NameFetchingDescriptor;
|
||||||
|
import lol.pyr.znpcsplus.skin.descriptor.MirrorDescriptor;
|
||||||
|
import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class SkinCommand implements CommandHandler {
|
||||||
|
private final MojangSkinCache skinCache;
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
private final NpcTypeRegistryImpl typeRegistry;
|
||||||
|
private final EntityPropertyRegistryImpl propertyRegistry;
|
||||||
|
|
||||||
|
public SkinCommand(MojangSkinCache skinCache, NpcRegistryImpl npcRegistry, NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry) {
|
||||||
|
this.skinCache = skinCache;
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
this.typeRegistry = typeRegistry;
|
||||||
|
this.propertyRegistry = propertyRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " skin <id> <type> [value]");
|
||||||
|
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||||
|
if (npc.getType() != typeRegistry.getByEntityType(EntityTypes.PLAYER)) context.halt(Component.text("The NPC must be a player to have a skin", NamedTextColor.RED));
|
||||||
|
String type = context.popString();
|
||||||
|
|
||||||
|
if (type.equalsIgnoreCase("mirror")) {
|
||||||
|
npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), new MirrorDescriptor(skinCache));
|
||||||
|
npc.respawn();
|
||||||
|
context.halt(Component.text("The NPC's skin will now mirror the player that it's being displayed to", NamedTextColor.GREEN));
|
||||||
|
} else if (type.equalsIgnoreCase("static")) {
|
||||||
|
context.ensureArgsNotEmpty();
|
||||||
|
String name = context.dumpAllArgs();
|
||||||
|
context.send(Component.text("Fetching skin \"" + name + "\"...", NamedTextColor.GREEN));
|
||||||
|
PrefetchedDescriptor.forPlayer(skinCache, name).thenAccept(skin -> {
|
||||||
|
if (skin.getSkin() == null) {
|
||||||
|
context.send(Component.text("Failed to fetch skin, are you sure the player name is valid?", NamedTextColor.RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), skin);
|
||||||
|
npc.respawn();
|
||||||
|
context.send(Component.text("The NPC's skin has been set to \"" + name + "\"", NamedTextColor.GREEN));
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else if (type.equalsIgnoreCase("dynamic")) {
|
||||||
|
context.ensureArgsNotEmpty();
|
||||||
|
String name = context.dumpAllArgs();
|
||||||
|
npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), new NameFetchingDescriptor(skinCache, name));
|
||||||
|
npc.respawn();
|
||||||
|
context.halt(Component.text("The NPC's skin will now be resolved per-player from \"" + name + "\""));
|
||||||
|
} else if (type.equalsIgnoreCase("url")) {
|
||||||
|
context.ensureArgsNotEmpty();
|
||||||
|
String variant = context.popString().toLowerCase();
|
||||||
|
if (!variant.equalsIgnoreCase("slim") && !variant.equalsIgnoreCase("classic")) {
|
||||||
|
context.send(Component.text("Invalid skin variant! Please use one of the following: slim, classic", NamedTextColor.RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String urlString = context.dumpAllArgs();
|
||||||
|
try {
|
||||||
|
URL url = new URL(urlString);
|
||||||
|
context.send(Component.text("Fetching skin from url \"" + urlString + "\"...", NamedTextColor.GREEN));
|
||||||
|
PrefetchedDescriptor.fromUrl(skinCache, url , variant).thenAccept(skin -> {
|
||||||
|
if (skin.getSkin() == null) {
|
||||||
|
context.send(Component.text("Failed to fetch skin, are you sure the url is valid?", NamedTextColor.RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), skin);
|
||||||
|
npc.respawn();
|
||||||
|
context.send(Component.text("The NPC's skin has been set.", NamedTextColor.GREEN));
|
||||||
|
});
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
context.send(Component.text("Invalid url!", NamedTextColor.RED));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (type.equalsIgnoreCase("file")) {
|
||||||
|
context.ensureArgsNotEmpty();
|
||||||
|
String path = context.dumpAllArgs();
|
||||||
|
context.send(Component.text("Fetching skin from file \"" + path + "\"...", NamedTextColor.GREEN));
|
||||||
|
PrefetchedDescriptor.fromFile(skinCache, path).exceptionally(e -> {
|
||||||
|
if (e instanceof FileNotFoundException || e.getCause() instanceof FileNotFoundException) {
|
||||||
|
context.send(Component.text("A file at the specified path could not be found!", NamedTextColor.RED));
|
||||||
|
} else {
|
||||||
|
context.send(Component.text("An error occurred while fetching the skin from file! Check the console for more details.", NamedTextColor.RED));
|
||||||
|
//noinspection CallToPrintStackTrace
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}).thenAccept(skin -> {
|
||||||
|
if (skin == null) return;
|
||||||
|
if (skin.getSkin() == null) {
|
||||||
|
context.send(Component.text("Failed to fetch skin, are you sure the file path is valid?", NamedTextColor.RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), skin);
|
||||||
|
npc.respawn();
|
||||||
|
context.send(Component.text("The NPC's skin has been set.", NamedTextColor.GREEN));
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.send(Component.text("Unknown skin type! Please use one of the following: mirror, static, dynamic, url"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
if (context.argSize() == 2) return context.suggestLiteral("mirror", "static", "dynamic", "url", "file");
|
||||||
|
if (context.matchSuggestion("*", "static")) return context.suggestPlayers();
|
||||||
|
if (context.argSize() == 3 && context.matchSuggestion("*", "url")) {
|
||||||
|
return context.suggestLiteral("slim", "classic");
|
||||||
|
}
|
||||||
|
if (context.argSize() == 3 && context.matchSuggestion("*", "file")) {
|
||||||
|
if (skinCache.getSkinsFolder().exists()) {
|
||||||
|
File[] files = skinCache.getSkinsFolder().listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
return Arrays.stream(files).map(File::getName).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.util.FoliaUtil;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TeleportCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public TeleportCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " teleport <id>");
|
||||||
|
Player player = context.ensureSenderIsPlayer();
|
||||||
|
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||||
|
Location location = npc.getBukkitLocation();
|
||||||
|
if (location == null) context.halt("Unable to teleport to NPC, the world is not loaded!");
|
||||||
|
FoliaUtil.teleport(player, location);
|
||||||
|
context.send(Component.text("Teleported to NPC!", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ToggleCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public ToggleCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " toggle <id> [<enable/disable>]");
|
||||||
|
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||||
|
boolean enabled;
|
||||||
|
if (context.argSize() == 1) {
|
||||||
|
enabled = context.popString().equalsIgnoreCase("enable");
|
||||||
|
} else {
|
||||||
|
enabled = !npc.isEnabled();
|
||||||
|
}
|
||||||
|
npc.setEnabled(enabled);
|
||||||
|
context.send(Component.text("NPC has been " + (enabled ? "enabled" : "disabled"), NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
if (context.argSize() == 2) return context.suggestLiteral("enable", "disable");
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.*;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TypeCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl registry;
|
||||||
|
private final NpcTypeRegistryImpl typeRegistry;
|
||||||
|
|
||||||
|
public TypeCommand(NpcRegistryImpl registry, NpcTypeRegistryImpl typeRegistry) {
|
||||||
|
this.registry = registry;
|
||||||
|
this.typeRegistry = typeRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " type <id> <type>");
|
||||||
|
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||||
|
NpcTypeImpl type = context.parse(NpcTypeImpl.class);
|
||||||
|
npc.setType(type);
|
||||||
|
context.send(Component.text("NPC type set to " + type.getName() + ".", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(registry.getModifiableIds());
|
||||||
|
if (context.argSize() == 2) return context.suggestStream(typeRegistry.getAllImpl().stream().map(NpcTypeImpl::getName));
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package lol.pyr.znpcsplus.commands;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.ZNpcsPlus;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.jar.Attributes;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
public class VersionCommand implements CommandHandler {
|
||||||
|
|
||||||
|
private final String pluginVersion;
|
||||||
|
private final String gitBranch;
|
||||||
|
private final String gitCommitHash;
|
||||||
|
private final String buildId;
|
||||||
|
|
||||||
|
public VersionCommand(ZNpcsPlus plugin) {
|
||||||
|
pluginVersion = plugin.getDescription().getVersion();
|
||||||
|
String gitBranch = "";
|
||||||
|
String gitCommitHash = "";
|
||||||
|
String buildId = "";
|
||||||
|
try {
|
||||||
|
URL jarUrl = getClass().getProtectionDomain().getCodeSource().getLocation();
|
||||||
|
JarFile jarFile = new JarFile(jarUrl.toURI().getPath());
|
||||||
|
Attributes attributes = jarFile.getManifest().getMainAttributes();
|
||||||
|
gitBranch = attributes.getValue("Git-Branch");
|
||||||
|
gitCommitHash = attributes.getValue("Git-Commit-Hash");
|
||||||
|
buildId = attributes.getValue("Build-Id");
|
||||||
|
} catch (IOException | URISyntaxException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
this.gitBranch = gitBranch;
|
||||||
|
this.gitCommitHash = gitCommitHash;
|
||||||
|
this.buildId = buildId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
|
||||||
|
StringBuilder versionBuilder = new StringBuilder("This server is running ZNPCsPlus version ").append(pluginVersion);
|
||||||
|
if (gitBranch != null && !gitBranch.isEmpty()) {
|
||||||
|
versionBuilder.append("-").append(gitBranch);
|
||||||
|
}
|
||||||
|
if (gitCommitHash != null && !gitCommitHash.isEmpty()) {
|
||||||
|
versionBuilder.append("@").append(gitCommitHash);
|
||||||
|
}
|
||||||
|
if (buildId != null && !buildId.isEmpty()) {
|
||||||
|
versionBuilder.append(" (Build #").append(buildId).append(")");
|
||||||
|
} else {
|
||||||
|
versionBuilder.append(" (Development Build)");
|
||||||
|
}
|
||||||
|
|
||||||
|
String version = versionBuilder.toString();
|
||||||
|
|
||||||
|
context.send(Component.text(version, NamedTextColor.GREEN)
|
||||||
|
.hoverEvent(Component.text("Click to copy version to clipboard"))
|
||||||
|
.clickEvent(ClickEvent.copyToClipboard(version)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package lol.pyr.znpcsplus.commands.action;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.interaction.ActionRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.interaction.InteractionCommandHandler;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ActionAddCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
private final ActionRegistryImpl actionRegistry;
|
||||||
|
|
||||||
|
public ActionAddCommand(NpcRegistryImpl npcRegistry, ActionRegistryImpl actionRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
this.actionRegistry = actionRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
List<InteractionCommandHandler> commands = actionRegistry.getCommands();
|
||||||
|
context.setUsage(context.getLabel() + " action add <action type>");
|
||||||
|
String sub = context.popString();
|
||||||
|
for (InteractionCommandHandler command : commands) if (command.getSubcommandName().equalsIgnoreCase(sub)) {
|
||||||
|
context.setUsage(context.getLabel() + " action add");
|
||||||
|
command.run(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.send(Component.text("Invalid action type, available action types:\n" +
|
||||||
|
commands.stream().map(InteractionCommandHandler::getSubcommandName).collect(Collectors.joining(", ")), NamedTextColor.RED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
List<InteractionCommandHandler> commands = actionRegistry.getCommands();
|
||||||
|
if (context.argSize() == 1) return context.suggestStream(commands.stream().map(InteractionCommandHandler::getSubcommandName));
|
||||||
|
if (context.argSize() == 2) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
if (context.argSize() >= 3) {
|
||||||
|
String sub = context.popString();
|
||||||
|
context.popString();
|
||||||
|
for (InteractionCommandHandler command : commands) if (command.getSubcommandName().equalsIgnoreCase(sub)) return command.suggest(context);
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package lol.pyr.znpcsplus.commands.action;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ActionClearCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public ActionClearCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " action clear <id>");
|
||||||
|
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||||
|
if (npc.getActions().size() == 0) context.halt(Component.text("That npc doesn't have any actions", NamedTextColor.RED));
|
||||||
|
npc.clearActions();
|
||||||
|
context.send(Component.text("Removed all actions from the npc", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package lol.pyr.znpcsplus.commands.action;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ActionDeleteCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public ActionDeleteCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " action delete <id> <index>");
|
||||||
|
NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc();
|
||||||
|
int index = context.parse(Integer.class);
|
||||||
|
if (index >= npc.getActions().size() || index < 0) context.halt(Component.text("That npc doesn't have any action with the index " + index, NamedTextColor.RED));
|
||||||
|
npc.removeAction(index);
|
||||||
|
context.send(Component.text("Removed action with index " + index, NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
if (context.argSize() == 2) return context.suggestStream(Stream.iterate(0, n -> n + 1)
|
||||||
|
.limit(context.suggestionParse(0, NpcEntryImpl.class).getNpc().getActions().size())
|
||||||
|
.map(String::valueOf));
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package lol.pyr.znpcsplus.commands.action;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.api.interaction.InteractionAction;
|
||||||
|
import lol.pyr.znpcsplus.interaction.ActionRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.interaction.InteractionCommandHandler;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ActionEditCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
private final ActionRegistryImpl actionRegistry;
|
||||||
|
|
||||||
|
private InteractionCommandHandler commandHandler = null;
|
||||||
|
|
||||||
|
public ActionEditCommand(NpcRegistryImpl npcRegistry, ActionRegistryImpl actionRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
this.actionRegistry = actionRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " action edit <id> <action index> <action type> ...");
|
||||||
|
NpcEntryImpl entry = context.parse(NpcEntryImpl.class);
|
||||||
|
int index = context.parse(Integer.class);
|
||||||
|
if (index >= entry.getNpc().getActions().size() || index < 0) context.halt(Component.text("That npc doesn't have any action with the index " + index, NamedTextColor.RED));
|
||||||
|
List<InteractionCommandHandler> commands = actionRegistry.getCommands();
|
||||||
|
String sub = context.popString();
|
||||||
|
for (InteractionCommandHandler command : commands) if (command.getSubcommandName().equalsIgnoreCase(sub)) {
|
||||||
|
this.commandHandler = command;
|
||||||
|
}
|
||||||
|
if (this.commandHandler == null) {
|
||||||
|
context.send(Component.text("Invalid action type, available action types:\n" +
|
||||||
|
commands.stream().map(InteractionCommandHandler::getSubcommandName).collect(Collectors.joining(", ")), NamedTextColor.RED));
|
||||||
|
}
|
||||||
|
InteractionAction newAction = this.commandHandler.parse(context);
|
||||||
|
entry.getNpc().editAction(index, newAction);
|
||||||
|
context.send(Component.text("Edited action with index " + index + " of Npc " + entry.getId(), NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
if (context.argSize() == 2) return context.suggestStream(Stream.iterate(0, n -> n + 1)
|
||||||
|
.limit(context.suggestionParse(0, NpcEntryImpl.class).getNpc().getActions().size())
|
||||||
|
.map(String::valueOf));
|
||||||
|
List<InteractionCommandHandler> commands = actionRegistry.getCommands();
|
||||||
|
if (context.argSize() == 3) return context.suggestStream(commands.stream().map(InteractionCommandHandler::getSubcommandName));
|
||||||
|
context.popString();
|
||||||
|
context.popString();
|
||||||
|
String sub = context.popString();
|
||||||
|
for (InteractionCommandHandler command : commands) if (command.getSubcommandName().equalsIgnoreCase(sub)) return command.suggest(context);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package lol.pyr.znpcsplus.commands.action;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.api.interaction.InteractionAction;
|
||||||
|
import lol.pyr.znpcsplus.interaction.InteractionActionImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ActionListCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public ActionListCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " action list <id>");
|
||||||
|
NpcEntryImpl entry = context.parse(NpcEntryImpl.class);
|
||||||
|
List<InteractionAction> actions = entry.getNpc().getActions();
|
||||||
|
context.send("Actions of Npc " + entry.getId() + ":");
|
||||||
|
for (int i = 0; i < actions.size(); i++) {
|
||||||
|
if (actions.get(i) instanceof InteractionActionImpl) {
|
||||||
|
context.send(((InteractionActionImpl) actions.get(i)).getInfo(entry.getId(), i, context));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package lol.pyr.znpcsplus.commands.hologram;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.hologram.HologramImpl;
|
||||||
|
import lol.pyr.znpcsplus.hologram.HologramItem;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class HoloAddCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl registry;
|
||||||
|
|
||||||
|
public HoloAddCommand(NpcRegistryImpl registry) {
|
||||||
|
this.registry = registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " holo add <id> <text>");
|
||||||
|
HologramImpl hologram = context.parse(NpcEntryImpl.class).getNpc().getHologram();
|
||||||
|
context.ensureArgsNotEmpty();
|
||||||
|
String in = context.dumpAllArgs();
|
||||||
|
if (in.toLowerCase().startsWith("item:")) {
|
||||||
|
if (!HologramItem.ensureValidItemInput(in.substring(5))) {
|
||||||
|
context.halt(Component.text("The item input is invalid!", NamedTextColor.RED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hologram.addLine(in);
|
||||||
|
context.send(Component.text("NPC line added!", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(registry.getModifiableIds());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package lol.pyr.znpcsplus.commands.hologram;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.hologram.HologramImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class HoloAddItemCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl registry;
|
||||||
|
|
||||||
|
public HoloAddItemCommand(NpcRegistryImpl registry) {
|
||||||
|
this.registry = registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " holo additem <id>");
|
||||||
|
Player player = context.ensureSenderIsPlayer();
|
||||||
|
org.bukkit.inventory.ItemStack itemStack = player.getInventory().getItemInHand();
|
||||||
|
if (itemStack == null) context.halt(Component.text("You must be holding an item!", NamedTextColor.RED));
|
||||||
|
HologramImpl hologram = context.parse(NpcEntryImpl.class).getNpc().getHologram();
|
||||||
|
hologram.addItemLineStack(itemStack);
|
||||||
|
context.send(Component.text("NPC item line added!", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(registry.getModifiableIds());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package lol.pyr.znpcsplus.commands.hologram;
|
||||||
|
|
||||||
|
import lol.pyr.director.adventure.command.CommandContext;
|
||||||
|
import lol.pyr.director.adventure.command.CommandHandler;
|
||||||
|
import lol.pyr.director.common.command.CommandExecutionException;
|
||||||
|
import lol.pyr.znpcsplus.hologram.HologramImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class HoloDeleteCommand implements CommandHandler {
|
||||||
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
|
||||||
|
public HoloDeleteCommand(NpcRegistryImpl npcRegistry) {
|
||||||
|
this.npcRegistry = npcRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(CommandContext context) throws CommandExecutionException {
|
||||||
|
context.setUsage(context.getLabel() + " holo delete <id> <line>");
|
||||||
|
HologramImpl hologram = context.parse(NpcEntryImpl.class).getNpc().getHologram();
|
||||||
|
int line = context.parse(Integer.class);
|
||||||
|
if (line < 0 || line >= hologram.getLines().size()) context.halt(Component.text("Invalid line number!", NamedTextColor.RED));
|
||||||
|
hologram.removeLine(line);
|
||||||
|
context.send(Component.text("NPC line removed.", NamedTextColor.GREEN));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> suggest(CommandContext context) throws CommandExecutionException {
|
||||||
|
if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds());
|
||||||
|
if (context.argSize() == 2) return context.suggestStream(Stream.iterate(0, n -> n + 1)
|
||||||
|
.limit(context.suggestionParse(0, NpcEntryImpl.class).getNpc().getHologram().getLines().size())
|
||||||
|
.map(String::valueOf));
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue