mirror of
https://github.com/CarmJos/UserPrefix.git
synced 2026-06-05 09:01:39 +08:00
Compare commits
61 Commits
1.0.0-SNAPSHOT
...
2.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| e14901ac86 | |||
| 9a620d7324 | |||
| 9cff1c03dc | |||
| 3a457082b1 | |||
| 12218a2141 | |||
| 389e4d3904 | |||
| 6ac3cea7c0 | |||
| 3f14294e67 | |||
| 93521f6621 | |||
| 43a4fb08a6 | |||
| 3dd6398afa | |||
| 799bb4e52b | |||
| 7ea3934db9 | |||
| 0d20860166 | |||
| b0c6c793a8 | |||
| b6319eec78 | |||
| 8bf19a69f8 | |||
| 5d4b131a13 | |||
| 5c2b062839 | |||
| dbe4b187d3 | |||
| 419e440700 | |||
| 7052ea6ec4 | |||
| 264b69b115 | |||
| c16d12d718 | |||
| 796aac50c2 | |||
| a8a1b844cc | |||
| a1cdf896da | |||
| 1d2960001c | |||
| 8ec9f88553 | |||
| 0c0f2fad16 | |||
| f3920c7e23 | |||
| 0344975371 | |||
| 259955153a | |||
| c72c7b8639 | |||
| c1fd97b765 | |||
| f0c2d98f7b | |||
| 77eeb7a8a2 | |||
| ae4a6717b6 | |||
| f7b5bff6e3 | |||
| 44fcc6b77d | |||
| 03f7a2c498 | |||
| 7a755767e9 | |||
| 97dd06a5b5 | |||
| 1ffef4179e | |||
| 7f3f3b65a2 | |||
| 393e205bb1 | |||
| 85f5e7d95a | |||
| ee2cc259ef | |||
| bd303f24b7 | |||
| a95d4d8cbb | |||
| 7af506362b | |||
| 6c175816ce | |||
| 2e57e03927 | |||
| 03afb12161 | |||
| bcc8d077a9 | |||
| eaa386a6ab | |||
| 22bf9d7d94 | |||
| 3de812c42a | |||
| 6abc13af23 | |||
| bb126c676e | |||
| f6a5538da3 |
@@ -0,0 +1,31 @@
|
||||
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
||||
|
||||
name: Java CI with Maven
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
cache: maven
|
||||
- name: Build with Maven
|
||||
run: mvn -B package --file pom.xml
|
||||
- run: mkdir staging && cp target/*.jar staging
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Package
|
||||
path: staging
|
||||
@@ -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>.
|
||||
+303
@@ -0,0 +1,303 @@
|
||||

|
||||
|
||||
# UserPrefix Plugin
|
||||
|
||||
[](https://www.codefactor.io/repository/github/carmjos/userprefix)
|
||||

|
||||
[](https://opensource.org/licenses/GPL-3.0)
|
||||
[](https://github.com/CarmJos/UserPrefix/actions/workflows/maven.yml)
|
||||

|
||||

|
||||
|
||||
Lightweight, efficient, and real-time user prefix system.
|
||||
|
||||
This plugin is implemented based on Spigot ,**Theoretically** support ALL MineCraft Versions.
|
||||
|
||||
The development of this plugin is based on Chinese which purpose is to help Chinese developers learn Bukkit plugin
|
||||
development.
|
||||
|
||||
This plugin has been published on [SpigotMC](https://www.spigotmc.org/resources/userprefix.96277/) .
|
||||
|
||||
本插件已在 [MCBBS](https://www.mcbbs.net/forum.php?mod=viewthread&tid=1261503) 上发布,欢迎中文用户来这里下载。
|
||||
|
||||
## Examples
|
||||
|
||||

|
||||
|
||||
## Dependencies
|
||||
|
||||
- **[Necessary]** Plugin developed based on [Spigot-API](https://hub.spigotmc.org/stash/projects/SPIGOT)
|
||||
and [BukkitAPI](http://bukkit.org/).
|
||||
- **[Necessary]** Plugin data storage base on [LuckPerms](https://www.spigotmc.org/resources/luckperms.28140/).
|
||||
- **[Recommend]** Placeholders based on [PlaceholderAPI](https://www.spigotmc.org/resources/6245/) .
|
||||
|
||||
For development dependencies, please see [Dependencies](https://github.com/CarmJos/UserPrefix/network/dependencies) .
|
||||
|
||||
## Features
|
||||
|
||||
- **Theoretically** support ALL MineCraft Versions.
|
||||
- Reloading the configuration will automatically refresh the prefix of all players.
|
||||
- Real-time judgment and feedback to the player when permissions are changed.
|
||||
- Configurable sounds and messages.
|
||||
- The prefix icon can be configured as "Selected", "Has Permission" and “No Permission”.
|
||||
- Item configuration is natively configured through ItemStack, which supports all MC settings!
|
||||
- TabList is automatically sorted according to the weight of the prefix (if there is a conflict, it can be turned off)
|
||||
- The prefix display on the player name (can be turned off if there is a conflict)
|
||||
- GUI with automatic sorting and page turning!
|
||||
- Support PlaceholderAPI variables!
|
||||
- Support Hex color! (Version 1.16 and above) `&(#Color)`
|
||||
- Example: LightSlateBlue `&(#8470FF)` 、 DarkSlateBlue `&(#483D8B)`
|
||||
|
||||
## Notice
|
||||
|
||||
### 1. Version support issues
|
||||
|
||||
This plugin theoretically supports all versions.
|
||||
|
||||
If the icon does not load, the sound cannot be played, etc., please check whether the type of the item and sound in the
|
||||
configuration file exists in the current version.
|
||||
|
||||
Take the SOUND as an example. The sound that the villager said "OK" is "`VILLAGER_YES`" in the lower version, but it
|
||||
becomes "`ENTITY_VILLAGER_YES`" in the higher version.
|
||||
|
||||
### 2. Scoreboard exception problem
|
||||
|
||||
The display of the prefix on the head and the sorting of the TabList both use the scoreboard API.
|
||||
|
||||
Please turn of the `functions.OnNamePrefix` in the configuration if there is a conflict.
|
||||
|
||||
### 3. Item icon configuration problem
|
||||
|
||||
Items are read through the ItemStack serialization method provided by Bukkit. For related configuration methods, please
|
||||
refer to [ItemStack Serialization](https://www.spigotmc.org/wiki/itemstack-serialization/).
|
||||
|
||||
## Commands
|
||||
|
||||
This plugin's Commands are based on Chinese!
|
||||
**May support multi-language in the future.**
|
||||
|
||||
```text
|
||||
/UserPrefix or /prefix #Open prefix GUI
|
||||
/UserPrefixAdmin # View Admin Command Help
|
||||
/UserPrefixAdmin reload # Reload Config
|
||||
/UserPrefixAdmin list # List all configured prefixes.~~~~
|
||||
```
|
||||
|
||||
## Placeholders (PlaceholderAPI)
|
||||
|
||||
After installed the [PlaceholderAPI](https://github.com/PlaceholderAPI/PlaceholderAPI) , you can
|
||||
type `/papi info UserPrefix` to see all the placeholders.
|
||||
|
||||
```text
|
||||
# %UserPrefix_prefix%
|
||||
- Get the content of the current prefix
|
||||
# %UserPrefix_weight%
|
||||
- Get the weight of the current prefix.
|
||||
# %UserPrefix_identifier%
|
||||
- Get the identifier of the current prefix.
|
||||
# %UserPrefix_name%
|
||||
- Get the name of the current prefix.
|
||||
# %UserPrefix_has_<Identifier>%
|
||||
- Determine whether the player has a certain prefix(true/false)
|
||||
```
|
||||
|
||||
## Configuration files
|
||||
|
||||
### [Plugin Configuration](https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/en_US/config.yml) (config.yml)
|
||||
|
||||
Notice: The default configuration is based on Chinese. You can find
|
||||
the [English Version here](https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/en_US/config.yml).
|
||||
|
||||
```yaml
|
||||
version: ${project.version} # DO NOT EDIT IT
|
||||
|
||||
debug: false #DEBUG OUT PUT
|
||||
|
||||
GUI:
|
||||
title: "&f&lMy Prefixes List" # Title of the GUI
|
||||
items:
|
||||
next-page: # only show has next page
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: ARROW
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fNext Page"
|
||||
lore:
|
||||
- ""
|
||||
- "§fRight-Click to the last page"
|
||||
previous-page: # only show has previous page
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: ARROW
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fPrevious Page"
|
||||
lore:
|
||||
- ""
|
||||
- "§fRight-Click to the first page"
|
||||
|
||||
functions:
|
||||
# Whether to add a prefix to the top of the head,
|
||||
# this method uses the scoreboard above the head,
|
||||
# please turn it off if there is a conflict.
|
||||
OnNamePrefix: true
|
||||
# Automatic prefix select.
|
||||
# When the player does not choose a prefix by himself,
|
||||
# the prefix with the highest weight will be used~~~~ automatically
|
||||
autoUsePrefix: true
|
||||
chat:
|
||||
# Chat Function
|
||||
# - I recommend using other chat plugins instead of using this plugin,
|
||||
# - this plugin only provides very basic chat format placeholders.
|
||||
# - Notice that: format must has “%1$s” and “%2$s” for PlayerName and Message (Bukkit Chat Event)
|
||||
enable: false
|
||||
format: "<%UserPrefix_prefix%%1$s> %2$s"
|
||||
|
||||
Sounds:
|
||||
# Format is [SOUND_NAME:Volume:Pitch] or [SOUND_NAME:Volume] or [SOUND_NAME]
|
||||
openGUI: "BLOCK_NOTE_BLOCK_PLING:1:1"
|
||||
guiClick: "UI_BUTTON_CLICK"
|
||||
prefixChange: "ENTITY_VILLAGER_YES"
|
||||
prefixExpired: "ENTITY_VILLAGER_NO"
|
||||
|
||||
# The default prefix's weight is 0.
|
||||
defaultPrefix:
|
||||
name: "Default prefix"
|
||||
content: "&b"
|
||||
itemNotUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: NAME_TAG
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fThe default prefix §f(Click to select)"
|
||||
lore:
|
||||
- ""
|
||||
- "§a➥ Click to use"
|
||||
itemUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: NAME_TAG
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fThe default prefix"
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ Selected"
|
||||
```
|
||||
|
||||
### [Messages Configuration](https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/en_US/messages.yml) (messages.yml)
|
||||
|
||||
```yaml
|
||||
selected:
|
||||
- "&7You have selected the &f%(name) &7as current prefix."
|
||||
expired:
|
||||
- "&7Your prefix &f%(oldName) &7has expired,"
|
||||
- "&7Now the prefix is changed to &f%(newName) &7."
|
||||
reload:
|
||||
- "&a&lReload completed!&7costs &f%(time)ms&7."
|
||||
help:
|
||||
- "&3&lUserPrefixAdmin &fHelp"
|
||||
- "&8#/upa&f list"
|
||||
- "&8- &7Show configured prefixes."
|
||||
- "&8#/upa&f reload"
|
||||
- "&8- &7Reload configuration."
|
||||
list-title:
|
||||
- "&3&lUserPrefixAdmin &fList"
|
||||
list-value:
|
||||
- "&8#%(weight) &f%(identifier)"
|
||||
- "&8- &7Name &r%(name) &7Perm &r%(permission)"
|
||||
- "&8- &7Example&r %(content) %(sender_name)"
|
||||
|
||||
```
|
||||
|
||||
### [Prefixes Configuration](https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/en_US/example-prefix.yml) (/prefixes/*.yml)
|
||||
|
||||
All prefixes are separate configuration files, stored in the `<Data Folder>/prefixes/` for easy management.
|
||||
|
||||
Some symbols in file name may affect reading, please avoid using them.
|
||||
|
||||
```yaml
|
||||
# identifier [Necessary]
|
||||
# This will be used for data-storage.
|
||||
identifier: "pro"
|
||||
|
||||
# Name [Necessary]
|
||||
# Use in messages.
|
||||
name: "&b&lPro&b"
|
||||
|
||||
# Content [Necessary]
|
||||
# Use in Placeholders
|
||||
content: "§b§lPro §b"
|
||||
|
||||
# Weight [Necessary]
|
||||
# used for sorting in the GUI and TabList
|
||||
# In GUI : the larger is displayed at the back
|
||||
# At TabList : the larger is displayed at the top
|
||||
weight: 1
|
||||
|
||||
# Permission [Unnecessary]
|
||||
# If there is no permission for detection, everyone can use it,
|
||||
# which means there is no need to configure "itemNoPermission"
|
||||
# (because it is impossible to display items without permission at all)
|
||||
permission: "yc.vip"
|
||||
|
||||
# itemHasPermission [Necessary]
|
||||
# This Item will be displayed when player has permission
|
||||
itemHasPermission:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP Prefix"
|
||||
lore:
|
||||
- ""
|
||||
- "§a➥ Click to use"
|
||||
|
||||
# itemUsing [Unnecessary]
|
||||
# This Item will be displayed when the prefix is selected.
|
||||
# If there is no such configuration, it will automatically display "itemHasPermission".
|
||||
itemUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP Prefix"
|
||||
enchants:
|
||||
PROTECTION_ENVIRONMENTAL: 1 #Add an enchantment so it looks like it’s selected
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ Selected"
|
||||
|
||||
# itemNoPermission [Unnecessary]
|
||||
# If player doesn't have the permission,this item will be displayed.
|
||||
# If this item is not configured, it will not be displayed in the GUI when the player does not have permission to use it.
|
||||
itemNoPermission:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: INK_SACK
|
||||
damage: 8
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP §c(Buy it!)"
|
||||
lore:
|
||||
- ""
|
||||
- "§e✯ Buy the VIP to use it!"
|
||||
```
|
||||
|
||||
## Support and Donation
|
||||
|
||||
This project is support by the [YourCraft(你的世界)](https://www.ycraft.cn) .
|
||||

|
||||
|
||||
## Open source agreement
|
||||
|
||||
The source code of this project uses [GNU General Public License v3.0](https://opensource.org/licenses/GPL-3.0)
|
||||
License.
|
||||
|
||||
@@ -1,8 +1,33 @@
|
||||

|
||||
|
||||
# 用户前缀系统插件
|
||||
|
||||
[](https://www.codefactor.io/repository/github/carmjos/userprefix)
|
||||

|
||||
[](https://opensource.org/licenses/GPL-3.0)
|
||||
[](https://github.com/CarmJos/UserPrefix/actions/workflows/maven.yml)
|
||||

|
||||

|
||||
|
||||
轻便、高效、实时的用户前缀系统。
|
||||
|
||||
数据部分基于 [LuckPerms](https://www.spigotmc.org/resources/luckperms.28140/) 实现。
|
||||
本插件基于Spigot实现,**理论上支持全版本**。
|
||||
|
||||
本插件已在 [MCBBS](https://www.mcbbs.net/forum.php?mod=viewthread&tid=1261503) 与 [SpigotMC](https://www.spigotmc.org/resources/userprefix-hex-color-support-all-version.96277/) 上发布。
|
||||
|
||||
The English version of the introduction is [here](https://github.com/CarmJos/UserPrefix/blob/master/README-en.md).
|
||||
|
||||
## 示例
|
||||
|
||||

|
||||
|
||||
## 依赖
|
||||
|
||||
- **[必须]** 插件本体基于 [Spigot-API](https://hub.spigotmc.org/stash/projects/SPIGOT)、[BukkitAPI](http://bukkit.org/) 实现。
|
||||
- **[必须]** 数据部分基于 [LuckPerms](https://www.spigotmc.org/resources/luckperms.28140/) 实现。
|
||||
- **[推荐]** 变量部分基于 [PlaceholderAPI](https://www.spigotmc.org/resources/6245/) 实现。
|
||||
|
||||
详细依赖列表可见 [Dependencies](https://github.com/CarmJos/UserPrefix/network/dependencies) 。
|
||||
|
||||
## 特性
|
||||
|
||||
@@ -11,12 +36,14 @@
|
||||
- 当玩家权限变更时会实时监测前缀,若权限不足则自动更换前缀并提示!
|
||||
- 可配置的声音、消息!
|
||||
- 前缀图标可配置“选中”、“有权限”与“无权限”三种状态的物品
|
||||
- 物品的配置通过ItemStack原生配置,支持MC所有的设定!
|
||||
- 具体的设定请参考其他文档哦~
|
||||
- 物品的配置通过ItemStack原生配置,支持MC所有的设定!
|
||||
- 具体的设定请参考其他文档哦~
|
||||
- TabList自动按照前缀的权重排序 (如有冲突可关掉)
|
||||
- 玩家头顶前缀显示 (如有冲突可关掉)
|
||||
- 自动排序,且可翻页的GUI
|
||||
- 支持PlaceholderAPI变量
|
||||
- 自动排序,且可翻页的GUI!
|
||||
- 支持PlaceholderAPI变量!(凡支持的都可以使用,如BungeeTabListPlus)
|
||||
- 支持Hex颜色!(1.16以上版本) 格式 `&(#颜色代码)`
|
||||
- 示例: LightSlateBlue `&(#8470FF)` 、 DarkSlateBlue `&(#483D8B)`
|
||||
|
||||
## 注意事项
|
||||
|
||||
@@ -33,7 +60,8 @@
|
||||
如有冲突导致其他插件的计分板无法显示,请关掉配置文件中`functions.OnNamePrefix`。
|
||||
|
||||
### 3. 物品图标配置问题
|
||||
物品相关均通过Bukkit提供的ItemStack序列化方法读取,相关配置方式请参考其他文档。
|
||||
|
||||
物品相关均通过Bukkit提供的ItemStack序列化方法读取,相关配置方式请参考[ItemStack Serialization(物品序列化)](https://www.spigotmc.org/wiki/itemstack-serialization/)。
|
||||
|
||||
## 指令
|
||||
|
||||
@@ -67,6 +95,8 @@
|
||||
|
||||
## 配置文件示例
|
||||
|
||||
### [基础配置文件](https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/config.yml) (config.yml)
|
||||
|
||||
```yaml
|
||||
version: 1.0.0-SNAPSHOT # 配置文件版本,一般不会动。
|
||||
|
||||
@@ -75,17 +105,42 @@ debug: false #debug输出,开发者用的
|
||||
functions:
|
||||
OnNamePrefix: true # 是否给头顶上添加前缀,该方法用到了头顶的那个计分板,如有冲突请关掉哦~
|
||||
autoUsePrefix: true # 自动前缀显示 当玩家没有自己选择一个前缀的时候,会自动使用所拥有的的前缀中权重最高的那一个
|
||||
chat:
|
||||
# 聊天功能
|
||||
# - 我不推荐使用本插件的聊天功能,而是建议使用其他的聊天插件。
|
||||
# - 本插件仅仅提供了**最基本**的格式变量支持,不包含其他任何功能。
|
||||
# - 注意聊天格式需要遵守Bukkit原格式,即不得缺失 “%1$s” 和 “%2$s” 。
|
||||
# - 本插件的聊天功能不影响其他插件对聊天事件的操作。
|
||||
enable: false # 是否启用
|
||||
format: "<%UserPrefix_prefix%%1$s> %2$s" #聊天的格式,注意 “%1$s” 和 “%2$s” 不可缺少,分别代表 玩家名 与 消息内容 。
|
||||
|
||||
messages:
|
||||
selected:
|
||||
- "&7您选择了 &f%(name) &7作为当前显示的前缀。"
|
||||
expired:
|
||||
- "&7您先前使用的前缀 &f%(oldName) &7已到期。"
|
||||
- "&7现在已为您重新调整为 &f%(newName) &7。"
|
||||
help:
|
||||
- "&7输入 &b/prefix &7打开前缀选择菜单。"
|
||||
GUI:
|
||||
title: "&f&l我的前缀 &8| 列表"
|
||||
items:
|
||||
# 【必须】 GUI中可能存在的其他物品
|
||||
next-page: # 下一页物品,如果没有下一页则不显示
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: ARROW
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§f下一页"
|
||||
lore:
|
||||
- ""
|
||||
- "§f右键可前往最后一页哦~"
|
||||
previous-page: # 上一页物品,如果没有上一页则不显示
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: ARROW
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§f上一页"
|
||||
lore:
|
||||
- ""
|
||||
- "§f右键可前往第一页哦~"
|
||||
|
||||
Sounds: #相关的声音,注释掉则不播放声音 格式为 【声音名:音量:音调】 或 【声音名:音量】 或 【声音名】
|
||||
Sounds: #相关的声音,注释掉则不播放声音
|
||||
# 格式为 【声音名:音量:音调】 或 【声音名:音量】 或 【声音名】
|
||||
openGUI: "BLOCK_NOTE_BLOCK_PLING:1:1"
|
||||
guiClick: "UI_BUTTON_CLICK"
|
||||
prefixChange: "ENTITY_VILLAGER_YES"
|
||||
@@ -116,60 +171,129 @@ defaultPrefix:
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ 您正在使用该前缀"
|
||||
```
|
||||
|
||||
### [消息配置文件](https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/messages.yml) (messages.yml)
|
||||
```yaml
|
||||
selected:
|
||||
- "&7您选择了 &f%(name) &7作为当前显示的前缀。"
|
||||
expired:
|
||||
- "&7您先前使用的前缀 &f%(oldName) &7已到期。"
|
||||
- "&7现在已为您重新调整为 &f%(newName) &7。"
|
||||
reload:
|
||||
- "&a&l重载完成!&7共耗时 &f%(time)ms&7。"
|
||||
help:
|
||||
- "&3&l用户前缀系统 &f帮助"
|
||||
- "&8#/upa&f list"
|
||||
- "&8- &7查看当前前缀列表。"
|
||||
- "&8#/upa&f reload"
|
||||
- "&8- &7重载前缀配置。"
|
||||
list-title:
|
||||
- "&3&l用户前缀系统 &f前缀列表"
|
||||
list-value:
|
||||
- "&8#%(weight) &f%(identifier)"
|
||||
- "&8- &7显示名 &r%(name) &7权限 &r%(permission)"
|
||||
- "&8- &7内容示例&r %(content) %(sender_name)"
|
||||
```
|
||||
|
||||
### [前缀配置文件](https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/prefixes/example-prefix.yml) (prefixes/*.yml)
|
||||
所有前缀均为单独的配置文件,存放于 `插件配置目录/prefixes` 下,便于管理。
|
||||
|
||||
文件名理论上可以随便取,推荐使用英文,部分符号可能会影响正常读取,请避免使用。
|
||||
|
||||
```yaml
|
||||
# 唯一标识 [必须]
|
||||
# 将用于记录玩家所选的前缀,以及用于数据的缓存。
|
||||
# 必须 必须 必须 保持唯一!
|
||||
identifier: "pro"
|
||||
|
||||
# 名字 [必须]
|
||||
# 切换的时候左下角会弹提示 用的就是这个名字
|
||||
name: "&b&lPro&b"
|
||||
|
||||
# 内容 [必须]
|
||||
# 显示在名字前面的内容
|
||||
content: "§b§lPro §b"
|
||||
|
||||
# 权重 [必须]
|
||||
# 用于GUI、TabList的排序和自动前缀显示
|
||||
# 在GUI中,权重越高的会显示在越后面
|
||||
# 在TabList中,权重越高的会显示在越上面
|
||||
weight: 1
|
||||
|
||||
# 检测的权限 [非必须]
|
||||
# 如果没有就是人人都能用,也代表不用配置“itemNoPermission”了(因为压根不可能显示没权限时候的物品)
|
||||
permission: "yc.pro"
|
||||
|
||||
# 有权限时显示的物品 [必须]
|
||||
# 当用户有权限且未选中时,会显示该物品
|
||||
itemHasPermission: #
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro §b会员前缀"
|
||||
lore:
|
||||
- "§7Pro会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- ""
|
||||
- "§a➥ 点击切换到该前缀"
|
||||
|
||||
# 正在使用时显示的物品 [非必需]
|
||||
# 当用户正在使用时会显示这个物品,不配置即自动加载“itemHasPermission”
|
||||
itemUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro §b会员前缀"
|
||||
enchants:
|
||||
PROTECTION_ENVIRONMENTAL: 1 #加一个附魔这样看上去就像是选中了的
|
||||
lore:
|
||||
- "§7Pro会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- ""
|
||||
- "§a✔ 您正在使用该前缀"
|
||||
|
||||
# 没有权限时显示的物品 [非必需]
|
||||
# 如果没有权限就会显示这个item。如果不配置该物品,则玩家没有使用权限时不会显示在GUI里面。
|
||||
itemNoPermission:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: INK_SACK
|
||||
damage: 8
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro+ §b会员前缀 §c(未拥有)"
|
||||
lore:
|
||||
- "§7Pro+会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- "§f您可以输入 §b/vip §f指令查看详细特权!"
|
||||
- ""
|
||||
- "§e✯ 加入Pro+会员以使用该前缀!"
|
||||
```
|
||||
|
||||
|
||||
## 支持与捐赠
|
||||
|
||||
本项目由 [YourCraft(你的世界)](https://www.ycraft.cn) 团队提供长期支持与维护。
|
||||

|
||||
|
||||
若您觉得本插件做的不错,您可以捐赠支持我!
|
||||
|
||||
感谢您成为开源项目的支持者!
|
||||
|
||||
<img height=25% width=25% src="https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/PAY.jpg" />
|
||||
|
||||
## 开源协议
|
||||
|
||||
本项目源码采用 [GNU General Public License v3.0](https://opensource.org/licenses/GPL-3.0) 开源协议。
|
||||
|
||||
prefixes:
|
||||
VIP:
|
||||
name: "&b&lPro&b" # [必须] 名字(切换的时候左下角会弹提示 用的就是这个名字)
|
||||
content: "§b§lPro §b" # [必须] 显示在名字前面的内容
|
||||
weight: 1 # [必须] 权重,用于GUI里面的排序(越大显示在越后面)和自动前缀显示
|
||||
permission: "yc.pro" # [非必须] 检测的权限,如果没有就是人人都能用,也代表不用配置“itemNoPermission”了(因为压根不可能显示没权限时候的物品)
|
||||
itemHasPermission:
|
||||
# [必须] 当有权限的时候会显示这个Item
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro §b会员前缀"
|
||||
lore:
|
||||
- "§7Pro会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- ""
|
||||
- "§a➥ 点击切换到该前缀"
|
||||
itemUsing:
|
||||
# [非必需] 当有权限的时候会显示这个Item,如果没有这个配置就自动显示“itemHasPermission”的。
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro §b会员前缀"
|
||||
enchants:
|
||||
PROTECTION_ENVIRONMENTAL: 1 #加一个附魔这样看上去就像是选中了的
|
||||
lore:
|
||||
- "§7Pro会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- ""
|
||||
- "§a✔ 您正在使用该前缀"
|
||||
itemNoPermission:
|
||||
# [非必需] 如果没有权限就会显示这个item。如果不配置该物品,则玩家没有使用权限时不会显示在GUI里面。
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: INK_SACK
|
||||
damage: 8
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro+ §b会员前缀 §c(未拥有)"
|
||||
lore:
|
||||
- "§7Pro+会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- "§f您可以输入 §b/vip §f指令查看详细特权!"
|
||||
- ""
|
||||
- "§e✯ 加入Pro+会员以使用该前缀!"
|
||||
```
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
@@ -0,0 +1,5 @@
|
||||
# 图片文件夹
|
||||
|
||||
用于存放相关介绍图片。
|
||||
|
||||
图片保留版权,未经授权禁止使用。
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 723 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 212 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 920 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>cc.carm.plugin</groupId>
|
||||
<artifactId>UserPrefix</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>2.1.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
@@ -19,14 +19,34 @@
|
||||
<repositories>
|
||||
|
||||
<repository>
|
||||
<id>ycraft</id>
|
||||
<url>https://maven.ycraft.cn/repository/maven-public/</url>
|
||||
<id>spigotmc-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/public/</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<id>placeholder-api-repo</id>
|
||||
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<id>lss233-repo</id>
|
||||
<url>https://lss233.littleservice.cn/repositories/minecraft</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<id>oss-repo</id>
|
||||
<url>https://oss.sonatype.org/content/groups/public/</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<id>luck-repo</id>
|
||||
<url>https://repo.lucko.me/</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<id>maven-central</id>
|
||||
<url>https://repo1.maven.org/maven2/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
@@ -52,20 +72,6 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<version>4.5.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.comphenix.packetwrapper</groupId>
|
||||
<artifactId>PacketWrapper</artifactId>
|
||||
<version>1.13-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
||||
@@ -4,13 +4,16 @@ import cc.carm.plugin.userprefix.command.UserPrefixAdminCommand;
|
||||
import cc.carm.plugin.userprefix.command.UserPrefixCommand;
|
||||
import cc.carm.plugin.userprefix.configuration.PrefixConfig;
|
||||
import cc.carm.plugin.userprefix.hooker.UserPrefixExpansion;
|
||||
import cc.carm.plugin.userprefix.listener.ChatListener;
|
||||
import cc.carm.plugin.userprefix.listener.UserListener;
|
||||
import cc.carm.plugin.userprefix.listener.processor.UserNodeUpdateProcessor;
|
||||
import cc.carm.plugin.userprefix.manager.ServiceManager;
|
||||
import net.luckperms.api.event.user.UserDataRecalculateEvent;
|
||||
import cc.carm.plugin.userprefix.manager.ConfigManager;
|
||||
import cc.carm.plugin.userprefix.manager.PrefixManager;
|
||||
import cc.carm.plugin.userprefix.manager.ServiceManager;
|
||||
import cc.carm.plugin.userprefix.manager.UserManager;
|
||||
import cc.carm.plugin.userprefix.util.ColorParser;
|
||||
import cc.carm.plugin.userprefix.util.MessageUtil;
|
||||
import net.luckperms.api.event.user.UserDataRecalculateEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
@@ -36,17 +39,26 @@ public class Main extends JavaPlugin {
|
||||
|
||||
log("注册监听器...");
|
||||
regListener(new UserListener());
|
||||
regListener(new ChatListener());
|
||||
ServiceManager.getService().getEventBus().subscribe(this, UserDataRecalculateEvent.class, UserNodeUpdateProcessor::process);
|
||||
|
||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
||||
if (MessageUtil.hasPlaceholderAPI()) {
|
||||
log("注册变量...");
|
||||
new UserPrefixExpansion(getInstance()).register();
|
||||
} else {
|
||||
log("未安装 PlaceholderAPI 放弃注册变量...");
|
||||
log("未安装 PlaceholderAPI 不进行变量注册...");
|
||||
log("若您想使用变量进行前缀的显示,请安装PlaceholderAPI!");
|
||||
}
|
||||
|
||||
|
||||
log("加载完成 ,共耗时 " + (System.currentTimeMillis() - startTime) + " ms 。");
|
||||
|
||||
showAD();
|
||||
|
||||
if (Bukkit.getOnlinePlayers().size() > 0) {
|
||||
Bukkit.getOnlinePlayers().forEach(UserManager::initPlayer); // 适配热重载
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,6 +70,9 @@ public class Main extends JavaPlugin {
|
||||
Bukkit.getServicesManager().unregisterAll(this);
|
||||
|
||||
log("卸载完成 ,共耗时 " + (System.currentTimeMillis() - startTime) + " ms 。");
|
||||
|
||||
showAD();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,12 +85,12 @@ public class Main extends JavaPlugin {
|
||||
}
|
||||
|
||||
public static void log(String message) {
|
||||
Bukkit.getConsoleSender().sendMessage(ColorParser.parseColor("[" + getInstance().getName() + "] " + message));
|
||||
Bukkit.getConsoleSender().sendMessage(ColorParser.parse("[" + getInstance().getName() + "] " + message));
|
||||
}
|
||||
|
||||
public static void debug(String message) {
|
||||
if (PrefixConfig.DEBUG.get()) {
|
||||
log("[DEBUG] " + ColorParser.parseColor(message));
|
||||
log("[DEBUG] " + message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,4 +98,9 @@ public class Main extends JavaPlugin {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void showAD() {
|
||||
log("&7感谢您使用 &3&lUserPrefix " + getDescription().getVersion() + "&7!");
|
||||
log("&7本插件由 &b&lYourCraft &7提供长期支持与维护。");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package cc.carm.plugin.userprefix.command;
|
||||
|
||||
import cc.carm.plugin.userprefix.ui.PrefixSelectGUI;
|
||||
import cc.carm.plugin.userprefix.configuration.PrefixConfig;
|
||||
import cc.carm.plugin.userprefix.manager.ConfigManager;
|
||||
import cc.carm.plugin.userprefix.manager.PrefixManager;
|
||||
import cc.carm.plugin.userprefix.manager.UserManager;
|
||||
import cc.carm.plugin.userprefix.model.ConfiguredPrefix;
|
||||
import cc.carm.plugin.userprefix.util.ColorParser;
|
||||
import cc.carm.plugin.userprefix.ui.PrefixSelectGUI;
|
||||
import cc.carm.plugin.userprefix.util.MessageUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
@@ -20,17 +22,28 @@ public class UserPrefixAdminCommand implements CommandExecutor {
|
||||
if (args.length == 1) {
|
||||
String aim = args[0];
|
||||
if (aim.equalsIgnoreCase("list")) {
|
||||
sender.sendMessage(ColorParser.parseColor("&3&l用户前缀系统 &f前缀列表"));
|
||||
MessageUtil.sendWithPlaceholders(sender, PrefixConfig.Messages.LIST_TITLE.get());
|
||||
for (ConfiguredPrefix value : PrefixManager.getPrefixes().values()) {
|
||||
sender.sendMessage(ColorParser.parseColor("&8#" + value.getWeight() + " &f" + value.getIdentifier()));
|
||||
sender.sendMessage(ColorParser.parseColor("&8- &7显示名 &r" + value.getName() + " &7权限&r " + value.getPermission()));
|
||||
sender.sendMessage(ColorParser.parseColor("&8- &7内容示例&r " + value.getContent() + sender.getName()));
|
||||
MessageUtil.sendWithPlaceholders(
|
||||
sender, PrefixConfig.Messages.LIST_VALUE.get(),
|
||||
new String[]{
|
||||
"%(weight)", "%(identifier)",
|
||||
"%(name)", "%(permission)",
|
||||
"%(content)", "%(sender_name)"
|
||||
},
|
||||
new Object[]{
|
||||
value.getWeight(), value.getIdentifier(),
|
||||
value.getName(), value.getPermission(),
|
||||
value.getContent(), sender.getName()
|
||||
}
|
||||
);
|
||||
}
|
||||
return true;
|
||||
} else if (aim.equalsIgnoreCase("reload")) {
|
||||
long s1 = System.currentTimeMillis();
|
||||
PrefixSelectGUI.closeAll(); // 关掉所有正在显示的前缀列表
|
||||
PrefixManager.loadConfiguredPrefixes(); //重载配置文件
|
||||
ConfigManager.reload(); // 重载配置文件
|
||||
PrefixManager.loadPrefixes(); //加载重载后了的前缀配置
|
||||
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
|
||||
UserManager.checkPrefix(onlinePlayer, false);
|
||||
/*
|
||||
@@ -40,7 +53,10 @@ public class UserPrefixAdminCommand implements CommandExecutor {
|
||||
*/
|
||||
UserManager.updatePrefixView(onlinePlayer, false);
|
||||
}
|
||||
sender.sendMessage(ColorParser.parseColor("&a&l重载完成!&7共耗时 &f" + (System.currentTimeMillis() - s1) + " ms&7。"));
|
||||
MessageUtil.sendWithPlaceholders(
|
||||
sender, PrefixConfig.Messages.RELOAD.get(),
|
||||
new String[]{"%(time)"}, new Object[]{(System.currentTimeMillis() - s1)}
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return help(sender);
|
||||
@@ -49,11 +65,7 @@ public class UserPrefixAdminCommand implements CommandExecutor {
|
||||
}
|
||||
|
||||
public static boolean help(CommandSender sender) {
|
||||
sender.sendMessage(ColorParser.parseColor("&3&l用户前缀系统 &f帮助"));
|
||||
sender.sendMessage(ColorParser.parseColor("&8#&f list"));
|
||||
sender.sendMessage(ColorParser.parseColor("&8- &7查看当前前缀列表。"));
|
||||
sender.sendMessage(ColorParser.parseColor("&8#&f reload"));
|
||||
sender.sendMessage(ColorParser.parseColor("&8- &7重载前缀配置。"));
|
||||
MessageUtil.send(sender, PrefixConfig.Messages.HELP.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package cc.carm.plugin.userprefix.configuration;
|
||||
|
||||
import cc.carm.plugin.userprefix.configuration.message.ConfigMessageList;
|
||||
import cc.carm.plugin.userprefix.configuration.values.ConfigSound;
|
||||
import cc.carm.plugin.userprefix.configuration.values.ConfigValue;
|
||||
import cc.carm.plugin.userprefix.configuration.values.ConfigValueList;
|
||||
import cc.carm.plugin.userprefix.util.ItemStackFactory;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class PrefixConfig {
|
||||
|
||||
@@ -13,15 +16,48 @@ public class PrefixConfig {
|
||||
public static ConfigValue<Boolean> NAME_PREFIX = new ConfigValue<>("functions.OnNamePrefix", Boolean.class, true);
|
||||
public static ConfigValue<Boolean> AUTO_USE = new ConfigValue<>("functions.autoUsePrefix", Boolean.class, true);
|
||||
|
||||
public static class Chat {
|
||||
|
||||
public static ConfigValue<Boolean> ENABLE = new ConfigValue<>("functions.chat.enable", Boolean.class, false);
|
||||
public static ConfigValue<String> FORMAT = new ConfigValue<>("functions.chat.format", String.class, "<%1$s> %2$s");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class GUI {
|
||||
|
||||
public static ConfigValue<String> TITLE = new ConfigValue<>("GUI.title", String.class, "&f&l我的前缀 &8| 列表");
|
||||
|
||||
public static class Items {
|
||||
|
||||
public static ConfigValue<ItemStack> NEXT_PAGE = new ConfigValue<>("GUI.items.next-page", ItemStack.class,
|
||||
new ItemStackFactory(Material.ARROW)
|
||||
.setDisplayName("下一页")
|
||||
.addLore("&7&o右键可前往最后一页哦")
|
||||
.toItemStack()
|
||||
);
|
||||
public static ConfigValue<ItemStack> PREVIOUS_PAGE = new ConfigValue<>("GUI.items.previous-page", ItemStack.class,
|
||||
new ItemStackFactory(Material.ARROW)
|
||||
.setDisplayName("上一页")
|
||||
.addLore("&7&o右键可前往第一页哦")
|
||||
.toItemStack()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Messages {
|
||||
|
||||
public static ConfigValueList<String> SELECTED = new ConfigValueList<>("messages.selected", String.class);
|
||||
public static ConfigValueList<String> EXPIRED = new ConfigValueList<>("messages.expired", String.class);
|
||||
public static ConfigValueList<String> HELP = new ConfigValueList<>("messages.help", String.class);
|
||||
public static ConfigMessageList SELECTED = new ConfigMessageList("selected");
|
||||
public static ConfigMessageList EXPIRED = new ConfigMessageList("expired");
|
||||
|
||||
public static ConfigMessageList RELOAD = new ConfigMessageList("reload");
|
||||
public static ConfigMessageList HELP = new ConfigMessageList("help");
|
||||
|
||||
public static ConfigMessageList LIST_TITLE = new ConfigMessageList("list-title");
|
||||
public static ConfigMessageList LIST_VALUE = new ConfigMessageList("list-value");
|
||||
}
|
||||
|
||||
public static class Sounds {
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package cc.carm.plugin.userprefix.configuration.file;
|
||||
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class FileConfig {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
|
||||
private final String fileName;
|
||||
|
||||
private File file;
|
||||
private FileConfiguration config;
|
||||
|
||||
public FileConfig(final JavaPlugin plugin) {
|
||||
this(plugin, "config.yml");
|
||||
}
|
||||
|
||||
public FileConfig(final JavaPlugin plugin, final String name) {
|
||||
this.plugin = plugin;
|
||||
this.fileName = name;
|
||||
initFile();
|
||||
}
|
||||
|
||||
private void initFile() {
|
||||
this.file = new File(plugin.getDataFolder(), fileName);
|
||||
if (!this.file.exists()) {
|
||||
if (!this.file.getParentFile().exists()) {
|
||||
this.file.getParentFile().mkdirs();
|
||||
}
|
||||
plugin.saveResource(fileName, true);
|
||||
}
|
||||
this.config = YamlConfiguration.loadConfiguration(this.file);
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public FileConfiguration getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void save() {
|
||||
try {
|
||||
getConfig().save(getFile());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
if (getFile().exists()) {
|
||||
this.config = YamlConfiguration.loadConfiguration(getFile());
|
||||
} else {
|
||||
initFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cc.carm.plugin.userprefix.configuration.message;
|
||||
|
||||
import cc.carm.plugin.userprefix.configuration.values.ConfigValue;
|
||||
import cc.carm.plugin.userprefix.manager.ConfigManager;
|
||||
import cc.carm.plugin.userprefix.util.MessageUtil;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ConfigMessage extends ConfigValue<String> {
|
||||
|
||||
public ConfigMessage(String configSection) {
|
||||
this(configSection, null);
|
||||
}
|
||||
|
||||
public ConfigMessage(String configSection, String defaultValue) {
|
||||
super(ConfigManager.getMessageConfig(), configSection, String.class, defaultValue);
|
||||
}
|
||||
|
||||
public void send(CommandSender sender) {
|
||||
MessageUtil.send(sender, get());
|
||||
}
|
||||
|
||||
public void sendWithPlaceholders(CommandSender sender) {
|
||||
MessageUtil.sendWithPlaceholders(sender, get());
|
||||
}
|
||||
|
||||
public void sendWithPlaceholders(CommandSender sender, String[] params, Object[] values) {
|
||||
MessageUtil.sendWithPlaceholders(sender, Arrays.asList(get()), params, values);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cc.carm.plugin.userprefix.configuration.message;
|
||||
|
||||
import cc.carm.plugin.userprefix.configuration.values.ConfigValueList;
|
||||
import cc.carm.plugin.userprefix.manager.ConfigManager;
|
||||
import cc.carm.plugin.userprefix.util.MessageUtil;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class ConfigMessageList extends ConfigValueList<String> {
|
||||
|
||||
public ConfigMessageList(String configSection) {
|
||||
super(ConfigManager.getMessageConfig(), configSection, String.class);
|
||||
}
|
||||
|
||||
public ConfigMessageList(String configSection, String[] defaultValue) {
|
||||
super(ConfigManager.getMessageConfig(), configSection, String.class, defaultValue);
|
||||
}
|
||||
|
||||
public void send(CommandSender sender) {
|
||||
MessageUtil.send(sender, get());
|
||||
}
|
||||
|
||||
public void sendWithPlaceholders(CommandSender sender) {
|
||||
MessageUtil.sendWithPlaceholders(sender, get());
|
||||
}
|
||||
|
||||
public void sendWithPlaceholders(CommandSender sender, String[] params, Object[] values) {
|
||||
MessageUtil.sendWithPlaceholders(sender, get(), params, values);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
package cc.carm.plugin.userprefix.configuration.values;
|
||||
|
||||
import cc.carm.plugin.userprefix.Main;
|
||||
import cc.carm.plugin.userprefix.configuration.file.FileConfig;
|
||||
import cc.carm.plugin.userprefix.manager.ConfigManager;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class ConfigSound {
|
||||
FileConfiguration source;
|
||||
|
||||
|
||||
FileConfig source;
|
||||
String configSection;
|
||||
|
||||
Sound defaultValue;
|
||||
@@ -17,18 +20,26 @@ public class ConfigSound {
|
||||
}
|
||||
|
||||
public ConfigSound(String configSection, Sound defaultValue) {
|
||||
this.source = ConfigManager.getConfig();
|
||||
this(ConfigManager.getPluginConfig(), configSection, defaultValue);
|
||||
}
|
||||
|
||||
public ConfigSound(FileConfig source, String configSection, Sound defaultValue) {
|
||||
this.source = source;
|
||||
this.configSection = configSection;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public FileConfiguration getConfiguration() {
|
||||
return this.source.getConfig();
|
||||
}
|
||||
|
||||
public void set(Sound value, float volume) {
|
||||
this.source.set(this.configSection, value.name() + ":" + volume);
|
||||
getConfiguration().set(this.configSection, value.name() + ":" + volume);
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void set(Sound value, float volume, float pitch) {
|
||||
this.source.set(this.configSection, value.name() + ":" + volume + ":" + pitch);
|
||||
getConfiguration().set(this.configSection, value.name() + ":" + volume + ":" + pitch);
|
||||
this.save();
|
||||
}
|
||||
|
||||
@@ -36,7 +47,7 @@ public class ConfigSound {
|
||||
Sound finalSound = defaultValue;
|
||||
float pitch = 1;
|
||||
float volume = 1;
|
||||
String soundString = this.source.getString(this.configSection);
|
||||
String soundString = getConfiguration().getString(this.configSection);
|
||||
if (soundString != null) {
|
||||
String[] args = soundString.contains(":") ? soundString.split(":") : new String[]{soundString};
|
||||
try {
|
||||
@@ -54,7 +65,7 @@ public class ConfigSound {
|
||||
}
|
||||
|
||||
public void save() {
|
||||
ConfigManager.saveConfig();
|
||||
this.source.save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package cc.carm.plugin.userprefix.configuration.values;
|
||||
|
||||
import cc.carm.plugin.userprefix.configuration.file.FileConfig;
|
||||
import cc.carm.plugin.userprefix.manager.ConfigManager;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
|
||||
public class ConfigValue<V> {
|
||||
FileConfiguration source;
|
||||
|
||||
FileConfig source;
|
||||
|
||||
String configSection;
|
||||
Class<V> clazz;
|
||||
V defaultValue;
|
||||
@@ -14,24 +17,32 @@ public class ConfigValue<V> {
|
||||
}
|
||||
|
||||
public ConfigValue(String configSection, Class<V> clazz, V defaultValue) {
|
||||
this.source = ConfigManager.getConfig();
|
||||
this(ConfigManager.getPluginConfig(), configSection, clazz, defaultValue);
|
||||
}
|
||||
|
||||
public ConfigValue(FileConfig source, String configSection, Class<V> clazz, V defaultValue) {
|
||||
this.source = source;
|
||||
this.configSection = configSection;
|
||||
this.clazz = clazz;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public FileConfiguration getConfiguration() {
|
||||
return this.source.getConfig();
|
||||
}
|
||||
|
||||
public V get() {
|
||||
Object val = this.source.get(this.configSection, this.defaultValue);
|
||||
Object val = getConfiguration().get(this.configSection, this.defaultValue);
|
||||
return this.clazz.isInstance(val) ? this.clazz.cast(val) : this.defaultValue;
|
||||
}
|
||||
|
||||
public void set(V value) {
|
||||
this.source.set(this.configSection, value);
|
||||
getConfiguration().set(this.configSection, value);
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void save() {
|
||||
ConfigManager.saveConfig();
|
||||
this.source.save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,26 +1,52 @@
|
||||
package cc.carm.plugin.userprefix.configuration.values;
|
||||
|
||||
import cc.carm.plugin.userprefix.configuration.file.FileConfig;
|
||||
import cc.carm.plugin.userprefix.manager.ConfigManager;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ConfigValueList<V> {
|
||||
FileConfiguration source;
|
||||
FileConfig source;
|
||||
String configSection;
|
||||
Class<V> clazz;
|
||||
|
||||
V[] defaultValue;
|
||||
|
||||
public ConfigValueList(String configSection, Class<V> clazz) {
|
||||
this.source = ConfigManager.getConfig();
|
||||
this.configSection = configSection;
|
||||
this.clazz = clazz;
|
||||
this(ConfigManager.getPluginConfig(), configSection, clazz);
|
||||
}
|
||||
|
||||
public ConfigValueList(String configSection, Class<V> clazz, V[] defaultValue) {
|
||||
this(ConfigManager.getPluginConfig(), configSection, clazz, defaultValue);
|
||||
}
|
||||
|
||||
public ConfigValueList(FileConfig configuration, String configSection, Class<V> clazz) {
|
||||
this(configuration, configSection, clazz, null);
|
||||
}
|
||||
|
||||
public ConfigValueList(FileConfig configuration, String configSection, Class<V> clazz, V[] defaultValue) {
|
||||
this.source = configuration;
|
||||
this.configSection = configSection;
|
||||
this.clazz = clazz;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public FileConfiguration getConfiguration() {
|
||||
return this.source.getConfig();
|
||||
}
|
||||
|
||||
|
||||
public ArrayList<V> get() {
|
||||
List<?> list = this.source.getList(this.configSection);
|
||||
List<?> list = getConfiguration().getList(this.configSection);
|
||||
if (list == null) {
|
||||
return new ArrayList(0);
|
||||
if (defaultValue != null) {
|
||||
return new ArrayList<>(Arrays.asList(defaultValue));
|
||||
} else {
|
||||
return new ArrayList(0);
|
||||
}
|
||||
} else {
|
||||
ArrayList<V> result = new ArrayList();
|
||||
|
||||
@@ -29,17 +55,17 @@ public class ConfigValueList<V> {
|
||||
result.add(this.clazz.cast(object));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public void set(ArrayList<V> value) {
|
||||
this.source.set(this.configSection, value);
|
||||
getConfiguration().set(this.configSection, value);
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void save() {
|
||||
ConfigManager.saveConfig();
|
||||
this.source.save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package cc.carm.plugin.userprefix.hooker;
|
||||
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import cc.carm.plugin.userprefix.manager.PrefixManager;
|
||||
import cc.carm.plugin.userprefix.manager.UserManager;
|
||||
import cc.carm.plugin.userprefix.model.ConfiguredPrefix;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -36,17 +36,17 @@ public class UserPrefixExpansion extends PlaceholderExpansion {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
public @NotNull String getAuthor() {
|
||||
return plugin.getDescription().getAuthors().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
public @NotNull String getIdentifier() {
|
||||
return "UserPrefix";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
public @NotNull String getVersion() {
|
||||
return plugin.getDescription().getVersion();
|
||||
}
|
||||
|
||||
@@ -82,8 +82,10 @@ public class UserPrefixExpansion extends PlaceholderExpansion {
|
||||
case "version": {
|
||||
return getVersion().replace("-SNAPSHOT", "");
|
||||
}
|
||||
default: {
|
||||
return "参数错误";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package cc.carm.plugin.userprefix.listener;
|
||||
|
||||
import cc.carm.plugin.userprefix.Main;
|
||||
import cc.carm.plugin.userprefix.configuration.PrefixConfig;
|
||||
import cc.carm.plugin.userprefix.util.MessageUtil;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
|
||||
public class ChatListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onChat(AsyncPlayerChatEvent event) {
|
||||
if (!PrefixConfig.Functions.Chat.ENABLE.get()) return;
|
||||
String format = PrefixConfig.Functions.Chat.FORMAT.get();
|
||||
if (format == null || format.length() < 1) return;
|
||||
|
||||
if (!MessageUtil.hasPlaceholderAPI()) return;
|
||||
|
||||
try {
|
||||
event.setFormat(PlaceholderAPI.setPlaceholders(event.getPlayer(), format));
|
||||
} catch (Exception exception) {
|
||||
Main.log("Please check the chat configuration.");
|
||||
Main.log("请检查配置文件中聊天相关是否配置正确。");
|
||||
exception.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
package cc.carm.plugin.userprefix.listener;
|
||||
|
||||
import cc.carm.plugin.userprefix.configuration.PrefixConfig;
|
||||
import cc.carm.plugin.userprefix.manager.UserManager;
|
||||
import cc.carm.plugin.userprefix.ui.PrefixSelectGUI;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
@@ -14,25 +11,13 @@ public class UserListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
UserManager.checkPrefix(player, false);
|
||||
|
||||
|
||||
if (PrefixConfig.Functions.NAME_PREFIX.get()) {
|
||||
UserManager.createNameTag(event.getPlayer());
|
||||
UserManager.updatePrefixView(event.getPlayer(), true);
|
||||
}
|
||||
|
||||
|
||||
UserManager.initPlayer(event.getPlayer());
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void onLeave(PlayerQuitEvent event) {
|
||||
PrefixSelectGUI.removeOpening(event.getPlayer());
|
||||
UserManager.unloadNameTag(event.getPlayer().getUniqueId());
|
||||
UserManager.checkingPlayers.remove(event.getPlayer().getUniqueId());
|
||||
UserManager.unloadPlayer(event.getPlayer());
|
||||
}
|
||||
|
||||
|
||||
|
||||
+8
-15
@@ -1,29 +1,22 @@
|
||||
package cc.carm.plugin.userprefix.listener.processor;
|
||||
|
||||
import net.luckperms.api.event.user.UserDataRecalculateEvent;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import cc.carm.plugin.userprefix.manager.UserManager;
|
||||
import cc.carm.plugin.userprefix.ui.PrefixSelectGUI;
|
||||
import net.luckperms.api.event.user.UserDataRecalculateEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class UserNodeUpdateProcessor {
|
||||
|
||||
// public static void process(NodeRemoveEvent event) {
|
||||
// if (event.getTarget() instanceof User) {
|
||||
// if (!(event.getNode() instanceof PermissionNode)) return;
|
||||
// User user = (User) event.getTarget();
|
||||
// Player player = Bukkit.getPlayer(user.getUniqueId());
|
||||
// if (player == null) return;
|
||||
// UserManager.checkPrefix(player, true);
|
||||
// }
|
||||
// }
|
||||
|
||||
public static void process(UserDataRecalculateEvent event) {
|
||||
User user = event.getUser();
|
||||
Player player = Bukkit.getPlayer(user.getUniqueId());
|
||||
Player player = Bukkit.getPlayer(event.getUser().getUniqueId());
|
||||
if (player == null) return;
|
||||
UserManager.checkPrefix(player, true);
|
||||
|
||||
if (PrefixSelectGUI.openingUsers.contains(player)) {
|
||||
// 玩家权限更新,关闭其GUI,以令其重新打开刷新自己的前缀。
|
||||
player.closeInventory();
|
||||
PrefixSelectGUI.removeOpening(player);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,30 +1,47 @@
|
||||
package cc.carm.plugin.userprefix.manager;
|
||||
|
||||
import cc.carm.plugin.userprefix.Main;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import cc.carm.plugin.userprefix.configuration.file.FileConfig;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class ConfigManager {
|
||||
|
||||
private static FileConfiguration config;
|
||||
private static FileConfig config;
|
||||
private static FileConfig messageConfig;
|
||||
|
||||
|
||||
public static void initConfig() {
|
||||
Main.getInstance().saveDefaultConfig();
|
||||
Main.getInstance().reloadConfig();
|
||||
File configFile = new File(Main.getInstance().getDataFolder(), "config.yml");
|
||||
if (!configFile.exists()) {
|
||||
//没找到配置文件,可能是第一次加载此插件
|
||||
//把一些英文版的东西复制出来,方便英文用户使用。
|
||||
Main.getInstance().saveResource("prefixes/example-prefix.yml", false);
|
||||
Main.getInstance().saveResource("en_US/config.yml", false);
|
||||
Main.getInstance().saveResource("en_US/messages.yml", false);
|
||||
Main.getInstance().saveResource("en_US/example-prefix.yml", false);
|
||||
}
|
||||
|
||||
config = Main.getInstance().getConfig();
|
||||
ConfigManager.config = new FileConfig(Main.getInstance(), "config.yml");
|
||||
ConfigManager.messageConfig = new FileConfig(Main.getInstance(), "messages.yml");
|
||||
}
|
||||
|
||||
public static FileConfiguration getConfig() {
|
||||
public static FileConfig getPluginConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public static void reloadConfig() {
|
||||
Main.getInstance().reloadConfig();
|
||||
config = Main.getInstance().getConfig();
|
||||
public static FileConfig getMessageConfig() {
|
||||
return messageConfig;
|
||||
}
|
||||
|
||||
public static void reload() {
|
||||
getPluginConfig().reload();
|
||||
getMessageConfig().reload();
|
||||
}
|
||||
|
||||
public static void saveConfig() {
|
||||
Main.getInstance().saveConfig();
|
||||
getPluginConfig().save();
|
||||
getMessageConfig().save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,11 @@ import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -19,70 +23,86 @@ public class PrefixManager {
|
||||
public static ConfiguredPrefix defaultPrefix;
|
||||
public static HashMap<String, ConfiguredPrefix> prefixes = new HashMap<>();
|
||||
|
||||
private static final String FOLDER_NAME = "prefixes";
|
||||
|
||||
public static void init() {
|
||||
loadConfiguredPrefixes();
|
||||
loadPrefixes();
|
||||
Main.log("共加载了 " + prefixes.size() + " 个前缀。");
|
||||
}
|
||||
|
||||
public static void loadConfiguredPrefixes() {
|
||||
public static void loadPrefixes() {
|
||||
loadDefaultPrefix();
|
||||
loadConfiguredPrefixes();
|
||||
}
|
||||
|
||||
ConfigurationSection prefixesSection = ConfigManager.getConfig().getConfigurationSection("prefixes");
|
||||
if (prefixesSection == null || prefixesSection.getKeys(false).isEmpty()) {
|
||||
public static void loadConfiguredPrefixes() {
|
||||
|
||||
File prefixDataFolder = new File(Main.getInstance().getDataFolder() + File.separator + FOLDER_NAME);
|
||||
if (!prefixDataFolder.isDirectory() || !prefixDataFolder.exists()) {
|
||||
prefixDataFolder.mkdir();
|
||||
}
|
||||
|
||||
String[] filesList = prefixDataFolder.list();
|
||||
if (filesList == null || filesList.length < 1) {
|
||||
Main.log("配置文件中暂无任何前缀配置,请检查。");
|
||||
Main.log("There's no configured prefix.");
|
||||
return;
|
||||
}
|
||||
List<File> files = Arrays.stream(filesList)
|
||||
.map(s -> new File(prefixDataFolder, s))
|
||||
.filter(File::isFile)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
HashMap<String, ConfiguredPrefix> dataPrefixes = new HashMap<>();
|
||||
for (String prefixIdentifier : prefixesSection.getKeys(false)) {
|
||||
ConfigurationSection configuredPrefixSection = prefixesSection.getConfigurationSection(prefixIdentifier);
|
||||
if (configuredPrefixSection == null) continue;
|
||||
|
||||
String name = configuredPrefixSection.getString("name", "前缀名配置错误");
|
||||
String content = configuredPrefixSection.getString("content", "&r");
|
||||
String permission = configuredPrefixSection.getString("permission");
|
||||
int weight = configuredPrefixSection.getInt("weight", 1);
|
||||
|
||||
ItemStack itemHasPermission = configuredPrefixSection.getItemStack("itemHasPermission",
|
||||
new ItemStackFactory(Material.STONE).setDisplayName(name).addLore(" ").addLore("§a➥ 点击切换到该前缀").toItemStack()
|
||||
);
|
||||
ItemStack itemNoPermission = configuredPrefixSection.getItemStack("itemNoPermission", itemHasPermission);
|
||||
ItemStack itemUsing = configuredPrefixSection.getItemStack("itemUsing", itemHasPermission);
|
||||
|
||||
|
||||
Main.log("完成前缀加载 " + prefixIdentifier + " : " + name);
|
||||
|
||||
dataPrefixes.put(prefixIdentifier, new ConfiguredPrefix(prefixIdentifier, name, content, weight, permission, itemHasPermission, itemNoPermission, itemUsing));
|
||||
if (files.size() > 0) {
|
||||
for (File file : files) {
|
||||
try {
|
||||
ConfiguredPrefix prefix = new ConfiguredPrefix(file);
|
||||
Main.log("完成前缀加载 " + prefix.getIdentifier() + " : " + prefix.getName());
|
||||
dataPrefixes.put(prefix.getIdentifier(), prefix);
|
||||
} catch (Exception ex) {
|
||||
Main.log("Error occurred when loading prefix #" + file.getAbsolutePath() + " !");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prefixes = dataPrefixes;
|
||||
PrefixManager.prefixes.clear();
|
||||
PrefixManager.prefixes = dataPrefixes;
|
||||
}
|
||||
|
||||
public static void loadDefaultPrefix() {
|
||||
ConfigurationSection defaultPrefixSection = ConfigManager.getConfig().getConfigurationSection("defaultPrefix");
|
||||
PrefixManager.defaultPrefix = null;
|
||||
ConfigurationSection defaultPrefixSection = ConfigManager.getPluginConfig().getConfig().getConfigurationSection("defaultPrefix");
|
||||
if (defaultPrefixSection != null) {
|
||||
String name = defaultPrefixSection.getString("name", "默认前缀");
|
||||
String content = defaultPrefixSection.getString("content", "&r");
|
||||
ItemStack itemNotUsing = defaultPrefixSection.getItemStack(
|
||||
"itemNotUsing",
|
||||
new ItemStackFactory(Material.NAME_TAG)
|
||||
.setDisplayName("&f默认前缀")
|
||||
.addLore(" ")
|
||||
.addLore("§a➥ 点击切换到该前缀")
|
||||
.toItemStack()
|
||||
);
|
||||
ItemStack itemUsing = defaultPrefixSection.getItemStack("itemUsing",
|
||||
new ItemStackFactory(Material.NAME_TAG)
|
||||
.setDisplayName("&f默认前缀")
|
||||
.addLore(" ")
|
||||
.addLore("§a✔ 您正在使用该前缀")
|
||||
.addEnchant(Enchantment.DURABILITY, 1, false)
|
||||
.addFlag(ItemFlag.HIDE_ENCHANTS)
|
||||
.toItemStack()
|
||||
);
|
||||
defaultPrefix = new ConfiguredPrefix("default", name, content, 0, null, itemNotUsing, null, itemUsing);
|
||||
try {
|
||||
String name = defaultPrefixSection.getString("name", "默认前缀");
|
||||
String content = defaultPrefixSection.getString("content", "&r");
|
||||
ItemStack itemNotUsing = defaultPrefixSection.getItemStack(
|
||||
"itemNotUsing",
|
||||
new ItemStackFactory(Material.NAME_TAG)
|
||||
.setDisplayName("&f默认前缀")
|
||||
.addLore(" ")
|
||||
.addLore("§a➥ 点击切换到该前缀")
|
||||
.toItemStack()
|
||||
);
|
||||
ItemStack itemUsing = defaultPrefixSection.getItemStack("itemUsing",
|
||||
new ItemStackFactory(Material.NAME_TAG)
|
||||
.setDisplayName("&f默认前缀")
|
||||
.addLore(" ")
|
||||
.addLore("§a✔ 您正在使用该前缀")
|
||||
.addEnchant(Enchantment.DURABILITY, 1, false)
|
||||
.addFlag(ItemFlag.HIDE_ENCHANTS)
|
||||
.toItemStack()
|
||||
);
|
||||
PrefixManager.defaultPrefix = new ConfiguredPrefix("default", name, content, 0, null, itemNotUsing, null, itemUsing);
|
||||
} catch (Exception ex) {
|
||||
Main.log("在加载默认前缀时出错,请检查配置!");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
defaultPrefix = new ConfiguredPrefix("default", "默认前缀", "&r", 0, null,
|
||||
PrefixManager.defaultPrefix = new ConfiguredPrefix("default", "默认前缀", "&r", 0, null,
|
||||
new ItemStackFactory(Material.NAME_TAG)
|
||||
.setDisplayName("&f默认前缀")
|
||||
.addLore(" ")
|
||||
@@ -109,16 +129,21 @@ public class PrefixManager {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ConfiguredPrefix getDefaultPrefix() {
|
||||
return defaultPrefix;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static HashMap<String, ConfiguredPrefix> getPrefixes() {
|
||||
return prefixes;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ConfiguredPrefix getPrefix(String identifier) {
|
||||
if (identifier == null || identifier.equalsIgnoreCase("default")) {
|
||||
if (identifier == null) {
|
||||
return null;
|
||||
} else if (identifier.equalsIgnoreCase("default")) {
|
||||
return getDefaultPrefix();
|
||||
} else {
|
||||
return getPrefixes().get(identifier);
|
||||
|
||||
@@ -4,12 +4,16 @@ import cc.carm.plugin.userprefix.Main;
|
||||
import cc.carm.plugin.userprefix.configuration.PrefixConfig;
|
||||
import cc.carm.plugin.userprefix.model.ConfiguredPrefix;
|
||||
import cc.carm.plugin.userprefix.nametag.UserNameTag;
|
||||
import cc.carm.plugin.userprefix.ui.PrefixSelectGUI;
|
||||
import cc.carm.plugin.userprefix.util.MessageUtil;
|
||||
import cc.carm.plugin.userprefix.util.gui.GUI;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.luckperms.api.node.NodeType;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -30,6 +34,21 @@ public class UserManager {
|
||||
return nameTag;
|
||||
}
|
||||
|
||||
public static void initPlayer(Player player) {
|
||||
UserManager.checkPrefix(player, false);
|
||||
if (PrefixConfig.Functions.NAME_PREFIX.get()) {
|
||||
UserManager.createNameTag(player);
|
||||
UserManager.updatePrefixView(player, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void unloadPlayer(Player player) {
|
||||
PrefixSelectGUI.removeOpening(player);
|
||||
UserManager.unloadNameTag(player.getUniqueId());
|
||||
UserManager.checkingPlayers.remove(player.getUniqueId());
|
||||
GUI.removeOpenedGUI(player); // 清空打开过的GUI缓存 (用于记录物品点击的
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新前缀显示效果
|
||||
*
|
||||
@@ -58,11 +77,9 @@ public class UserManager {
|
||||
|
||||
if (loadOthers) {
|
||||
ConfiguredPrefix onlinePlayerPrefix = UserManager.getPrefix(onlinePlayer);
|
||||
if (onlinePlayerPrefix != null) {
|
||||
tag.setPrefix(onlinePlayer, onlinePlayerPrefix.getContent());
|
||||
tag.setOrder(onlinePlayer, onlinePlayerPrefix.getWeight());
|
||||
Main.debug("为玩家 " + player.getName() + " 设置了 " + player.getName() + "的前缀为 #" + onlinePlayerPrefix.getWeight() + " " + onlinePlayerPrefix.getName());
|
||||
}
|
||||
tag.setPrefix(onlinePlayer, onlinePlayerPrefix.getContent());
|
||||
tag.setOrder(onlinePlayer, onlinePlayerPrefix.getWeight());
|
||||
Main.debug("为玩家 " + player.getName() + " 设置了 " + onlinePlayer.getName() + "的前缀为 #" + onlinePlayerPrefix.getWeight() + " " + onlinePlayerPrefix.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,7 +91,13 @@ public class UserManager {
|
||||
* @param updateView 是否更新头顶与TabList中的前缀
|
||||
*/
|
||||
public static void checkPrefix(Player player, boolean updateView) {
|
||||
if (checkingPlayers.contains(player.getUniqueId())) return;
|
||||
if (checkingPlayers.contains(player.getUniqueId())) {
|
||||
/*
|
||||
* 这里为了避免极短时间内的重复触发导致多次判断且结果相同误导玩家,
|
||||
* 故没有采用同步锁,而是采用添加到一个临时Set中,对Set中玩家跳过判断。
|
||||
*/
|
||||
return;
|
||||
}
|
||||
checkingPlayers.add(player.getUniqueId());
|
||||
String currentPrefixIdentifier = UserManager.getPrefixData(player);
|
||||
ConfiguredPrefix currentPrefix = PrefixManager.getPrefix(currentPrefixIdentifier);
|
||||
@@ -104,12 +127,14 @@ public class UserManager {
|
||||
* @param player 玩家
|
||||
* @return 前缀配置
|
||||
*/
|
||||
@NotNull
|
||||
public static ConfiguredPrefix getPrefix(Player player) {
|
||||
String identifier = getPrefixData(player);
|
||||
if (identifier == null || !isPrefixUsable(player, identifier)) {
|
||||
return getHighestPrefix(player);
|
||||
} else {
|
||||
return PrefixManager.getPrefix(identifier);
|
||||
ConfiguredPrefix prefix = PrefixManager.getPrefix(identifier);
|
||||
return prefix == null ? PrefixManager.getDefaultPrefix() : prefix;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,11 +156,12 @@ public class UserManager {
|
||||
* @param player 玩家
|
||||
* @return 可用前缀列表
|
||||
*/
|
||||
@NotNull
|
||||
public static List<ConfiguredPrefix> getUsablePrefixes(Player player) {
|
||||
return PrefixManager.getPrefixes().values().stream()
|
||||
.filter(configuredPrefix -> isPrefixUsable(player, configuredPrefix))
|
||||
.sorted(Comparator.comparingInt(ConfiguredPrefix::getWeight))
|
||||
.collect(Collectors.toList());
|
||||
.filter(configuredPrefix -> isPrefixUsable(player, configuredPrefix)) //过滤出玩家可用的前缀
|
||||
.sorted(Comparator.comparingInt(ConfiguredPrefix::getWeight)) // 以前缀排序
|
||||
.collect(Collectors.toList()); // 返回集合
|
||||
}
|
||||
|
||||
|
||||
@@ -146,13 +172,15 @@ public class UserManager {
|
||||
* @param player 玩家
|
||||
* @return 权限内容
|
||||
*/
|
||||
@NotNull
|
||||
public static ConfiguredPrefix getHighestPrefix(Player player) {
|
||||
if (PrefixConfig.Functions.AUTO_USE.get()) {
|
||||
// 关闭了自动选择,就直接给默认的前缀,让玩家自己去设置吧
|
||||
// 关闭了自动选择,就直接给默认的前缀,让玩家自己去设置吧~
|
||||
return PrefixManager.getDefaultPrefix();
|
||||
}
|
||||
List<ConfiguredPrefix> prefixes = getUsablePrefixes(player);
|
||||
return prefixes.stream().max(Comparator.comparingInt(ConfiguredPrefix::getWeight)).orElseGet(PrefixManager::getDefaultPrefix);
|
||||
return getUsablePrefixes(player).stream()
|
||||
.max(Comparator.comparingInt(ConfiguredPrefix::getWeight)) // 取权重最大
|
||||
.orElseGet(PrefixManager::getDefaultPrefix); // 啥都没有? 返回默认前缀。
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,7 +205,8 @@ public class UserManager {
|
||||
* @return 若前缀标识不存在,则返回false;若前缀为默认前缀,或该前缀无权限,或玩家有该前缀的权限,则返回true。
|
||||
*/
|
||||
public static boolean isPrefixUsable(Player player, ConfiguredPrefix configuredPrefix) {
|
||||
return configuredPrefix.getPermission() == null || ServiceManager.hasPermission(ServiceManager.getUser(player), configuredPrefix.getPermission());
|
||||
return configuredPrefix.isPublic()
|
||||
|| ServiceManager.hasPermission(ServiceManager.getUser(player), configuredPrefix.getPermission());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,8 +216,11 @@ public class UserManager {
|
||||
* @param player 玩家
|
||||
* @return 正在使用的前缀Identifier(若不存在则返回null)
|
||||
*/
|
||||
@Nullable
|
||||
public static String getPrefixData(Player player) {
|
||||
return ServiceManager.getAPI().getMetaData(player).getMetaValue("userprefix", String::valueOf).orElse(null);
|
||||
return ServiceManager.getAPI().getMetaData(player)
|
||||
.getMetaValue("userprefix", String::valueOf)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,11 +232,11 @@ public class UserManager {
|
||||
*/
|
||||
public static void setPrefixData(Player player, String prefixIdentifier) {
|
||||
User user = ServiceManager.getUser(player);
|
||||
clearPrefixData(player);
|
||||
// LuckPerms竟然会把所有的metaKey全部转换为小写... 那我这里就直接写成小写吧~
|
||||
MetaNode node = MetaNode.builder("userprefix", prefixIdentifier).build();
|
||||
user.data().add(node);
|
||||
ServiceManager.getService().getUserManager().saveUser(user);
|
||||
clearPrefixData(player); // 清除掉旧的数据,LuckPerms不会去覆盖一个Meta,需要手动清除。
|
||||
if (prefixIdentifier != null) {
|
||||
user.data().add(MetaNode.builder("userprefix", prefixIdentifier).build());
|
||||
ServiceManager.getService().getUserManager().saveUser(user); // 保存数据
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
package cc.carm.plugin.userprefix.model;
|
||||
|
||||
import cc.carm.plugin.userprefix.util.ColorParser;
|
||||
import cc.carm.plugin.userprefix.util.ItemStackFactory;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class ConfiguredPrefix {
|
||||
|
||||
@Nullable
|
||||
private File dataFile;
|
||||
@Nullable
|
||||
private FileConfiguration configuration;
|
||||
|
||||
String identifier;
|
||||
|
||||
String name;
|
||||
@@ -18,7 +31,32 @@ public class ConfiguredPrefix {
|
||||
ItemStack itemNoPermission;
|
||||
ItemStack itemWhenUsing;
|
||||
|
||||
public ConfiguredPrefix(String identifier, String name, String content, int weight, String permission, ItemStack itemHasPermission, ItemStack itemNoPermission, ItemStack itemWhenUsing) {
|
||||
|
||||
public ConfiguredPrefix(@NotNull File dataFile) {
|
||||
this.dataFile = dataFile;
|
||||
this.configuration = YamlConfiguration.loadConfiguration(dataFile);
|
||||
if (getConfiguration() != null) {
|
||||
this.identifier = getConfiguration().getString("identifier", "ERROR");
|
||||
this.name = getConfiguration().getString("name", "ERROR");
|
||||
this.content = getConfiguration().getString("content", "&r");
|
||||
this.permission = getConfiguration().getString("permission");
|
||||
this.weight = getConfiguration().getInt("weight", 1);
|
||||
|
||||
this.itemHasPermission = (ItemStack) getConfiguration().get("itemHasPermission",
|
||||
new ItemStackFactory(Material.STONE).setDisplayName(name).addLore(" ").addLore("§a➥ 点击切换到该前缀").toItemStack()
|
||||
);
|
||||
this.itemNoPermission = (ItemStack) getConfiguration().get("itemNoPermission", itemHasPermission);
|
||||
this.itemWhenUsing = (ItemStack) getConfiguration().get("itemUsing", itemHasPermission);
|
||||
}
|
||||
}
|
||||
|
||||
public ConfiguredPrefix(@NotNull String identifier,
|
||||
@NotNull String name,
|
||||
@NotNull String content,
|
||||
int weight, @Nullable String permission,
|
||||
@NotNull ItemStack itemHasPermission,
|
||||
@Nullable ItemStack itemNoPermission,
|
||||
@Nullable ItemStack itemWhenUsing) {
|
||||
this.identifier = identifier;
|
||||
this.name = name;
|
||||
this.content = content;
|
||||
@@ -29,64 +67,52 @@ public class ConfiguredPrefix {
|
||||
this.itemWhenUsing = itemWhenUsing;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public FileConfiguration getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getContent() {
|
||||
return ColorParser.parseColor(content);
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
return ColorParser.parse(content);
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public void setWeight(int weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
public void setPermission(String permission) {
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ItemStack getItemHasPermission() {
|
||||
return itemHasPermission;
|
||||
}
|
||||
|
||||
public void setItemHasPermission(ItemStack itemHasPermission) {
|
||||
this.itemHasPermission = itemHasPermission;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ItemStack getItemNoPermission() {
|
||||
return itemNoPermission;
|
||||
}
|
||||
|
||||
public void setItemNoPermission(ItemStack itemNoPermission) {
|
||||
this.itemNoPermission = itemNoPermission;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ItemStack getItemWhenUsing() {
|
||||
return itemWhenUsing;
|
||||
}
|
||||
|
||||
public void setItemWhenUsing(ItemStack itemWhenUsing) {
|
||||
this.itemWhenUsing = itemWhenUsing;
|
||||
public boolean isPublic() {
|
||||
return getPermission() == null;
|
||||
}
|
||||
|
||||
public boolean isVisibleNoPermission() {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package cc.carm.plugin.userprefix.ui;
|
||||
|
||||
import cc.carm.plugin.userprefix.configuration.PrefixConfig;
|
||||
import cc.carm.plugin.userprefix.util.MessageUtil;
|
||||
import cc.carm.plugin.userprefix.util.gui.GUIType;
|
||||
import cc.carm.plugin.userprefix.manager.PrefixManager;
|
||||
import cc.carm.plugin.userprefix.manager.UserManager;
|
||||
import cc.carm.plugin.userprefix.model.ConfiguredPrefix;
|
||||
import cc.carm.plugin.userprefix.util.MessageUtil;
|
||||
import cc.carm.plugin.userprefix.util.gui.AutoPagedGUI;
|
||||
import cc.carm.plugin.userprefix.util.gui.GUIItem;
|
||||
import cc.carm.plugin.userprefix.util.gui.GUIType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
|
||||
@@ -22,7 +22,7 @@ public class PrefixSelectGUI extends AutoPagedGUI {
|
||||
Player player;
|
||||
|
||||
public PrefixSelectGUI(Player player) {
|
||||
super(GUIType.SIXBYNINE, "&f&l我的前缀 &8| 列表", 10, 43);
|
||||
super(GUIType.SIXBYNINE, PrefixConfig.GUI.TITLE.get(), 10, 43);
|
||||
this.player = player;
|
||||
|
||||
setPreviousPageSlot(18);
|
||||
@@ -38,7 +38,7 @@ public class PrefixSelectGUI extends AutoPagedGUI {
|
||||
public void loadItems() {
|
||||
List<ConfiguredPrefix> prefixList = new ArrayList<>();
|
||||
prefixList.add(PrefixManager.getDefaultPrefix());
|
||||
prefixList.addAll(PrefixManager.getVisiblePrefix());
|
||||
prefixList.addAll(PrefixManager.getVisiblePrefix()); //只需要读取看得见的
|
||||
|
||||
ConfiguredPrefix usingPrefix = UserManager.getPrefix(getPlayer());
|
||||
|
||||
@@ -49,7 +49,8 @@ public class PrefixSelectGUI extends AutoPagedGUI {
|
||||
addItem(new GUIItem(prefix.getItemHasPermission()) {
|
||||
@Override
|
||||
public void onClick(ClickType type) {
|
||||
if (UserManager.isPrefixUsable(player, prefix)) { //再次检查,防止打开GUI后、选择前的时间段内权限消失
|
||||
//再次检查,防止打开GUI后、选择前的时间段内权限消失
|
||||
if (UserManager.isPrefixUsable(player, prefix)) {
|
||||
player.closeInventory();
|
||||
UserManager.setPrefix(player, prefix, true);
|
||||
|
||||
@@ -71,7 +72,7 @@ public class PrefixSelectGUI extends AutoPagedGUI {
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
openingUsers.remove(player);
|
||||
removeOpening(player);
|
||||
}
|
||||
|
||||
public static void removeOpening(Player player) {
|
||||
@@ -82,6 +83,7 @@ public class PrefixSelectGUI extends AutoPagedGUI {
|
||||
for (Player player : new HashSet<>(openingUsers)) {
|
||||
player.closeInventory();
|
||||
}
|
||||
openingUsers.clear();
|
||||
}
|
||||
|
||||
public static void open(Player player) {
|
||||
|
||||
@@ -1,10 +1,33 @@
|
||||
|
||||
package cc.carm.plugin.userprefix.util;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ColorParser {
|
||||
|
||||
public static String parse(String text) {
|
||||
text = parseHexColor(text);
|
||||
return parseColor(text);
|
||||
}
|
||||
|
||||
public static String parseColor(final String text) {
|
||||
return text.replaceAll("&", "§").replace("§§", "&");
|
||||
}
|
||||
|
||||
public static String parseHexColor(String text) {
|
||||
Pattern pattern = Pattern.compile("&\\((&?#[0-9a-fA-F]{6})\\)");
|
||||
Matcher matcher = pattern.matcher(text);
|
||||
while (matcher.find()) {
|
||||
String hexColor = text.substring(matcher.start() + 2, matcher.end() - 1);
|
||||
hexColor = hexColor.replace("&", "");
|
||||
StringBuilder bukkitColorCode = new StringBuilder('§' + "x");
|
||||
for (int i = 1; i < hexColor.length(); i++) {
|
||||
bukkitColorCode.append('§').append(hexColor.charAt(i));
|
||||
}
|
||||
text = text.replaceAll("&\\(" + hexColor + "\\)", bukkitColorCode.toString().toLowerCase());
|
||||
matcher.reset(text);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ItemStackFactory {
|
||||
ItemStack item;
|
||||
@@ -57,85 +57,83 @@ public class ItemStackFactory {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory setDisplayName(String name) {
|
||||
public ItemStackFactory setDisplayName(@NotNull String name) {
|
||||
ItemMeta im = this.item.getItemMeta();
|
||||
im.setDisplayName(name.replace("&", "§").replace("§§", "&&"));
|
||||
this.item.setItemMeta(im);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory setLore(List<String> lores) {
|
||||
ItemMeta im = this.item.getItemMeta();
|
||||
List<String> lores_ = new ArrayList();
|
||||
Iterator var4 = lores.iterator();
|
||||
|
||||
while (var4.hasNext()) {
|
||||
String lore = (String) var4.next();
|
||||
lores_.add(lore.replace("&", "§").replace("§§", "&&"));
|
||||
if (im != null) {
|
||||
im.setDisplayName(ColorParser.parse(name));
|
||||
this.item.setItemMeta(im);
|
||||
}
|
||||
|
||||
im.setLore(lores_);
|
||||
this.item.setItemMeta(im);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory addLore(String name) {
|
||||
public ItemStackFactory setLore(@NotNull List<String> loreList) {
|
||||
ItemMeta im = this.item.getItemMeta();
|
||||
Object lores;
|
||||
if (im.hasLore()) {
|
||||
lores = im.getLore();
|
||||
} else {
|
||||
lores = new ArrayList();
|
||||
if (im != null) {
|
||||
im.setLore(
|
||||
loreList.stream()
|
||||
.map(ColorParser::parse)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
this.item.setItemMeta(im);
|
||||
}
|
||||
|
||||
((List) lores).add(name.replace("&", "§").replace("§§", "&&"));
|
||||
im.setLore((List) lores);
|
||||
this.item.setItemMeta(im);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory addEnchant(Enchantment ench, int level, boolean ignoreLevelRestriction) {
|
||||
public ItemStackFactory addLore(@NotNull String s) {
|
||||
ItemMeta im = this.item.getItemMeta();
|
||||
im.addEnchant(ench, level, ignoreLevelRestriction);
|
||||
this.item.setItemMeta(im);
|
||||
if (im != null) {
|
||||
List<String> lore = im.getLore() != null ? im.getLore() : new ArrayList<>();
|
||||
lore.add(ColorParser.parse(s));
|
||||
im.setLore(lore);
|
||||
this.item.setItemMeta(im);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory removeEnchant(Enchantment ench) {
|
||||
public ItemStackFactory addEnchant(@NotNull Enchantment enchant, int level, boolean ignoreLevelRestriction) {
|
||||
ItemMeta im = this.item.getItemMeta();
|
||||
im.removeEnchant(ench);
|
||||
this.item.setItemMeta(im);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory addFlag(ItemFlag flag) {
|
||||
ItemMeta im = this.item.getItemMeta();
|
||||
im.addItemFlags(new ItemFlag[]{flag});
|
||||
this.item.setItemMeta(im);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory removeFlag(ItemFlag flag) {
|
||||
ItemMeta im = this.item.getItemMeta();
|
||||
im.removeItemFlags(new ItemFlag[]{flag});
|
||||
this.item.setItemMeta(im);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory setUnbreakable(boolean unbreakable) {
|
||||
ItemMeta im = this.item.getItemMeta();
|
||||
im.setUnbreakable(unbreakable);
|
||||
this.item.setItemMeta(im);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory setSkullOwner(String name) {
|
||||
if (this.item.getType() == Material.PLAYER_HEAD || this.item.getType() == Material.PLAYER_WALL_HEAD) {
|
||||
SkullMeta im = (SkullMeta) this.item.getItemMeta();
|
||||
im.setOwner(name);
|
||||
if (im != null) {
|
||||
im.addEnchant(enchant, level, ignoreLevelRestriction);
|
||||
this.item.setItemMeta(im);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory removeEnchant(@NotNull Enchantment enchant) {
|
||||
ItemMeta im = this.item.getItemMeta();
|
||||
if (im != null) {
|
||||
im.removeEnchant(enchant);
|
||||
this.item.setItemMeta(im);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory addFlag(@NotNull ItemFlag flag) {
|
||||
ItemMeta im = this.item.getItemMeta();
|
||||
if (im != null) {
|
||||
im.addItemFlags(flag);
|
||||
this.item.setItemMeta(im);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory removeFlag(@NotNull ItemFlag flag) {
|
||||
ItemMeta im = this.item.getItemMeta();
|
||||
if (im != null) {
|
||||
im.removeItemFlags(flag);
|
||||
this.item.setItemMeta(im);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ItemStackFactory setUnbreakable(boolean unbreakable) {
|
||||
ItemMeta im = this.item.getItemMeta();
|
||||
if (im != null) {
|
||||
im.setUnbreakable(unbreakable);
|
||||
this.item.setItemMeta(im);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,47 @@
|
||||
package cc.carm.plugin.userprefix.util;
|
||||
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MessageUtil {
|
||||
|
||||
public static void send(Player player, List<String> messages) {
|
||||
public static boolean hasPlaceholderAPI() {
|
||||
return Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null;
|
||||
}
|
||||
|
||||
public static void send(CommandSender sender, List<String> messages) {
|
||||
for (String s : messages) {
|
||||
player.sendMessage(ColorParser.parseColor(s));
|
||||
sender.sendMessage(ColorParser.parse(s));
|
||||
}
|
||||
}
|
||||
|
||||
public static void send(Player player, String... messages) {
|
||||
send(player, Arrays.asList(messages));
|
||||
public static void send(CommandSender sender, String... messages) {
|
||||
send(sender, Arrays.asList(messages));
|
||||
}
|
||||
|
||||
public static void sendWithPlaceholders(Player player, String... messages) {
|
||||
sendWithPlaceholders(player, Arrays.asList(messages));
|
||||
public static void sendWithPlaceholders(CommandSender sender, String... messages) {
|
||||
sendWithPlaceholders(sender, Arrays.asList(messages));
|
||||
}
|
||||
|
||||
public static void sendWithPlaceholders(Player player, List<String> messages) {
|
||||
send(player, PlaceholderAPI.setPlaceholders(player, messages));
|
||||
public static void sendWithPlaceholders(CommandSender sender, List<String> messages) {
|
||||
if (messages == null || messages.isEmpty()) return;
|
||||
if (hasPlaceholderAPI() && sender instanceof Player) {
|
||||
send(sender, PlaceholderAPI.setPlaceholders((Player) sender, messages));
|
||||
} else {
|
||||
send(sender, messages);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendWithPlaceholders(Player player, List<String> messages, String param, Object value) {
|
||||
sendWithPlaceholders(player, messages, new String[]{param}, new Object[]{value});
|
||||
public static void sendWithPlaceholders(CommandSender sender, List<String> messages, String param, Object value) {
|
||||
sendWithPlaceholders(sender, messages, new String[]{param}, new Object[]{value});
|
||||
}
|
||||
|
||||
public static void sendWithPlaceholders(Player player, List<String> messages, String[] params, Object[] values) {
|
||||
sendWithPlaceholders(player, setCustomParams(messages, params, values));
|
||||
public static void sendWithPlaceholders(CommandSender sender, List<String> messages, String[] params, Object[] values) {
|
||||
sendWithPlaceholders(sender, setCustomParams(messages, params, values));
|
||||
}
|
||||
|
||||
public static List<String> setCustomParams(List<String> messages, String param, Object value) {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package cc.carm.plugin.userprefix.util.gui;
|
||||
|
||||
import cc.carm.plugin.userprefix.configuration.PrefixConfig;
|
||||
import cc.carm.plugin.userprefix.util.ItemStackFactory;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -53,50 +51,34 @@ public class AutoPagedGUI extends CommonPagedGUI {
|
||||
public void openGUI(Player user) {
|
||||
if (previousPageSlot >= 0)
|
||||
if (hasPreviousPage()) {
|
||||
setItem(previousPageSlot, new GUIItem(previousPageUI == null ? new ItemStackFactory(Material.ARROW)
|
||||
.setDisplayName("&f上一页")
|
||||
.addLore("&7&o右键可前往第一页哦")
|
||||
.toItemStack() : previousPageUI) {
|
||||
setItem(previousPageSlot, new GUIItem(previousPageUI == null ? PrefixConfig.GUI.Items.PREVIOUS_PAGE.get() : previousPageUI) {
|
||||
@Override
|
||||
public void ClickAction(ClickType type, Player u) {
|
||||
public void onClick(ClickType type) {
|
||||
if (type == ClickType.RIGHT) {
|
||||
goFirstPage();
|
||||
} else {
|
||||
goPreviousPage();
|
||||
}
|
||||
PrefixConfig.Sounds.GUI_CLICK.play(u);
|
||||
openGUI(u);
|
||||
// u.playSound(u.getLocation(), Sound.ENTITY_CHICKEN_EGG, 0.5f, 1);
|
||||
PrefixConfig.Sounds.GUI_CLICK.play(user);
|
||||
openGUI(user);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// setItem(previousPageSlot, new GUIItem(noPreviousPageUI == null ? new ItemStackFactory(Material.GRAY_STAINED_GLASS_PANE)
|
||||
// .setDisplayName("已经是第一页啦")
|
||||
// .toItemStack() : noPreviousPageUI));
|
||||
}
|
||||
|
||||
if (previousPageSlot >= 0)
|
||||
if (nextPageSlot >= 0)
|
||||
if (hasNextPage()) {
|
||||
setItem(nextPageSlot, new GUIItem(nextPageUI == null ? new ItemStackFactory(Material.ARROW)
|
||||
.setDisplayName("下一页")
|
||||
.addLore("&7&o右键可前往最后一页哦")
|
||||
.toItemStack() : nextPageUI) {
|
||||
setItem(nextPageSlot, new GUIItem(nextPageUI == null ? PrefixConfig.GUI.Items.NEXT_PAGE.get() : nextPageUI) {
|
||||
@Override
|
||||
public void ClickAction(ClickType type, Player u) {
|
||||
public void onClick(ClickType type) {
|
||||
if (type == ClickType.RIGHT) {
|
||||
goLastPage();
|
||||
} else {
|
||||
goNextPage();
|
||||
}
|
||||
PrefixConfig.Sounds.GUI_CLICK.play(u);
|
||||
openGUI(u);
|
||||
// u.playSound(u.getLocation(), Sound.ENTITY_CHICKEN_EGG, 0.5f, 1);
|
||||
PrefixConfig.Sounds.GUI_CLICK.play(user);
|
||||
openGUI(user);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// setItem(nextPageSlot, new GUIItem(noNextPageUI == null ? new ItemStackFactory(Material.GRAY_STAINED_GLASS_PANE)
|
||||
// .setDisplayName("已经是最后一页啦")
|
||||
// .toItemStack() : noNextPageUI));
|
||||
}
|
||||
|
||||
super.openGUI(user);
|
||||
|
||||
@@ -12,7 +12,6 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@@ -39,7 +38,7 @@ public class GUI {
|
||||
|
||||
public GUI(GUIType type, String name) {
|
||||
this.type = type;
|
||||
this.name = ColorParser.parseColor(name);
|
||||
this.name = ColorParser.parse(name);
|
||||
switch (type) {
|
||||
case ONEBYNINE:
|
||||
this.items = new GUIItem[9];
|
||||
@@ -56,52 +55,11 @@ public class GUI {
|
||||
case FIVEBYNINE:
|
||||
this.items = new GUIItem[45];
|
||||
break;
|
||||
default:
|
||||
case SIXBYNINE:
|
||||
this.items = new GUIItem[54];
|
||||
break;
|
||||
|
||||
case HOPPER:
|
||||
this.items = new GUIItem[InventoryType.HOPPER.getDefaultSize()];
|
||||
break;
|
||||
case BEACON:
|
||||
this.items = new GUIItem[InventoryType.BEACON.getDefaultSize()];
|
||||
break;
|
||||
case DISPENSER:
|
||||
this.items = new GUIItem[InventoryType.DISPENSER.getDefaultSize()];
|
||||
break;
|
||||
case DROPPER:
|
||||
this.items = new GUIItem[InventoryType.DROPPER.getDefaultSize()];
|
||||
break;
|
||||
case FURNACE:
|
||||
this.items = new GUIItem[InventoryType.FURNACE.getDefaultSize()];
|
||||
break;
|
||||
case WORKBENCH:
|
||||
this.items = new GUIItem[InventoryType.WORKBENCH.getDefaultSize()];
|
||||
break;
|
||||
case CRAFTING:
|
||||
this.items = new GUIItem[InventoryType.CRAFTING.getDefaultSize()];
|
||||
break;
|
||||
case ENCHANTING:
|
||||
this.items = new GUIItem[InventoryType.ENCHANTING.getDefaultSize()];
|
||||
break;
|
||||
case BREWING:
|
||||
this.items = new GUIItem[InventoryType.BREWING.getDefaultSize()];
|
||||
break;
|
||||
case PLAYER:
|
||||
this.items = new GUIItem[InventoryType.PLAYER.getDefaultSize()];
|
||||
break;
|
||||
case MERCHANT:
|
||||
this.items = new GUIItem[InventoryType.MERCHANT.getDefaultSize()];
|
||||
break;
|
||||
case ENDER_CHEST:
|
||||
this.items = new GUIItem[InventoryType.ENDER_CHEST.getDefaultSize()];
|
||||
break;
|
||||
|
||||
case CREATIVE:
|
||||
this.items = new GUIItem[InventoryType.CREATIVE.getDefaultSize()];
|
||||
break;
|
||||
case CANCEL:
|
||||
default:
|
||||
this.items = null;
|
||||
}
|
||||
}
|
||||
@@ -209,57 +167,8 @@ public class GUI {
|
||||
if (this.type == GUIType.CANCEL) {
|
||||
throw new NullPointerException("被取消或不存在的GUI");
|
||||
}
|
||||
switch (type) {
|
||||
default:
|
||||
case ONEBYNINE:
|
||||
case TWOBYNINE:
|
||||
case THREEBYNINE:
|
||||
case FOURBYNINE:
|
||||
case FIVEBYNINE:
|
||||
case SIXBYNINE:
|
||||
inv = Bukkit.createInventory(null, this.items.length, this.name);
|
||||
break;
|
||||
case HOPPER:
|
||||
inv = Bukkit.createInventory(null, InventoryType.HOPPER, this.name);
|
||||
break;
|
||||
case BEACON:
|
||||
inv = Bukkit.createInventory(null, InventoryType.BEACON, this.name);
|
||||
break;
|
||||
case DISPENSER:
|
||||
inv = Bukkit.createInventory(null, InventoryType.DISPENSER, this.name);
|
||||
break;
|
||||
case DROPPER:
|
||||
inv = Bukkit.createInventory(null, InventoryType.DROPPER, this.name);
|
||||
break;
|
||||
case FURNACE:
|
||||
inv = Bukkit.createInventory(null, InventoryType.FURNACE, this.name);
|
||||
break;
|
||||
case WORKBENCH:
|
||||
inv = Bukkit.createInventory(null, InventoryType.WORKBENCH, this.name);
|
||||
break;
|
||||
case CRAFTING:
|
||||
inv = Bukkit.createInventory(null, InventoryType.CRAFTING, this.name);
|
||||
break;
|
||||
case ENCHANTING:
|
||||
inv = Bukkit.createInventory(null, InventoryType.ENCHANTING, this.name);
|
||||
break;
|
||||
case BREWING:
|
||||
inv = Bukkit.createInventory(null, InventoryType.BREWING, this.name);
|
||||
break;
|
||||
case PLAYER:
|
||||
inv = Bukkit.createInventory(null, InventoryType.PLAYER, this.name);
|
||||
break;
|
||||
case CREATIVE:
|
||||
inv = Bukkit.createInventory(null, InventoryType.CREATIVE, this.name);
|
||||
break;
|
||||
case MERCHANT:
|
||||
inv = Bukkit.createInventory(null, InventoryType.MERCHANT, this.name);
|
||||
break;
|
||||
case ENDER_CHEST:
|
||||
inv = Bukkit.createInventory(null, InventoryType.ENDER_CHEST, this.name);
|
||||
break;
|
||||
}
|
||||
|
||||
inv = Bukkit.createInventory(null, this.items.length, this.name);
|
||||
|
||||
for (int index = 0; index < this.items.length; index++) {
|
||||
if (items[index] == null) {
|
||||
inv.setItem(index, new ItemStack(Material.AIR));
|
||||
@@ -275,31 +184,34 @@ public class GUI {
|
||||
Bukkit.getPluginManager().registerEvents(listener = new Listener() {
|
||||
@EventHandler
|
||||
public void onInventoryClickEvent(InventoryClickEvent event) {
|
||||
rawClickListener(event);
|
||||
if (!(event.getWhoClicked() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
if (!(event.getWhoClicked() instanceof Player)) return;
|
||||
Player p = (Player) event.getWhoClicked();
|
||||
rawClickListener(event);
|
||||
if (event.getSlot() != -999) {
|
||||
try {
|
||||
if (getOpenedGUI(p) == GUI.this && event.getClickedInventory() != null && event.getClickedInventory().equals(GUI.this.inv) && GUI.this.items[event.getSlot()] != null)
|
||||
if (getOpenedGUI(p) == GUI.this
|
||||
&& event.getClickedInventory() != null
|
||||
&& event.getClickedInventory().equals(GUI.this.inv)
|
||||
&& GUI.this.items[event.getSlot()] != null) {
|
||||
GUI.this.items[event.getSlot()].realRawClickAction(event);
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
System.err.print("err cause by GUI(" + GUI.this + "), name=" + name);
|
||||
e.printStackTrace();
|
||||
System.err.print("err cause by GUI(" + GUI.this.toString() + "), name=" + name);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (setCancelledIfClickOnOuter) event.setCancelled(true);
|
||||
} else if (setCancelledIfClickOnOuter) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
if (hasOpenedGUI(p) && /*player.openedGUI.inv.equals(event.getClickedInventory())*/ getOpenedGUI(p) == GUI.this && event.getClickedInventory() != null) {
|
||||
if (hasOpenedGUI(p)
|
||||
&& getOpenedGUI(p) == GUI.this
|
||||
&& event.getClickedInventory() != null) {
|
||||
if (event.getClickedInventory().equals(GUI.this.inv)) {
|
||||
if (setCancelledIfClickOnTarget) event.setCancelled(true);
|
||||
|
||||
if (event.getSlot() != -999 && GUI.this.items[event.getSlot()] != null) {
|
||||
if (GUI.this.items[event.getSlot()].isActionActive()) {
|
||||
GUI.this.items[event.getSlot()].onClick(event.getClick());
|
||||
GUI.this.items[event.getSlot()].ClickAction(event.getClick(), player);
|
||||
GUI.this.items[event.getSlot()].rawClickAction(event);
|
||||
if (!GUI.this.items[event.getSlot()].actions.isEmpty()) {
|
||||
for (GUIItem.GUIClickAction action : GUI.this.items[event.getSlot()].actions) {
|
||||
@@ -313,8 +225,8 @@ public class GUI {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (event.getClickedInventory().equals(p.getInventory())) {
|
||||
if (setCancelledIfClickOnSelf) event.setCancelled(true);
|
||||
} else if (event.getClickedInventory().equals(p.getInventory()) && setCancelledIfClickOnSelf) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -336,6 +248,7 @@ public class GUI {
|
||||
if (event.getInventory().equals(inv)) {
|
||||
HandlerList.unregisterAll(this);
|
||||
listener = null;
|
||||
removeOpenedGUI(p);
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,17 +36,6 @@ public class GUIItem {
|
||||
actionActive = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* 玩家点击GUI后执行的代码
|
||||
*
|
||||
* @param type 点击的类型
|
||||
* @param player 点击GUI的玩家
|
||||
*/
|
||||
@Deprecated
|
||||
public void ClickAction(ClickType type, Player player) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 玩家点击GUI后执行的代码
|
||||
*
|
||||
@@ -64,10 +53,6 @@ public class GUIItem {
|
||||
actionsIgnoreActive.add(action);
|
||||
}
|
||||
|
||||
public void customAction() {
|
||||
|
||||
}
|
||||
|
||||
public void rawClickAction(InventoryClickEvent event) {
|
||||
|
||||
}
|
||||
@@ -76,10 +61,6 @@ public class GUIItem {
|
||||
|
||||
}
|
||||
|
||||
public void customAction(Object obj) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 玩家点击GUI后执行的代码
|
||||
*
|
||||
|
||||
@@ -11,20 +11,6 @@ public enum GUIType {
|
||||
FOURBYNINE,
|
||||
FIVEBYNINE,
|
||||
SIXBYNINE,
|
||||
DISPENSER,
|
||||
DROPPER,
|
||||
FURNACE,
|
||||
WORKBENCH,
|
||||
CRAFTING,
|
||||
ENCHANTING,
|
||||
BREWING,
|
||||
PLAYER,
|
||||
CREATIVE,
|
||||
MERCHANT,
|
||||
ENDER_CHEST,
|
||||
BEACON,
|
||||
HOPPER,
|
||||
UNKNOWN,
|
||||
CANCEL;
|
||||
|
||||
}
|
||||
|
||||
@@ -5,15 +5,39 @@ debug: false
|
||||
functions:
|
||||
OnNamePrefix: true # 是否给头顶上添加前缀,该方法用到了头顶的那个计分板,如有冲突请关掉哦~
|
||||
autoUsePrefix: true # 自动前缀显示 当玩家没有自己选择一个前缀的时候,会自动使用所拥有的的前缀中权重最高的那一个
|
||||
chat:
|
||||
# 聊天功能
|
||||
# - 我不推荐使用本插件的聊天功能,而是建议使用其他的聊天插件。
|
||||
# - 本插件仅仅提供了**最基本**的格式变量支持,不包含其他任何功能。
|
||||
# - 注意聊天格式需要遵守Bukkit原格式,即不得缺失 “%1$s” 和 “%2$s” 。
|
||||
# - 本插件的聊天功能不影响其他插件对聊天事件的操作。
|
||||
enable: false # 是否启用
|
||||
format: "<%UserPrefix_prefix%%1$s> %2$s" #聊天的格式,注意 “%1$s” 和 “%2$s” 不可缺少,分别代表 玩家名 与 消息内容 。
|
||||
|
||||
messages:
|
||||
selected:
|
||||
- "&7您选择了 &f%(name) &7作为当前显示的前缀。"
|
||||
expired:
|
||||
- "&7您先前使用的前缀 &f%(oldName) &7已到期。"
|
||||
- "&7现在已为您重新调整为 &f%(newName) &7。"
|
||||
help:
|
||||
- "&7输入 &b/prefix &7打开前缀选择菜单。"
|
||||
GUI:
|
||||
title: "&f&l我的前缀 &8| 列表"
|
||||
items:
|
||||
# 【必须】 GUI中可能存在的其他物品
|
||||
next-page: # 下一页物品,如果没有下一页则不显示
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: ARROW
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§f下一页"
|
||||
lore:
|
||||
- ""
|
||||
- "§f右键可前往最后一页哦~"
|
||||
previous-page: # 上一页物品,如果没有上一页则不显示
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: ARROW
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§f上一页"
|
||||
lore:
|
||||
- ""
|
||||
- "§f右键可前往第一页哦~"
|
||||
|
||||
Sounds: #相关的声音,注释掉则不播放声音 格式为 【声音名:音量:音调】 或 【声音名:音量】 或 【声音名】
|
||||
openGUI: "BLOCK_NOTE_BLOCK_PLING:1:1"
|
||||
@@ -45,58 +69,4 @@ defaultPrefix:
|
||||
display-name: "§f默认玩家前缀"
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ 您正在使用该前缀"
|
||||
|
||||
prefixes:
|
||||
VIP:
|
||||
name: "&b&lPro&b" # [必须] 名字(切换的时候左下角会弹提示 用的就是这个名字)
|
||||
content: "§b§lPro §b" # [必须] 显示在名字前面的内容
|
||||
weight: 1 # [必须] 权重,用于GUI里面的排序(越大显示在越后面)和自动前缀显示
|
||||
permission: "yc.pro" # [非必须] 检测的权限,如果没有就是人人都能用,也代表不用配置“itemNoPermission”了(因为压根不可能显示没权限时候的物品)
|
||||
itemHasPermission: # [必须] 当有权限的时候会显示这个Item
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro §b会员前缀"
|
||||
lore:
|
||||
- "§7Pro会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- ""
|
||||
- "§a➥ 点击切换到该前缀"
|
||||
itemUsing: # [非必需] 当有权限的时候会显示这个Item,如果没有这个配置就自动显示“itemHasPermission”的。
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro §b会员前缀"
|
||||
enchants:
|
||||
PROTECTION_ENVIRONMENTAL: 1 #加一个附魔这样看上去就像是选中了的
|
||||
lore:
|
||||
- "§7Pro会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- ""
|
||||
- "§a✔ 您正在使用该前缀"
|
||||
itemNoPermission: # [非必需] 如果没有权限就会显示这个item。如果不配置该物品,则玩家没有使用权限时不会显示在GUI里面。
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: INK_SACK
|
||||
damage: 8
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro+ §b会员前缀 §c(未拥有)"
|
||||
lore:
|
||||
- "§7Pro+会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- "§f您可以输入 §b/vip §f指令查看详细特权!"
|
||||
- ""
|
||||
- "§e✯ 加入Pro+会员以使用该前缀!"
|
||||
|
||||
- "§a✔ 您正在使用该前缀"
|
||||
@@ -0,0 +1,78 @@
|
||||
version: ${project.version} # DO NOT EDIT IT
|
||||
|
||||
debug: false #DEBUG OUT PUT
|
||||
|
||||
GUI:
|
||||
title: "&f&lMy Prefixes List" # Title of the GUI
|
||||
items:
|
||||
next-page: # only show has next page
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: ARROW
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fNext Page"
|
||||
lore:
|
||||
- ""
|
||||
- "§fRight-Click to the last page"
|
||||
previous-page: # only show has previous page
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: ARROW
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fPrevious Page"
|
||||
lore:
|
||||
- ""
|
||||
- "§fRight-Click to the first page"
|
||||
|
||||
functions:
|
||||
# Whether to add a prefix to the top of the head,
|
||||
# this method uses the scoreboard above the head,
|
||||
# please turn it off if there is a conflict.
|
||||
OnNamePrefix: true
|
||||
# Automatic prefix select.
|
||||
# When the player does not choose a prefix by himself,
|
||||
# the prefix with the highest weight will be used automatically
|
||||
autoUsePrefix: true
|
||||
chat:
|
||||
# Chat Function
|
||||
# - I recommend using other chat plugins instead of using this plugin,
|
||||
# - this plugin only provides very basic chat format placeholders.
|
||||
# - Notice that: format must has “%1$s” and “%2$s” for PlayerName and Message (Bukkit Chat Event)
|
||||
enable: false
|
||||
format: "<%UserPrefix_prefix%%1$s> %2$s"
|
||||
|
||||
|
||||
|
||||
Sounds:
|
||||
# Format is [SOUND_NAME:Volume:Pitch] or [SOUND_NAME:Volume] or [SOUND_NAME]
|
||||
openGUI: "BLOCK_NOTE_BLOCK_PLING:1:1"
|
||||
guiClick: "UI_BUTTON_CLICK"
|
||||
prefixChange: "ENTITY_VILLAGER_YES"
|
||||
prefixExpired: "ENTITY_VILLAGER_NO"
|
||||
|
||||
# The default prefix's weight is 0.
|
||||
defaultPrefix:
|
||||
name: "Default prefix"
|
||||
content: "&b"
|
||||
itemNotUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: NAME_TAG
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fThe default prefix §f(Click to select)"
|
||||
lore:
|
||||
- ""
|
||||
- "§a➥ Click to use"
|
||||
itemUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: NAME_TAG
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fThe default prefix"
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ Selected"
|
||||
@@ -0,0 +1,71 @@
|
||||
|
||||
# identifier [Necessary]
|
||||
# This will be used for data-storage.
|
||||
identifier: "pro"
|
||||
|
||||
# Name [Necessary]
|
||||
# Use in messages.
|
||||
name: "&b&lPro&b"
|
||||
|
||||
# Content [Necessary]
|
||||
# Use in Placeholders
|
||||
content: "§b§lPro §b"
|
||||
|
||||
# Weight [Necessary]
|
||||
# used for sorting in the GUI and TabList
|
||||
# In GUI : the larger is displayed at the back
|
||||
# At TabList : the larger is displayed at the top
|
||||
weight: 1
|
||||
|
||||
# Permission [Unnecessary]
|
||||
# If there is no permission for detection, everyone can use it,
|
||||
# which means there is no need to configure "itemNoPermission"
|
||||
# (because it is impossible to display items without permission at all)
|
||||
permission: "yc.vip"
|
||||
|
||||
# itemHasPermission [Necessary]
|
||||
# This Item will be displayed when player has permission
|
||||
itemHasPermission:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP Prefix"
|
||||
lore:
|
||||
- ""
|
||||
- "§a➥ Click to use"
|
||||
|
||||
# itemUsing [Unnecessary]
|
||||
# This Item will be displayed when the prefix is selected.
|
||||
# If there is no such configuration, it will automatically display "itemHasPermission".
|
||||
itemUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP Prefix"
|
||||
enchants:
|
||||
PROTECTION_ENVIRONMENTAL: 1 #Add an enchantment so it looks like it’s selected
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ Selected"
|
||||
|
||||
# itemNoPermission [Unnecessary]
|
||||
# If player doesn't have the permission,this item will be displayed.
|
||||
# If this item is not configured, it will not be displayed in the GUI when the player does not have permission to use it.
|
||||
itemNoPermission:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: INK_SACK
|
||||
damage: 8
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP §c(Buy it!)"
|
||||
lore:
|
||||
- ""
|
||||
- "§e✯ Buy the VIP to use it!"
|
||||
@@ -0,0 +1,19 @@
|
||||
selected:
|
||||
- "&7You have selected the &f%(name) &7as current prefix."
|
||||
expired:
|
||||
- "&7Your prefix &f%(oldName) &7has expired,"
|
||||
- "&7Now the prefix is changed to &f%(newName) &7."
|
||||
reload:
|
||||
- "&a&lReload completed!&7costs &f%(time)ms&7."
|
||||
help:
|
||||
- "&3&lUserPrefixAdmin &fHelp"
|
||||
- "&8#/upa&f list"
|
||||
- "&8- &7Show configured prefixes."
|
||||
- "&8#/upa&f reload"
|
||||
- "&8- &7Reload configuration."
|
||||
list-title:
|
||||
- "&3&lUserPrefixAdmin &fList"
|
||||
list-value:
|
||||
- "&8#%(weight) &f%(identifier)"
|
||||
- "&8- &7Name &r%(name) &7Perm &r%(permission)"
|
||||
- "&8- &7Example&r %(content) %(sender_name)"
|
||||
@@ -0,0 +1,19 @@
|
||||
selected:
|
||||
- "&7您选择了 &f%(name) &7作为当前显示的前缀。"
|
||||
expired:
|
||||
- "&7您先前使用的前缀 &f%(oldName) &7已到期。"
|
||||
- "&7现在已为您重新调整为 &f%(newName) &7。"
|
||||
reload:
|
||||
- "&a&l重载完成!&7共耗时 &f%(time)ms&7。"
|
||||
help:
|
||||
- "&3&l用户前缀系统 &f帮助"
|
||||
- "&8#/upa&f list"
|
||||
- "&8- &7查看当前前缀列表。"
|
||||
- "&8#/upa&f reload"
|
||||
- "&8- &7重载前缀配置。"
|
||||
list-title:
|
||||
- "&3&l用户前缀系统 &f前缀列表"
|
||||
list-value:
|
||||
- "&8#%(weight) &f%(identifier)"
|
||||
- "&8- &7显示名 &r%(name) &7权限 &r%(permission)"
|
||||
- "&8- &7内容示例&r %(content) %(sender_name)"
|
||||
@@ -3,6 +3,9 @@ name: UserPrefix
|
||||
version: ${project.version}
|
||||
authors:
|
||||
- Carm
|
||||
- YourCraft
|
||||
- SakuraGame
|
||||
website: "https://github.com/CarmJos/UserPrefix"
|
||||
depend:
|
||||
- LuckPerms
|
||||
softdepend:
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# 唯一标识 [必须]
|
||||
# 将用于记录玩家所选的前缀,以及用于数据的缓存。
|
||||
# 必须 必须 必须 保持唯一!
|
||||
identifier: "pro"
|
||||
|
||||
# 名字 [必须]
|
||||
# 切换的时候左下角会弹提示 用的就是这个名字
|
||||
name: "&b&lPro&b"
|
||||
|
||||
# 内容 [必须]
|
||||
# 显示在名字前面的内容
|
||||
content: "§b§lPro §b"
|
||||
|
||||
# 权重 [必须]
|
||||
# 用于GUI、TabList的排序和自动前缀显示
|
||||
# 在GUI中,权重越高的会显示在越后面
|
||||
# 在TabList中,权重越高的会显示在越上面
|
||||
weight: 1
|
||||
|
||||
|
||||
# 检测的权限 [非必须]
|
||||
# 如果没有就是人人都能用,也代表不用配置“itemNoPermission”了(因为压根不可能显示没权限时候的物品)
|
||||
permission: "yc.pro"
|
||||
|
||||
# 有权限时显示的物品 [必须]
|
||||
# 当用户有权限且未选中时,会显示该物品
|
||||
itemHasPermission: #
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro §b会员前缀"
|
||||
lore:
|
||||
- "§7Pro会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- ""
|
||||
- "§a➥ 点击切换到该前缀"
|
||||
|
||||
# 正在使用时显示的物品 [非必需]
|
||||
# 当用户正在使用时会显示这个物品,不配置即自动加载“itemHasPermission”
|
||||
itemUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro §b会员前缀"
|
||||
enchants:
|
||||
PROTECTION_ENVIRONMENTAL: 1 #加一个附魔这样看上去就像是选中了的
|
||||
lore:
|
||||
- "§7Pro会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- ""
|
||||
- "§a✔ 您正在使用该前缀"
|
||||
|
||||
# 没有权限时显示的物品 [非必需]
|
||||
# 如果没有权限就会显示这个item。如果不配置该物品,则玩家没有使用权限时不会显示在GUI里面。
|
||||
itemNoPermission:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: INK_SACK
|
||||
damage: 8
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro+ §b会员前缀 §c(未拥有)"
|
||||
lore:
|
||||
- "§7Pro+会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- "§f您可以输入 §b/vip §f指令查看详细特权!"
|
||||
- ""
|
||||
- "§e✯ 加入Pro+会员以使用该前缀!"
|
||||
@@ -0,0 +1,14 @@
|
||||
import cc.carm.plugin.userprefix.util.ColorParser;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ColorParseTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void onTest() {
|
||||
String testString = "&f爱的人永远不爱我,为何付出得到的只有&(#aaaaaa)背叛。";
|
||||
|
||||
System.out.println(ColorParser.parseHexColor(testString));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
[align=center][attachimg]1905166[/attachimg]
|
||||
[/align]
|
||||
[align=left][b][size=6]用户前缀系统插件[/size][/b][/align][align=left][hr][/align][align=left][img]https://www.codefactor.io/repository/github/carmjos/userprefix/badge?s=b76fec1f64726b5f19989aace6adb5f85fdab840[/img] [img]https://github.com/CarmJos/UserPrefix/actions/workflows/maven.yml/badge.svg?branch=master[/img] [img]https://visitor-badge.glitch.me/badge?page_id=userprefix.readme[/img]
|
||||
[/align]
|
||||
[align=left]轻便、高效、实时的用户前缀系统。[/align]
|
||||
[align=left]本插件基于Spigot实现,[b]理论上支持全版本[/b]。[/align]
|
||||
[align=left][size=5][b]示例[/b][/size][/align][align=left][hr][/align]
|
||||
[attachimg]1905175[/attachimg]
|
||||
[align=left][size=5][b]依赖[/b][/size][/align][align=left][hr][/align]
|
||||
[align=left][list]
|
||||
[*][size=3][b][必须] [/b][/size]插件本体基于 [url=https://hub.spigotmc.org/stash/projects/SPIGOT][b]Spigot-API[/b][/url] 与 [b][url=http://bukkit.org/]BukkitAPI[/url] [/b]实现。
|
||||
[*][size=3][b][必须] [/b][/size]数据部分基于 [url=https://www.spigotmc.org/resources/luckperms.28140/][b]LuckPerms[/b][/url] 实现。
|
||||
[*][size=3][b][推荐][/b] [/size]变量部分基于 [url=https://www.spigotmc.org/resources/6245/][b]PlaceholderAPI[/b][/url] 实现。
|
||||
[/list]
|
||||
[/align]详细依赖列表可见 [url=https://github.com/CarmJos/UserPrefix/network/dependencies]软件依赖[/url] 。
|
||||
|
||||
[size=5][b]特性[/b][/size]
|
||||
[hr]
|
||||
[list]
|
||||
[*]理论上[b]全版本支持[/b]!
|
||||
[*]游戏内重载配置文件并实时更新到玩家!
|
||||
[*]当玩家权限变更时会[b]实时监测前缀[/b],若权限不足则[b]自动更换[/b]前缀并提示!
|
||||
[*]可配置的声音、消息!
|
||||
[*]前缀图标可配置“选中”、“有权限”与“无权限”三种状态的物品
|
||||
[*]物品的配置通过ItemStack原生配置,支持MC所有的设定!
|
||||
[*]TabList自动按照前缀的权重排序 (如有冲突可关掉)
|
||||
[*]玩家头顶前缀实时显示 (如有冲突可关掉)
|
||||
[*][b]自动排序[/b],且[b]可翻页[/b]的GUI!
|
||||
[*]支持PlaceholderAPI变量!(凡支持的都可以使用,如BungeeTabListPlus)
|
||||
[*]支持Hex颜色!(1.16以上版本) 格式 [u]&(#颜色代码)[/u]
|
||||
[/list][size=5][b]
|
||||
注意事项[/b][/size]
|
||||
[hr]
|
||||
[size=4][b]1. 版本支持问题[/b][/size]
|
||||
本插件理论全版本支持,如果出现图标不加载、声音无法播放等问题请检查配置文件中物品与声音的type在当前版本是否存在。
|
||||
以声音举例,村民表示可以的声音在低版本中为 “[color=#000000][backcolor=silver]VILLAGER_YES[/backcolor][/color]”,而在高版本中则变为了“[backcolor=silver][color=#000000]ENTITY_VILLAGER_YES[/color][/backcolor]”。
|
||||
|
||||
[size=4][b]2. 计分板异常问题[/b][/size]
|
||||
头顶上前缀的显示与TabList的排序均使用到了团队计分板API。
|
||||
如有冲突导致其他插件的计分板无法显示,请关掉配置文件中 [u]functions.OnNamePrefix[/u]。
|
||||
|
||||
[size=4][b]3. 物品图标配置问题[/b][/size]
|
||||
物品相关均通过Bukkit提供的ItemStack序列化方法读取,相关配置方式请参考[url=https://www.spigotmc.org/wiki/itemstack-serialization/]ItemStack Serialization(物品序列化)[/url]。
|
||||
|
||||
[size=5][b]指令[/b][/size]
|
||||
[hr]
|
||||
本插件指令部分较为简单,大多通过GUI实现。
|
||||
[code]/UserPrefix 或 /prefix 打开前缀更换GUI
|
||||
/UserPrefixAdmin 查看管理员指令帮助
|
||||
/UserPrefixAdmin reload 重载配置文件
|
||||
/UserPrefixAdmin list 查看已配置的前缀内容[/code]
|
||||
[size=5][b]变量 (PlaceholderAPI)[/b][/size]
|
||||
[hr]
|
||||
安装 [url=https://github.com/PlaceholderAPI/PlaceholderAPI]PlaceholderAPI[/url]后,可以输入 [u]/papi info UserPrefix[/u] 查看相关变量。
|
||||
变量内容如下
|
||||
[code]# %UserPrefix_prefix%
|
||||
- 得到当前正在使用的前缀
|
||||
# %UserPrefix_weight%
|
||||
- 得到当前正在使用的前缀权重
|
||||
# %UserPrefix_identifier%
|
||||
- 得到当前正在使用的前缀标识
|
||||
# %UserPrefix_name%
|
||||
- 得到当前正在使用的前缀名
|
||||
# %UserPrefix_has_<Identifier>%
|
||||
- 判断玩家是否拥有某个前缀(true/false)[/code][size=5][b]
|
||||
配置文件示例[/b][/size]
|
||||
[hr]
|
||||
[size=4][b]基础配置文件 [/b][/size][color=#24292f][font=Tahoma][size=4](config.yml)[/size][/font][/color]
|
||||
[spoiler]
|
||||
[code] version: 1.0.0-SNAPSHOT # 配置文件版本,一般不会动。
|
||||
|
||||
debug: false #debug输出,开发者用的
|
||||
|
||||
functions:
|
||||
OnNamePrefix: true # 是否给头顶上添加前缀,该方法用到了头顶的那个计分板,如有冲突请关掉哦~
|
||||
autoUsePrefix: true # 自动前缀显示 当玩家没有自己选择一个前缀的时候,会自动使用所拥有的的前缀中权重最高的那一个[/code][/spoiler]
|
||||
|
||||
[b][size=4][backcolor=transparent]消息配置文件[/backcolor][/size] [/b][size=4](messages.yml)[/size]
|
||||
[spoiler][code]selected:
|
||||
- "&7您选择了 &f%(name) &7作为当前显示的前缀。"
|
||||
expired:
|
||||
- "&7您先前使用的前缀 &f%(oldName) &7已到期。"
|
||||
- "&7现在已为您重新调整为 &f%(newName) &7。"
|
||||
reload:
|
||||
- "&a&l重载完成!&7共耗时 &f%(time)ms&7。"
|
||||
help:
|
||||
- "&3&l用户前缀系统 &f帮助"
|
||||
- "&8#/upa&f list"
|
||||
- "&8- &7查看当前前缀列表。"
|
||||
- "&8#/upa&f reload"
|
||||
- "&8- &7重载前缀配置。"
|
||||
list-title:
|
||||
- "&3&l用户前缀系统 &f前缀列表"
|
||||
list-value:
|
||||
- "&8#%(weight) &f%(identifier)"
|
||||
- "&8- &7显示名 &r%(name) &7权限 &r%(permission)"
|
||||
- "&8- &7内容示例&r %(content) %(sender_name)"[/code][/spoiler]
|
||||
|
||||
[size=4][backcolor=transparent][b]前缀配置文件[/b][/backcolor] (prefixes/*.yml)[/size]
|
||||
[align=left][font=-apple-system, BlinkMacSystemFont, "][size=3][color=#000000]所有前缀均为单独的配置文件,存放于 [u]插件配置目录/prefixes[/u] 下,便于管理。[/color][/size][/font][/align][align=left][font=-apple-system, BlinkMacSystemFont, "][size=3][color=#000000]文件名理论上可以随便取,推荐使用英文,部分符号可能会影响正常读取,请避免使用。[/color][/size][/font][/align][align=left][spoiler][/align][code]# 唯一标识 [必须]
|
||||
# 将用于记录玩家所选的前缀,以及用于数据的缓存。
|
||||
# 必须 必须 必须 保持唯一!
|
||||
identifier: "pro"
|
||||
|
||||
# 名字 [必须]
|
||||
# 切换的时候左下角会弹提示 用的就是这个名字
|
||||
name: "&b&lPro&b"
|
||||
|
||||
# 内容 [必须]
|
||||
# 显示在名字前面的内容
|
||||
content: "§b§lPro §b"
|
||||
|
||||
# 权重 [必须]
|
||||
# 用于GUI、TabList的排序和自动前缀显示
|
||||
# 在GUI中,权重越高的会显示在越后面
|
||||
# 在TabList中,权重越高的会显示在越上面
|
||||
weight: 1
|
||||
|
||||
# 检测的权限 [非必须]
|
||||
# 如果没有就是人人都能用,也代表不用配置“itemNoPermission”了(因为压根不可能显示没权限时候的物品)
|
||||
permission: "yc.pro"
|
||||
|
||||
# 有权限时显示的物品 [必须]
|
||||
# 当用户有权限且未选中时,会显示该物品
|
||||
itemHasPermission: #
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro §b会员前缀"
|
||||
lore:
|
||||
- "§7Pro会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- ""
|
||||
- "§a➥ 点击切换到该前缀"
|
||||
|
||||
# 正在使用时显示的物品 [非必需]
|
||||
# 当用户正在使用时会显示这个物品,不配置即自动加载“itemHasPermission”
|
||||
itemUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro §b会员前缀"
|
||||
enchants:
|
||||
PROTECTION_ENVIRONMENTAL: 1 #加一个附魔这样看上去就像是选中了的
|
||||
lore:
|
||||
- "§7Pro会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- ""
|
||||
- "§a✔ 您正在使用该前缀"
|
||||
|
||||
# 没有权限时显示的物品 [非必需]
|
||||
# 如果没有权限就会显示这个item。如果不配置该物品,则玩家没有使用权限时不会显示在GUI里面。
|
||||
itemNoPermission:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: INK_SACK
|
||||
damage: 8
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lPro+ §b会员前缀 §c(未拥有)"
|
||||
lore:
|
||||
- "§7Pro+会员专属称号"
|
||||
- ""
|
||||
- "§f尊贵的Pro会员专属称号。"
|
||||
- "§f您将获得多种特权与更好的游戏体验。"
|
||||
- "§f您可以输入 §b/vip §f指令查看详细特权!"
|
||||
- ""
|
||||
- "§e✯ 加入Pro+会员以使用该前缀!"[/code][align=left][/spoiler][/align]
|
||||
|
||||
[size=5][b]下载地址[/b][/size]
|
||||
[hr]
|
||||
[size=3][b]最新版本 2.1.0 [/b][/size][attach]1909962[/attach][quote][b][size=3]更新内容[/size][/b]
|
||||
1. 添加聊天相关设定,支持聊天前缀。(但不推荐使用哦~)[/quote]
|
||||
|
||||
[spoiler]
|
||||
|
||||
[size=3][b] 2.0.0 [/b][/size][attach]1905700[/attach]
|
||||
[quote][b][size=3]更新内容[/size][/b]
|
||||
1. 修复低版本可能无法读取物品的bug。
|
||||
2. 分离配置文件,消息配置文件改为messages.yml,前缀配置文件改 prefixes/*.yml,便于配置和管理。
|
||||
3. 允许配置GUI中上一页和下一页的物品。
|
||||
4. 补全帮助文档,在插件首次加载将提供一份英文版的配置,以便使用。[/quote]
|
||||
[size=3][b] 1.2.5 [/b][/size][attach]1905430[/attach][quote][size=3][b]更新内容[/b]
|
||||
1. 支持指令的多语言配置。[/size][/quote]
|
||||
[b][size=3]
|
||||
1.2.4[/size][size=4] [/size][/b][attach]1905431[/attach]
|
||||
[quote][size=3][b]更新内容:[/b]
|
||||
1. 修复closeAll方法中,未移除玩家缓存的bug。
|
||||
2. 当玩家权限更新时,将关闭玩家的GUI,令其自行打开刷新所有前缀。
|
||||
3. 允许配置GUI的标题。[/size][/quote]
|
||||
[size=3][b]1.2.3 [/b][/size][attach]1905406[/attach]
|
||||
[quote][size=3][b]更新内容:[/b]
|
||||
[/size][size=3]1. 支持Hex颜色!(1.16以上版本) 格式 [u]&(#颜色代码)[/u] ;[/size]
|
||||
[size=3][backcolor=initial]- 如 “[/backcolor][/size][backcolor=initial][size=3]LightSlateBlue [u]&(#8470FF)[/u] ”、 “DarkSlateBlue [u]&(#483D8B)[/u]”。[/size][/backcolor]
|
||||
[backcolor=initial][size=3]2. 修复未安装PlaceholderAPI的情况下可能导致的部分报错。[/size][/backcolor]
|
||||
[backcolor=initial][size=3]
|
||||
[/size][/backcolor]
|
||||
[/quote]
|
||||
[/spoiler]
|
||||
|
||||
更多版本请移步 [url=https://github.com/CarmJos/UserPrefix/releases]Releases · CarmJos/UserPrefix (github.com)[/url] 。
|
||||
|
||||
|
||||
[size=5][b]开源地址[/b][/size]
|
||||
[hr]
|
||||
[size=3]本插件于 [/size][url=https://github.com/CarmJos/UserPrefix]Github[/url][size=3] 开源。[/size]
|
||||
[size=3]
|
||||
[/size]
|
||||
[color=#24292f][font=-apple-system, BlinkMacSystemFont, "][size=16px]本项目源码采用 [/size][/font][/color][url=https://opensource.org/licenses/GPL-3.0]GNU General Public License v3.0[/url][color=#24292f][font=-apple-system, BlinkMacSystemFont, "][size=16px] 开源协议。[/size][/font][/color]
|
||||
[font=-apple-system, BlinkMacSystemFont][color=#24292f][size=16px]
|
||||
[/size][/color][/font][size=3]喜欢本插件的话,也可以去Github上给我点个小星星哦~
|
||||
[/size]
|
||||
|
||||
[size=5][b]插件支持[/b][/size]
|
||||
[hr]
|
||||
[size=4]本项目由 [url=https://www.mcbbs.net/group-2077-1.html]YourCraft(你的世界)[/url] 团队提供长期支持与维护。
|
||||
欢迎加入 [url=https://jq.qq.com/?_wv=1027&k=W634w2NT]YourCraft技术交流群[/url] 深入探讨开发问题。[/size]
|
||||
[attachimg]1905173[/attachimg]
|
||||
|
||||
|
||||
|
||||
|
||||
[hr]
|
||||
[align=center][b][size=4][color=#ff0000]本插件所用所有代码均为原创,不存在借用/抄袭等行为[/color][/size][/b][/align]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,277 @@
|
||||
[URL='https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/banner.png'][IMG]https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/banner.png[/IMG][/URL]
|
||||
|
||||
[SIZE=6][B]UserPrefix Plugin[/B][/SIZE]
|
||||
[URL='https://www.codefactor.io/repository/github/carmjos/userprefix'][IMG]https://camo.githubusercontent.com/6040f5c07ea04f9cb666459d6b6f08d19971fc29a26183cdc6595297b287234b/68747470733a2f2f7777772e636f6465666163746f722e696f2f7265706f7369746f72792f6769746875622f6361726d6a6f732f757365727072656669782f62616467653f733d62373666656331663634373236623566313939383961616365366164623566383566646162383430[/IMG][/URL] [URL='https://github.com/CarmJos/UserPrefix/actions/workflows/maven.yml'][IMG]https://github.com/CarmJos/UserPrefix/actions/workflows/maven.yml/badge.svg?branch=master[/IMG][/URL] [URL='https://opensource.org/licenses/GPL-3.0'][IMG]https://camo.githubusercontent.com/fd3e53788a319da1b7287d976c2f23fcb8e3d474249af0bf7f8e671f968faebd/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f4361726d4a6f732f55736572507265666978[/IMG][/URL] [URL='https://camo.githubusercontent.com/753f86cc8d2a514a026309afab251b090749751b35409f1e633c77cc0b3f5618/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d696e6563726166742d4a617661253230312e382d2d4c61746573742d79656c6c6f77'][IMG]https://camo.githubusercontent.com/753f86cc8d2a514a026309afab251b090749751b35409f1e633c77cc0b3f5618/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d696e6563726166742d4a617661253230312e382d2d4c61746573742d79656c6c6f77[/IMG][/URL] [URL='https://camo.githubusercontent.com/75543844e4f92947d837bd45ab75d5a268e63ff485cd7b354cf69f52e60be28d/68747470733a2f2f76697369746f722d62616467652e676c697463682e6d652f62616467653f706167655f69643d757365727072656669782e726561646d65'][IMG]https://camo.githubusercontent.com/75543844e4f92947d837bd45ab75d5a268e63ff485cd7b354cf69f52e60be28d/68747470733a2f2f76697369746f722d62616467652e676c697463682e6d652f62616467653f706167655f69643d757365727072656669782e726561646d65[/IMG][/URL]
|
||||
|
||||
Lightweight, efficient, and real-time user prefix system.
|
||||
|
||||
This plugin is implemented based on Spigot ,Theoretically support ALL MineCraft Versions.
|
||||
|
||||
The development of this plugin is based on Chinese, which purpose is to help Chinese developers learn Bukkit plugin development.
|
||||
|
||||
[QUOTE]
|
||||
本插件已在 [URL='https://www.mcbbs.net/forum.php?mod=viewthread&tid=1261503']MCBBS[/URL] 上发布,欢迎中文用户来这里下载。
|
||||
[/QUOTE]
|
||||
|
||||
[SIZE=5][B]Examples[/B][/SIZE]
|
||||
[URL='https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/using-example.png'][IMG]https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/using-example.png[/IMG][/URL]
|
||||
|
||||
[SIZE=5][B]Dependencies[/B][/SIZE]
|
||||
[LIST]
|
||||
[*][B][Necessary][/B] Plugin developed based on [URL='https://hub.spigotmc.org/stash/projects/SPIGOT']Spigot-API[/URL] and [URL='http://bukkit.org/']BukkitAPI[/URL].
|
||||
[*][B][Necessary][/B] Plugin data storage base on [URL='https://www.spigotmc.org/resources/luckperms.28140/']LuckPerms[/URL].
|
||||
[*][Recommend] Placeholders based on [URL='https://www.spigotmc.org/resources/6245/']PlaceholderAPI[/URL] .
|
||||
[/LIST]
|
||||
For development dependencies, please see [URL='https://github.com/CarmJos/UserPrefix/network/dependencies']Dependencies[/URL] .
|
||||
|
||||
[SIZE=5][B]Features[/B][/SIZE]
|
||||
[LIST]
|
||||
[*]Theoretically support ALL MineCraft Versions.
|
||||
[*]Reloading the configuration will automatically refresh the prefix of all players.
|
||||
[*]Real-time judgment and feedback to the player when permissions are changed.
|
||||
[*]Configurable sounds and messages.
|
||||
[*]The prefix icon can be configured as "Selected", "Has Permission" and “No Permission”.
|
||||
[LIST]
|
||||
[*]Item configuration is natively configured through ItemStack, which supports all MC settings!
|
||||
[/LIST]
|
||||
[*]TabList is automatically sorted according to the weight of the prefix (if there is a conflict, it can be turned off)
|
||||
[*]The prefix display on the player name (can be turned off if there is a conflict)
|
||||
[*]GUI with automatic sorting and page turning!
|
||||
[*]Support PlaceholderAPI variables!
|
||||
[*]Support Hex color! (Version 1.16 and above) [U]&(#Color)[/U]
|
||||
[LIST]
|
||||
[*]Example: LightSlateBlue [U]&(#8470FF)[/U] 、 DarkSlateBlue [U]&(#483D8B)[/U]
|
||||
[/LIST]
|
||||
[/LIST]
|
||||
[SIZE=5][B]Notice[/B][/SIZE]
|
||||
[SIZE=4][B]1. Version support issues[/B][/SIZE]
|
||||
This plugin theoretically supports all versions.
|
||||
|
||||
If the icon does not load, the sound cannot be played, etc., please check whether the type of the item and sound in the configuration file exists in the current version.
|
||||
|
||||
Take the SOUND as an example. The sound that the villager said "OK" is "[U]VILLAGER_YES[/U]" in the lower version, but it becomes "[U]ENTITY_VILLAGER_YES[/U]" in the higher version.
|
||||
|
||||
[SIZE=4][B]2. Scoreboard exception problem[/B][/SIZE]
|
||||
The display of the prefix on the head and the sorting of the TabList both use the scoreboard API.
|
||||
|
||||
Please turn of the [U]functions.OnNamePrefix[/U] in the configuration if there is a conflict.
|
||||
|
||||
[SIZE=4][B]3. Item icon configuration problem[/B][/SIZE]
|
||||
Items are read through the ItemStack serialization method provided by Bukkit. For related configuration methods, please refer to [URL='https://www.spigotmc.org/wiki/itemstack-serialization/']ItemStack Serialization[/URL].
|
||||
|
||||
[SIZE=5][B]Commands[/B]
|
||||
[/SIZE]
|
||||
[code]
|
||||
/UserPrefix or /prefix #Open prefix GUI
|
||||
/UserPrefixAdmin # View Admin Command Help
|
||||
/UserPrefixAdmin reload # Reload Config
|
||||
/UserPrefixAdmin list # List all configured prefixes.
|
||||
[/code]
|
||||
|
||||
[SIZE=5][B]Placeholders (PlaceholderAPI)[/B][/SIZE]
|
||||
After installed the [URL='https://github.com/PlaceholderAPI/PlaceholderAPI']PlaceholderAPI[/URL] , you can type /papi info UserPrefix to see all the placeholders.
|
||||
|
||||
[code]
|
||||
# %UserPrefix_prefix%
|
||||
- Get the content of the current prefix
|
||||
# %UserPrefix_weight%
|
||||
- Get the weight of the current prefix.
|
||||
# %UserPrefix_identifier%
|
||||
- Get the identifier of the current prefix.
|
||||
# %UserPrefix_name%
|
||||
- Get the name of the current prefix.
|
||||
# %UserPrefix_has_<Identifier>%
|
||||
- Determine whether the player has a certain prefix(true/false)
|
||||
[/code]
|
||||
|
||||
[SIZE=5][B]Configuration Files[/B][/SIZE]
|
||||
[B][SIZE=4][URL='https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/en_US/config.yml']Plugin Configuration[/URL] (config.yml)[/SIZE]
|
||||
[/B]
|
||||
Notice: The default configuration is based on Chinese. You can find the English Version [URL='https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/en_US/config.yml']here[/URL].
|
||||
|
||||
[code=YAML]
|
||||
version: ${project.version} # DO NOT EDIT IT
|
||||
|
||||
debug: false #DEBUG OUT PUT
|
||||
|
||||
GUI:
|
||||
title: "&f&lMy Prefixes List" # Title of the GUI
|
||||
items:
|
||||
next-page: # only show has next page
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: ARROW
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fNext Page"
|
||||
lore:
|
||||
- ""
|
||||
- "§fRight-Click to the last page"
|
||||
previous-page: # only show has previous page
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: ARROW
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fPrevious Page"
|
||||
lore:
|
||||
- ""
|
||||
- "§fRight-Click to the first page"
|
||||
|
||||
functions:
|
||||
# Whether to add a prefix to the top of the head,
|
||||
# this method uses the scoreboard above the head,
|
||||
# please turn it off if there is a conflict.
|
||||
OnNamePrefix: true
|
||||
# Automatic prefix select.
|
||||
# When the player does not choose a prefix by himself,
|
||||
# the prefix with the highest weight will be used automatically
|
||||
autoUsePrefix: true
|
||||
chat:
|
||||
# Chat Function
|
||||
# - I recommend using other chat plugins instead of using this plugin,
|
||||
# - this plugin only provides very basic chat format placeholders.
|
||||
# - Notice that: format must has “%1$s” and “%2$s” for PlayerName and Message (Bukkit Chat Event)
|
||||
enable: false
|
||||
format: "<%UserPrefix_prefix%%1$s> %2$s"
|
||||
|
||||
Sounds:
|
||||
# Format is [SOUND_NAME:Volume:Pitch] or [SOUND_NAME:Volume] or [SOUND_NAME]
|
||||
openGUI: "BLOCK_NOTE_BLOCK_PLING:1:1"
|
||||
guiClick: "UI_BUTTON_CLICK"
|
||||
prefixChange: "ENTITY_VILLAGER_YES"
|
||||
prefixExpired: "ENTITY_VILLAGER_NO"
|
||||
|
||||
# The default prefix's weight is 0.
|
||||
defaultPrefix:
|
||||
name: "Default prefix"
|
||||
content: "&b"
|
||||
itemNotUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: NAME_TAG
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fThe default prefix §f(Click to select)"
|
||||
lore:
|
||||
- ""
|
||||
- "§a➥ Click to use"
|
||||
itemUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: NAME_TAG
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§fThe default prefix"
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ Selected"
|
||||
[/code]
|
||||
|
||||
[B][SIZE=4][URL='https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/en_US/messages.yml']Messages Configuration[/URL] (messages.yml)[/SIZE][/B]
|
||||
[code=YAML]
|
||||
selected:
|
||||
- "&7You have selected the &f%(name) &7as current prefix."
|
||||
expired:
|
||||
- "&7Your prefix &f%(oldName) &7has expired,"
|
||||
- "&7Now the prefix is changed to &f%(newName) &7."
|
||||
reload:
|
||||
- "&a&lReload completed!&7costs &f%(time)ms&7."
|
||||
help:
|
||||
- "&3&lUserPrefixAdmin &fHelp"
|
||||
- "&8#/upa&f list"
|
||||
- "&8- &7Show configured prefixes."
|
||||
- "&8#/upa&f reload"
|
||||
- "&8- &7Reload configuration."
|
||||
list-title:
|
||||
- "&3&lUserPrefixAdmin &fList"
|
||||
list-value:
|
||||
- "&8#%(weight) &f%(identifier)"
|
||||
- "&8- &7Name &r%(name) &7Perm &r%(permission)"
|
||||
- "&8- &7Example&r %(content) %(sender_name)"
|
||||
[/code]
|
||||
|
||||
[B][URL='https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/en_US/example-prefix.yml']Prefixes [/URL][B][URL='https://github.com/CarmJos/UserPrefix/blob/master/src/main/resources/en_US/example-prefix.yml']Configuration[/URL] [/B](/prefixes/*.yml)
|
||||
[/B]
|
||||
All prefixes are separate configuration files, stored in the [U]<Data Folder>/prefixes/[/U] for easy management.
|
||||
|
||||
Some symbols in file name may affect reading, please avoid using them.
|
||||
|
||||
[code]# identifier [Necessary]
|
||||
# This will be used for data-storage.
|
||||
identifier: "pro"
|
||||
|
||||
# Name [Necessary]
|
||||
# Use in messages.
|
||||
name: "&b&lPro&b"
|
||||
|
||||
# Content [Necessary]
|
||||
# Use in Placeholders
|
||||
content: "§b§lPro §b"
|
||||
|
||||
# Weight [Necessary]
|
||||
# used for sorting in the GUI and TabList
|
||||
# In GUI : the larger is displayed at the back
|
||||
# At TabList : the larger is displayed at the top
|
||||
weight: 1
|
||||
|
||||
# Permission [Unnecessary]
|
||||
# If there is no permission for detection, everyone can use it,
|
||||
# which means there is no need to configure "itemNoPermission"
|
||||
# (because it is impossible to display items without permission at all)
|
||||
permission: "yc.vip"
|
||||
|
||||
# itemHasPermission [Necessary]
|
||||
# This Item will be displayed when player has permission
|
||||
itemHasPermission:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP Prefix"
|
||||
lore:
|
||||
- ""
|
||||
- "§a➥ Click to use"
|
||||
|
||||
# itemUsing [Unnecessary]
|
||||
# This Item will be displayed when the prefix is selected.
|
||||
# If there is no such configuration, it will automatically display "itemHasPermission".
|
||||
itemUsing:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: DIAMOND
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP Prefix"
|
||||
enchants:
|
||||
PROTECTION_ENVIRONMENTAL: 1 #Add an enchantment so it looks like it’s selected
|
||||
lore:
|
||||
- ""
|
||||
- "§a✔ Selected"
|
||||
|
||||
# itemNoPermission [Unnecessary]
|
||||
# If player doesn't have the permission,this item will be displayed.
|
||||
# If this item is not configured, it will not be displayed in the GUI when the player does not have permission to use it.
|
||||
itemNoPermission:
|
||||
==: org.bukkit.inventory.ItemStack
|
||||
type: INK_SACK
|
||||
damage: 8
|
||||
meta:
|
||||
==: ItemMeta
|
||||
meta-type: UNSPECIFIC
|
||||
display-name: "§b§lVIP §c(Buy it!)"
|
||||
lore:
|
||||
- ""
|
||||
- "§e✯ Buy the VIP to use it!"[/code]
|
||||
|
||||
|
||||
|
||||
[SIZE=5][B]Support and Donation[/B][/SIZE]
|
||||
This project is support by the [URL='https://www.ycraft.cn/']YourCraft(你的世界)[/URL] . [URL='https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/team-logo.png'][IMG]https://raw.githubusercontent.com/CarmJos/UserPrefix/master/img/team-logo.png[/IMG][/URL]
|
||||
|
||||
[SIZE=5][B]Open source agreement[/B][/SIZE]
|
||||
The source code of this project uses [URL='https://opensource.org/licenses/GPL-3.0']GNU General Public License v3.0[/URL] License.
|
||||
Reference in New Issue
Block a user