init
This commit is contained in:
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
.mtj.tmp/
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
.idea
|
||||||
|
.gradle
|
||||||
|
build
|
||||||
|
run
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
/temp/
|
||||||
|
runs/
|
||||||
504
LICENSE
Normal file
504
LICENSE
Normal file
@@ -0,0 +1,504 @@
|
|||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 2.1, February 1999
|
||||||
|
|
||||||
|
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
[This is the first released version of the Lesser GPL. It also counts
|
||||||
|
as the successor of the GNU Library Public License, version 2, hence
|
||||||
|
the version number 2.1.]
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
Licenses are intended to guarantee your freedom to share and change
|
||||||
|
free software--to make sure the software is free for all its users.
|
||||||
|
|
||||||
|
This license, the Lesser General Public License, applies to some
|
||||||
|
specially designated software packages--typically libraries--of the
|
||||||
|
Free Software Foundation and other authors who decide to use it. You
|
||||||
|
can use it too, but we suggest you first think carefully about whether
|
||||||
|
this license or the ordinary General Public License is the better
|
||||||
|
strategy to use in any particular case, based on the explanations below.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom of use,
|
||||||
|
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 this service if you wish); that you receive source code or can get
|
||||||
|
it if you want it; that you can change the software and use pieces of
|
||||||
|
it in new free programs; and that you are informed that you can do
|
||||||
|
these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
distributors to deny you these rights or to ask you to surrender these
|
||||||
|
rights. These restrictions translate to certain responsibilities for
|
||||||
|
you if you distribute copies of the library or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of the library, whether gratis
|
||||||
|
or for a fee, you must give the recipients all the rights that we gave
|
||||||
|
you. You must make sure that they, too, receive or can get the source
|
||||||
|
code. If you link other code with the library, you must provide
|
||||||
|
complete object files to the recipients, so that they can relink them
|
||||||
|
with the library after making changes to the library and recompiling
|
||||||
|
it. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
We protect your rights with a two-step method: (1) we copyright the
|
||||||
|
library, and (2) we offer you this license, which gives you legal
|
||||||
|
permission to copy, distribute and/or modify the library.
|
||||||
|
|
||||||
|
To protect each distributor, we want to make it very clear that
|
||||||
|
there is no warranty for the free library. Also, if the library is
|
||||||
|
modified by someone else and passed on, the recipients should know
|
||||||
|
that what they have is not the original version, so that the original
|
||||||
|
author's reputation will not be affected by problems that might be
|
||||||
|
introduced by others.
|
||||||
|
|
||||||
|
Finally, software patents pose a constant threat to the existence of
|
||||||
|
any free program. We wish to make sure that a company cannot
|
||||||
|
effectively restrict the users of a free program by obtaining a
|
||||||
|
restrictive license from a patent holder. Therefore, we insist that
|
||||||
|
any patent license obtained for a version of the library must be
|
||||||
|
consistent with the full freedom of use specified in this license.
|
||||||
|
|
||||||
|
Most GNU software, including some libraries, is covered by the
|
||||||
|
ordinary GNU General Public License. This license, the GNU Lesser
|
||||||
|
General Public License, applies to certain designated libraries, and
|
||||||
|
is quite different from the ordinary General Public License. We use
|
||||||
|
this license for certain libraries in order to permit linking those
|
||||||
|
libraries into non-free programs.
|
||||||
|
|
||||||
|
When a program is linked with a library, whether statically or using
|
||||||
|
a shared library, the combination of the two is legally speaking a
|
||||||
|
combined work, a derivative of the original library. The ordinary
|
||||||
|
General Public License therefore permits such linking only if the
|
||||||
|
entire combination fits its criteria of freedom. The Lesser General
|
||||||
|
Public License permits more lax criteria for linking other code with
|
||||||
|
the library.
|
||||||
|
|
||||||
|
We call this license the "Lesser" General Public License because it
|
||||||
|
does Less to protect the user's freedom than the ordinary General
|
||||||
|
Public License. It also provides other free software developers Less
|
||||||
|
of an advantage over competing non-free programs. These disadvantages
|
||||||
|
are the reason we use the ordinary General Public License for many
|
||||||
|
libraries. However, the Lesser license provides advantages in certain
|
||||||
|
special circumstances.
|
||||||
|
|
||||||
|
For example, on rare occasions, there may be a special need to
|
||||||
|
encourage the widest possible use of a certain library, so that it becomes
|
||||||
|
a de-facto standard. To achieve this, non-free programs must be
|
||||||
|
allowed to use the library. A more frequent case is that a free
|
||||||
|
library does the same job as widely used non-free libraries. In this
|
||||||
|
case, there is little to gain by limiting the free library to free
|
||||||
|
software only, so we use the Lesser General Public License.
|
||||||
|
|
||||||
|
In other cases, permission to use a particular library in non-free
|
||||||
|
programs enables a greater number of people to use a large body of
|
||||||
|
free software. For example, permission to use the GNU C Library in
|
||||||
|
non-free programs enables many more people to use the whole GNU
|
||||||
|
operating system, as well as its variant, the GNU/Linux operating
|
||||||
|
system.
|
||||||
|
|
||||||
|
Although the Lesser General Public License is Less protective of the
|
||||||
|
users' freedom, it does ensure that the user of a program that is
|
||||||
|
linked with the Library has the freedom and the wherewithal to run
|
||||||
|
that program using a modified version of the Library.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow. Pay close attention to the difference between a
|
||||||
|
"work based on the library" and a "work that uses the library". The
|
||||||
|
former contains code derived from the library, whereas the latter must
|
||||||
|
be combined with the library in order to run.
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any software library or other
|
||||||
|
program which contains a notice placed by the copyright holder or
|
||||||
|
other authorized party saying it may be distributed under the terms of
|
||||||
|
this Lesser General Public License (also called "this License").
|
||||||
|
Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
A "library" means a collection of software functions and/or data
|
||||||
|
prepared so as to be conveniently linked with application programs
|
||||||
|
(which use some of those functions and data) to form executables.
|
||||||
|
|
||||||
|
The "Library", below, refers to any such software library or work
|
||||||
|
which has been distributed under these terms. A "work based on the
|
||||||
|
Library" means either the Library or any derivative work under
|
||||||
|
copyright law: that is to say, a work containing the Library or a
|
||||||
|
portion of it, either verbatim or with modifications and/or translated
|
||||||
|
straightforwardly into another language. (Hereinafter, translation is
|
||||||
|
included without limitation in the term "modification".)
|
||||||
|
|
||||||
|
"Source code" for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For a library, complete source code means
|
||||||
|
all the source code for all modules it contains, plus any associated
|
||||||
|
interface definition files, plus the scripts used to control compilation
|
||||||
|
and installation of the library.
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running a program using the Library is not restricted, and output from
|
||||||
|
such a program is covered only if its contents constitute a work based
|
||||||
|
on the Library (independent of the use of the Library in a tool for
|
||||||
|
writing it). Whether that is true depends on what the Library does
|
||||||
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
|
complete source code as you receive it, in any medium, provided that
|
||||||
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||||
|
all the notices that refer to this License and to the absence of any
|
||||||
|
warranty; and distribute a copy of this License along with the
|
||||||
|
Library.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy,
|
||||||
|
and you may at your option offer warranty protection in exchange for a
|
||||||
|
fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Library or any portion
|
||||||
|
of it, thus forming a work based on the Library, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The modified work must itself be a software library.
|
||||||
|
|
||||||
|
b) You must cause the files modified to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
c) You must cause the whole of the work to be licensed at no
|
||||||
|
charge to all third parties under the terms of this License.
|
||||||
|
|
||||||
|
d) If a facility in the modified Library refers to a function or a
|
||||||
|
table of data to be supplied by an application program that uses
|
||||||
|
the facility, other than as an argument passed when the facility
|
||||||
|
is invoked, then you must make a good faith effort to ensure that,
|
||||||
|
in the event an application does not supply such function or
|
||||||
|
table, the facility still operates, and performs whatever part of
|
||||||
|
its purpose remains meaningful.
|
||||||
|
|
||||||
|
(For example, a function in a library to compute square roots has
|
||||||
|
a purpose that is entirely well-defined independent of the
|
||||||
|
application. Therefore, Subsection 2d requires that any
|
||||||
|
application-supplied function or table used by this function must
|
||||||
|
be optional: if the application does not supply it, the square
|
||||||
|
root function must still compute square roots.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Library,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Library, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote
|
||||||
|
it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Library.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Library
|
||||||
|
with the Library (or with a work based on the Library) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||||
|
License instead of this License to a given copy of the Library. To do
|
||||||
|
this, you must alter all the notices that refer to this License, so
|
||||||
|
that they refer to the ordinary GNU General Public License, version 2,
|
||||||
|
instead of to this License. (If a newer version than version 2 of the
|
||||||
|
ordinary GNU General Public License has appeared, then you can specify
|
||||||
|
that version instead if you wish.) Do not make any other change in
|
||||||
|
these notices.
|
||||||
|
|
||||||
|
Once this change is made in a given copy, it is irreversible for
|
||||||
|
that copy, so the ordinary GNU General Public License applies to all
|
||||||
|
subsequent copies and derivative works made from that copy.
|
||||||
|
|
||||||
|
This option is useful when you wish to copy part of the code of
|
||||||
|
the Library into a program that is not a library.
|
||||||
|
|
||||||
|
4. You may copy and distribute the Library (or a portion or
|
||||||
|
derivative of it, under Section 2) in object code or executable form
|
||||||
|
under the terms of Sections 1 and 2 above provided that you accompany
|
||||||
|
it with the complete corresponding machine-readable source code, which
|
||||||
|
must be distributed under the terms of Sections 1 and 2 above on a
|
||||||
|
medium customarily used for software interchange.
|
||||||
|
|
||||||
|
If distribution of object code is made by offering access to copy
|
||||||
|
from a designated place, then offering equivalent access to copy the
|
||||||
|
source code from the same place satisfies the requirement to
|
||||||
|
distribute the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
5. A program that contains no derivative of any portion of the
|
||||||
|
Library, but is designed to work with the Library by being compiled or
|
||||||
|
linked with it, is called a "work that uses the Library". Such a
|
||||||
|
work, in isolation, is not a derivative work of the Library, and
|
||||||
|
therefore falls outside the scope of this License.
|
||||||
|
|
||||||
|
However, linking a "work that uses the Library" with the Library
|
||||||
|
creates an executable that is a derivative of the Library (because it
|
||||||
|
contains portions of the Library), rather than a "work that uses the
|
||||||
|
library". The executable is therefore covered by this License.
|
||||||
|
Section 6 states terms for distribution of such executables.
|
||||||
|
|
||||||
|
When a "work that uses the Library" uses material from a header file
|
||||||
|
that is part of the Library, the object code for the work may be a
|
||||||
|
derivative work of the Library even though the source code is not.
|
||||||
|
Whether this is true is especially significant if the work can be
|
||||||
|
linked without the Library, or if the work is itself a library. The
|
||||||
|
threshold for this to be true is not precisely defined by law.
|
||||||
|
|
||||||
|
If such an object file uses only numerical parameters, data
|
||||||
|
structure layouts and accessors, and small macros and small inline
|
||||||
|
functions (ten lines or less in length), then the use of the object
|
||||||
|
file is unrestricted, regardless of whether it is legally a derivative
|
||||||
|
work. (Executables containing this object code plus portions of the
|
||||||
|
Library will still fall under Section 6.)
|
||||||
|
|
||||||
|
Otherwise, if the work is a derivative of the Library, you may
|
||||||
|
distribute the object code for the work under the terms of Section 6.
|
||||||
|
Any executables containing that work also fall under Section 6,
|
||||||
|
whether or not they are linked directly with the Library itself.
|
||||||
|
|
||||||
|
6. As an exception to the Sections above, you may also combine or
|
||||||
|
link a "work that uses the Library" with the Library to produce a
|
||||||
|
work containing portions of the Library, and distribute that work
|
||||||
|
under terms of your choice, provided that the terms permit
|
||||||
|
modification of the work for the customer's own use and reverse
|
||||||
|
engineering for debugging such modifications.
|
||||||
|
|
||||||
|
You must give prominent notice with each copy of the work that the
|
||||||
|
Library is used in it and that the Library and its use are covered by
|
||||||
|
this License. You must supply a copy of this License. If the work
|
||||||
|
during execution displays copyright notices, you must include the
|
||||||
|
copyright notice for the Library among them, as well as a reference
|
||||||
|
directing the user to the copy of this License. Also, you must do one
|
||||||
|
of these things:
|
||||||
|
|
||||||
|
a) Accompany the work with the complete corresponding
|
||||||
|
machine-readable source code for the Library including whatever
|
||||||
|
changes were used in the work (which must be distributed under
|
||||||
|
Sections 1 and 2 above); and, if the work is an executable linked
|
||||||
|
with the Library, with the complete machine-readable "work that
|
||||||
|
uses the Library", as object code and/or source code, so that the
|
||||||
|
user can modify the Library and then relink to produce a modified
|
||||||
|
executable containing the modified Library. (It is understood
|
||||||
|
that the user who changes the contents of definitions files in the
|
||||||
|
Library will not necessarily be able to recompile the application
|
||||||
|
to use the modified definitions.)
|
||||||
|
|
||||||
|
b) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (1) uses at run time a
|
||||||
|
copy of the library already present on the user's computer system,
|
||||||
|
rather than copying library functions into the executable, and (2)
|
||||||
|
will operate properly with a modified version of the library, if
|
||||||
|
the user installs one, as long as the modified version is
|
||||||
|
interface-compatible with the version that the work was made with.
|
||||||
|
|
||||||
|
c) Accompany the work with a written offer, valid for at
|
||||||
|
least three years, to give the same user the materials
|
||||||
|
specified in Subsection 6a, above, for a charge no more
|
||||||
|
than the cost of performing this distribution.
|
||||||
|
|
||||||
|
d) If distribution of the work is made by offering access to copy
|
||||||
|
from a designated place, offer equivalent access to copy the above
|
||||||
|
specified materials from the same place.
|
||||||
|
|
||||||
|
e) Verify that the user has already received a copy of these
|
||||||
|
materials or that you have already sent this user a copy.
|
||||||
|
|
||||||
|
For an executable, the required form of the "work that uses the
|
||||||
|
Library" must include any data and utility programs needed for
|
||||||
|
reproducing the executable from it. However, as a special exception,
|
||||||
|
the materials to be distributed need not include anything that is
|
||||||
|
normally distributed (in either source or binary form) with the major
|
||||||
|
components (compiler, kernel, and so on) of the operating system on
|
||||||
|
which the executable runs, unless that component itself accompanies
|
||||||
|
the executable.
|
||||||
|
|
||||||
|
It may happen that this requirement contradicts the license
|
||||||
|
restrictions of other proprietary libraries that do not normally
|
||||||
|
accompany the operating system. Such a contradiction means you cannot
|
||||||
|
use both them and the Library together in an executable that you
|
||||||
|
distribute.
|
||||||
|
|
||||||
|
7. You may place library facilities that are a work based on the
|
||||||
|
Library side-by-side in a single library together with other library
|
||||||
|
facilities not covered by this License, and distribute such a combined
|
||||||
|
library, provided that the separate distribution of the work based on
|
||||||
|
the Library and of the other library facilities is otherwise
|
||||||
|
permitted, and provided that you do these two things:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work
|
||||||
|
based on the Library, uncombined with any other library
|
||||||
|
facilities. This must be distributed under the terms of the
|
||||||
|
Sections above.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library of the fact
|
||||||
|
that part of it is a work based on the Library, and explaining
|
||||||
|
where to find the accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
8. You may not copy, modify, sublicense, link with, or distribute
|
||||||
|
the Library except as expressly provided under this License. Any
|
||||||
|
attempt otherwise to copy, modify, sublicense, link with, or
|
||||||
|
distribute the Library is void, and will automatically terminate your
|
||||||
|
rights under this License. However, parties who have received copies,
|
||||||
|
or rights, from you under this License will not have their licenses
|
||||||
|
terminated so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
9. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Library or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Library (or any work based on the
|
||||||
|
Library), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Library or works based on it.
|
||||||
|
|
||||||
|
10. Each time you redistribute the Library (or any work based on the
|
||||||
|
Library), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute, link with or modify the Library
|
||||||
|
subject to these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties with
|
||||||
|
this License.
|
||||||
|
|
||||||
|
11. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
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
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Library at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Library by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Library.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply,
|
||||||
|
and the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
12. If the distribution and/or use of the Library is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Library under this License may add
|
||||||
|
an explicit geographical distribution limitation excluding those countries,
|
||||||
|
so that distribution is permitted only in or among countries not thus
|
||||||
|
excluded. In such case, this License incorporates the limitation as if
|
||||||
|
written in the body of this License.
|
||||||
|
|
||||||
|
13. The Free Software Foundation may publish revised and/or new
|
||||||
|
versions of the Lesser 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 Library
|
||||||
|
specifies a version number of this License which applies to it and
|
||||||
|
"any later version", you have the option of following the terms and
|
||||||
|
conditions either of that version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Library does not specify a
|
||||||
|
license version number, you may choose any version ever published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
14. If you wish to incorporate parts of the Library into other free
|
||||||
|
programs whose distribution conditions are incompatible with these,
|
||||||
|
write to the author to ask for permission. For software which is
|
||||||
|
copyrighted by the Free Software Foundation, write to the Free
|
||||||
|
Software Foundation; we sometimes make exceptions for this. Our
|
||||||
|
decision will be guided by the two goals of preserving the free status
|
||||||
|
of all derivatives of our free software and of promoting the sharing
|
||||||
|
and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||||
|
OTHER PARTIES PROVIDE THE LIBRARY "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
|
||||||
|
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||||
|
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||||
|
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||||
|
AND/OR REDISTRIBUTE THE LIBRARY 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
|
||||||
|
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||||
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Libraries
|
||||||
|
|
||||||
|
If you develop a new library, and you want it to be of the greatest
|
||||||
|
possible use to the public, we recommend making it free software that
|
||||||
|
everyone can redistribute and change. You can do so by permitting
|
||||||
|
redistribution under these terms (or, alternatively, under the terms of the
|
||||||
|
ordinary General Public License).
|
||||||
|
|
||||||
|
To apply these terms, attach the following notices to the library. It is
|
||||||
|
safest to attach them to the start of each source file to most effectively
|
||||||
|
convey 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 library's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||||
|
USA
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||||
|
library `Frob' (a library for tweaking knobs) written by James Random
|
||||||
|
Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1990
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
That's all there is to it!
|
||||||
184
build.gradle
Normal file
184
build.gradle
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java-library'
|
||||||
|
id 'eclipse'
|
||||||
|
id 'idea'
|
||||||
|
id 'maven-publish'
|
||||||
|
id 'net.neoforged.gradle.userdev' version '7.0.145'
|
||||||
|
}
|
||||||
|
|
||||||
|
version = mod_version
|
||||||
|
group = 'dev.kxmc'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
base {
|
||||||
|
archivesName = mod_id
|
||||||
|
}
|
||||||
|
|
||||||
|
java.toolchain.languageVersion = JavaLanguageVersion.of(21)
|
||||||
|
|
||||||
|
minecraft.accessTransformers.file rootProject.file('src/main/resources/META-INF/accesstransformer.cfg')
|
||||||
|
|
||||||
|
runs {
|
||||||
|
configureEach {
|
||||||
|
systemProperty 'forge.logging.markers', 'REGISTRIES'
|
||||||
|
systemProperty 'forge.logging.console.level', 'debug'
|
||||||
|
modSource project.sourceSets.main
|
||||||
|
}
|
||||||
|
client {
|
||||||
|
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
|
||||||
|
}
|
||||||
|
server {
|
||||||
|
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
|
||||||
|
programArgument '--nogui'
|
||||||
|
}
|
||||||
|
gameTestServer {
|
||||||
|
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
|
||||||
|
}
|
||||||
|
data {
|
||||||
|
programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets.main.resources { srcDir 'src/generated/resources' }
|
||||||
|
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "net.neoforged:neoforge:${neo_version}"
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(ProcessResources).configureEach {
|
||||||
|
var replaceProperties = [
|
||||||
|
minecraft_version : minecraft_version, minecraft_version_range: minecraft_version_range,
|
||||||
|
neo_version : neo_version, neo_version_range: neo_version_range,
|
||||||
|
loader_version_range: loader_version_range,
|
||||||
|
mod_id : mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version,
|
||||||
|
mod_authors : mod_authors, mod_description: mod_description,
|
||||||
|
]
|
||||||
|
inputs.properties replaceProperties
|
||||||
|
|
||||||
|
filesMatching(['META-INF/mods.toml']) {
|
||||||
|
expand replaceProperties + [project: project]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example configuration to allow publishing using the maven-publish plugin
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
register('mavenJava', MavenPublication) {
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
url "file://${project.projectDir}/repo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lljij.toBoolean()) jarJar.enable()
|
||||||
|
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes([
|
||||||
|
"Specification-Title" : "${mod_id}",
|
||||||
|
"Specification-Vendor" : "xkmc",
|
||||||
|
"Specification-Version" : "1", // We are version 1 of ourselves
|
||||||
|
"Implementation-Title" : project.name,
|
||||||
|
"Implementation-Version" : project.jar.archiveVersion,
|
||||||
|
"Implementation-Vendor" : "xkmc",
|
||||||
|
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||||
|
'MixinConfigs' : "${mod_id}.mixins.json"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lljij.toBoolean()) {
|
||||||
|
|
||||||
|
tasks.jarJar.configure {
|
||||||
|
archiveClassifier.set('')
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
archiveClassifier.set('slim')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
//annotationProcessor "org.spongepowered:mixin:${mixin_version}:processor"
|
||||||
|
//compileOnly fg.deobf("com.tterrag.registrate:Registrate:${registrate_version}")
|
||||||
|
if (rootMod.toBoolean()) {
|
||||||
|
//jarJar(group: 'com.tterrag.registrate', name: 'Registrate', version: "[MC1.20,MC1.21)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// project specific
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
flatDir {
|
||||||
|
dirs 'libs'
|
||||||
|
}
|
||||||
|
maven { // Registrate
|
||||||
|
url "https://maven.tterrag.com/"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url = "https://maven.theillusivec4.top/"
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
// Location of the maven for vazkii's mods
|
||||||
|
name 'blamejared'
|
||||||
|
url 'https://maven.blamejared.com'
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url 'https://www.cursemaven.com'
|
||||||
|
content {
|
||||||
|
includeGroup "curse.maven"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
// Location of the maven that hosts JEI files (and TiC)
|
||||||
|
name 'Progwml6 maven'
|
||||||
|
url 'https://dvs1.progwml6.com/files/maven'
|
||||||
|
}
|
||||||
|
mavenLocal();
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// base dep
|
||||||
|
implementation "mezz.jei:jei-${jei_minecraft_version}:${jei_version}"
|
||||||
|
//implementation "top.theillusivec4.curios:curios-neoforge:${curios_version}"
|
||||||
|
|
||||||
|
implementation "dev.xkmc:l2serial:${l2serial_ver}"
|
||||||
|
|
||||||
|
//runtimeOnly fg.deobf("dev.xkmc.l2damagetracker:l2damagetracker:0.2.4")
|
||||||
|
//runtimeOnly fg.deobf("dev.xkmc.l2backpack:l2backpack:2.4.12-slim")
|
||||||
|
//runtimeOnly fg.deobf("dev.xkmc.l2complements:l2complements:2.4.18-slim")
|
||||||
|
//runtimeOnly fg.deobf('dev.xkmc.modulargolems:modulargolems:2.4.16-slim')
|
||||||
|
//runtimeOnly fg.deobf("dev.xkmc.l2archery:l2archery:2.4.9")
|
||||||
|
//runtimeOnly fg.deobf("dev.xkmc.l2weaponry:l2weaponry:2.4.18")
|
||||||
|
//runtimeOnly fg.deobf("dev.xkmc.l2artifacts:l2artifacts:2.4.8-slim")
|
||||||
|
|
||||||
|
//runtimeOnly fg.deobf("curse.maven:create-328085:4626108")
|
||||||
|
//implementation fg.deobf("curse.maven:just-enough-effect-descriptions-jeed-532286:4599236")
|
||||||
|
|
||||||
|
//runtimeOnly fg.deobf("curse.maven:badpackets-615134:4438956")
|
||||||
|
//runtimeOnly fg.deobf("curse.maven:wthit-forge-455982:4596739")
|
||||||
|
//runtimeOnly fg.deobf("curse.maven:attributefix-280510:4588114")
|
||||||
|
//runtimeOnly fg.deobf("curse.maven:bookshelf-228525:4581675")
|
||||||
|
//runtimeOnly fg.deobf("curse.maven:enchantment-descriptions-250419:4587429")
|
||||||
|
//runtimeOnly fg.deobf("curse.maven:appleskin-248787:4605078")
|
||||||
|
//implementation fg.deobf("curse.maven:patchouli-306770:4636277")
|
||||||
|
|
||||||
|
//runtimeOnly fg.deobf("dev.xkmc.traderefresh:traderefresh:2.1.1-slim")
|
||||||
|
//runtimeOnly fg.deobf("dev.xkmc.lasertransport:lasertransport:2.2.0.pre5-slim")
|
||||||
|
|
||||||
|
//runtimeOnly fg.deobf('curse.maven:max-health-fix-492246:4447240')
|
||||||
|
//runtimeOnly fg.deobf('curse.maven:the-twilight-forest-227639:4516391')
|
||||||
|
}
|
||||||
33
gradle.properties
Normal file
33
gradle.properties
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
|
||||||
|
org.gradle.jvmargs=-Xmx3G
|
||||||
|
org.gradle.daemon=false
|
||||||
|
org.gradle.debug=false
|
||||||
|
|
||||||
|
#read more on this at https://github.com/neoforged/NeoGradle/blob/NG_7.0/README.md#apply-parchment-mappings
|
||||||
|
# you can also find the latest versions at: https://parchmentmc.org/docs/getting-started
|
||||||
|
neogradle.subsystems.parchment.minecraftVersion=1.20.6
|
||||||
|
neogradle.subsystems.parchment.mappingsVersion=2024.06.02
|
||||||
|
|
||||||
|
minecraft_version=1.21
|
||||||
|
minecraft_version_range=[1.21,1.22)
|
||||||
|
neo_version=21.0.19-beta
|
||||||
|
neo_version_range=[21.0,)
|
||||||
|
loader_version_range=[2,)
|
||||||
|
|
||||||
|
## Mod Properties
|
||||||
|
mod_id=l2core
|
||||||
|
mod_name=L2Core
|
||||||
|
mod_license=LGPL-2.1
|
||||||
|
mod_version=3.0.0-pre0
|
||||||
|
mod_group_id=dev.xkmc
|
||||||
|
mod_authors=lcy0x1
|
||||||
|
mod_description=Core Library mod for all L2 mods
|
||||||
|
|
||||||
|
|
||||||
|
jei_minecraft_version = 1.21-neoforge
|
||||||
|
jei_version = 19.0.0.7
|
||||||
|
|
||||||
|
lljij = false
|
||||||
|
rootMod = false
|
||||||
|
|
||||||
|
l2serial_ver = 3.0.0-pre1
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
245
gradlew
vendored
Executable file
245
gradlew
vendored
Executable file
@@ -0,0 +1,245 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# This is normally unused
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC3045
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC3045
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
92
gradlew.bat
vendored
Normal file
92
gradlew.bat
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%"=="" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
BIN
libs/l2modularblocks-3.0.0-pre0.jar
Normal file
BIN
libs/l2modularblocks-3.0.0-pre0.jar
Normal file
Binary file not shown.
BIN
libs/l2serial-3.0.0-pre1-sources.jar
Normal file
BIN
libs/l2serial-3.0.0-pre1-sources.jar
Normal file
Binary file not shown.
BIN
libs/l2serial-3.0.0-pre1.jar
Normal file
BIN
libs/l2serial-3.0.0-pre1.jar
Normal file
Binary file not shown.
11
settings.gradle
Normal file
11
settings.gradle
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
gradlePluginPortal()
|
||||||
|
maven { url = 'https://maven.neoforged.net/releases' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
// 1.20.1 2023-07-17T13:58:00.905748 Registrate Provider for l2library [Recipes, Advancements, Loot Tables, Tags (blocks), Tags (items), Tags (fluids), Tags (entity_types), Blockstates, Item models, Lang (en_us/en_ud)]
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.capability.attachment.GeneralCapabilityTemplate;
|
||||||
|
import dev.xkmc.l2serial.serialization.SerialClass;
|
||||||
|
import net.minecraft.world.effect.MobEffect;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
@SerialClass
|
||||||
|
public class ClientEffectCap extends GeneralCapabilityTemplate<LivingEntity, ClientEffectCap> {
|
||||||
|
|
||||||
|
public final Map<MobEffect, Integer> map = new TreeMap<>(Comparator.comparing(MobEffect::getDescriptionId));
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects;
|
||||||
|
|
||||||
|
import net.minecraft.world.effect.MobEffect;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
|
||||||
|
public class EffectBuilder {
|
||||||
|
|
||||||
|
public final MobEffectInstance ins;
|
||||||
|
|
||||||
|
public EffectBuilder(MobEffectInstance ins) {
|
||||||
|
this.ins = ins;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EffectBuilder(MobEffect effect) {
|
||||||
|
this.ins = new MobEffectInstance(effect, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EffectBuilder setAmplifier(int amplifier) {
|
||||||
|
ins.amplifier = amplifier;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EffectBuilder setDuration(int duration) {
|
||||||
|
ins.duration = duration;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EffectBuilder setVisible(boolean visible) {
|
||||||
|
ins.visible = visible;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EffectBuilder setAmbient(boolean ambient) {
|
||||||
|
ins.ambient = ambient;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EffectBuilder setShowIcon(boolean showIcon) {
|
||||||
|
ins.showIcon = showIcon;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects;
|
||||||
|
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
|
||||||
|
public class EffectProperties {
|
||||||
|
|
||||||
|
public Boolean ambient = null;
|
||||||
|
public Boolean visible = null;
|
||||||
|
public Boolean showIcon = null;
|
||||||
|
|
||||||
|
public MobEffectInstance set(MobEffectInstance ins) {
|
||||||
|
if (ambient != null) ins.ambient = ambient;
|
||||||
|
if (visible != null) ins.visible = visible;
|
||||||
|
if (showIcon != null) ins.showIcon = showIcon;
|
||||||
|
return ins;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.init.events.ClientEffectRenderEvents;
|
||||||
|
import dev.xkmc.l2serial.network.SerialPacketBase;
|
||||||
|
import dev.xkmc.l2serial.serialization.SerialClass;
|
||||||
|
import net.minecraft.world.effect.MobEffect;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public record EffectToClient(int entity, MobEffect effect, boolean exist, int level)
|
||||||
|
implements SerialPacketBase<EffectToClient> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(@Nullable Player player) {
|
||||||
|
ClientEffectRenderEvents.sync(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
84
src/main/java/dev/xkmc/l2core/base/effects/EffectUtil.java
Normal file
84
src/main/java/dev/xkmc/l2core/base/effects/EffectUtil.java
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.base.effects.api.ForceEffect;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.neoforged.bus.api.Event;
|
||||||
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
|
import net.neoforged.neoforge.event.EventHooks;
|
||||||
|
import net.neoforged.neoforge.event.entity.living.MobEffectEvent;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
public class EffectUtil {
|
||||||
|
|
||||||
|
public enum AddReason {
|
||||||
|
NONE, PROF, FORCE, SKILL, SELF
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final ThreadLocal<AddReason> REASON = new ThreadLocal<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* force add effect, make hard not override
|
||||||
|
* for icon use only, such as Arcane Mark on Wither and Ender Dragon
|
||||||
|
*/
|
||||||
|
private static void forceAddEffect(LivingEntity e, MobEffectInstance ins, @Nullable Entity source) {
|
||||||
|
MobEffectInstance effectinstance = e.getActiveEffectsMap().get(ins.getEffect());
|
||||||
|
var event = new ForceAddEffectEvent(e, ins);
|
||||||
|
NeoForge.EVENT_BUS.post(event);
|
||||||
|
if (event.getResult() == Event.Result.DENY) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NeoForge.EVENT_BUS.post(new MobEffectEvent.Added(e, effectinstance, ins, source));
|
||||||
|
if (effectinstance == null) {
|
||||||
|
e.getActiveEffectsMap().put(ins.getEffect(), ins);
|
||||||
|
e.onEffectAdded(ins, source);
|
||||||
|
} else if (effectinstance.update(ins)) {
|
||||||
|
e.onEffectUpdated(effectinstance, true, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addEffect(LivingEntity entity, MobEffectInstance ins, AddReason reason, @Nullable Entity source) {
|
||||||
|
if (entity == source)
|
||||||
|
reason = AddReason.SELF;
|
||||||
|
if (ins.getEffect() instanceof ForceEffect)
|
||||||
|
reason = AddReason.FORCE;
|
||||||
|
ins = new MobEffectInstance(ins.getEffect(), ins.getDuration(), ins.getAmplifier(),
|
||||||
|
ins.isAmbient(), reason != AddReason.FORCE && ins.isVisible(), ins.showIcon());
|
||||||
|
REASON.set(reason);
|
||||||
|
if (ins.getEffect() instanceof ForceEffect)
|
||||||
|
forceAddEffect(entity, ins, source);
|
||||||
|
else if (ins.getEffect().isInstantenous())
|
||||||
|
ins.getEffect().applyInstantenousEffect(null, null, entity, ins.getAmplifier(), 1);
|
||||||
|
else entity.addEffect(ins, source);
|
||||||
|
REASON.set(AddReason.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void refreshEffect(LivingEntity entity, MobEffectInstance ins, AddReason reason, Entity source) {
|
||||||
|
if (ins.duration < 40) ins.duration = 40;
|
||||||
|
MobEffectInstance cur = entity.getEffect(ins.getEffect());
|
||||||
|
if (cur == null || cur.getAmplifier() < ins.getAmplifier() || cur.getAmplifier() == ins.getAmplifier() && cur.getDuration() < ins.getDuration() / 2)
|
||||||
|
addEffect(entity, ins, reason, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeEffect(LivingEntity entity, Predicate<MobEffectInstance> pred) {
|
||||||
|
Iterator<MobEffectInstance> itr = entity.activeEffects.values().iterator();
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
MobEffectInstance effect = itr.next();
|
||||||
|
if (pred.test(effect) && EventHooks.onEffectRemoved(entity, effect, null)) {
|
||||||
|
entity.onEffectRemoved(effect);
|
||||||
|
itr.remove();
|
||||||
|
entity.effectsDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AddReason getReason() {
|
||||||
|
AddReason ans = REASON.get();
|
||||||
|
return ans == null ? AddReason.NONE : ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects;
|
||||||
|
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.neoforged.bus.api.Event;
|
||||||
|
import net.neoforged.neoforge.event.entity.living.MobEffectEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
@Event.HasResult
|
||||||
|
public class ForceAddEffectEvent extends MobEffectEvent {
|
||||||
|
|
||||||
|
public ForceAddEffectEvent(LivingEntity living, @NotNull MobEffectInstance effectInstance) {
|
||||||
|
super(living, effectInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public MobEffectInstance getEffectInstance() {
|
||||||
|
return super.getEffectInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects.api;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public interface ClientRenderEffect {
|
||||||
|
|
||||||
|
void render(LivingEntity entity, int lv, Consumer<DelayedEntityRender> adder);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects.api;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
|
||||||
|
public record DelayedEntityRender(LivingEntity entity, IconRenderRegion region, ResourceLocation rl,
|
||||||
|
float tx, float ty, float tw, float th) {
|
||||||
|
|
||||||
|
public static DelayedEntityRender icon(LivingEntity entity, ResourceLocation rl) {
|
||||||
|
return icon(entity, IconRenderRegion.identity(), rl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DelayedEntityRender icon(LivingEntity entity, IconRenderRegion r, ResourceLocation rl) {
|
||||||
|
return new DelayedEntityRender(entity, r, rl, 0, 0, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DelayedEntityRender resize(IconRenderRegion r) {
|
||||||
|
return new DelayedEntityRender(entity, r.resize(region), rl, tx, ty, tw, th);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects.api;
|
||||||
|
|
||||||
|
import net.minecraft.client.player.AbstractClientPlayer;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
|
||||||
|
public interface FirstPlayerRenderEffect {
|
||||||
|
|
||||||
|
void onClientLevelRender(AbstractClientPlayer player, MobEffectInstance value);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects.api;
|
||||||
|
|
||||||
|
public interface ForceEffect {
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects.api;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public interface IconOverlayEffect extends ClientRenderEffect {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void render(LivingEntity entity, int lv, Consumer<DelayedEntityRender> adder) {
|
||||||
|
adder.accept(getIcon(entity, lv));
|
||||||
|
}
|
||||||
|
|
||||||
|
DelayedEntityRender getIcon(LivingEntity entity, int lv);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects.api;
|
||||||
|
|
||||||
|
public record IconRenderRegion(float x, float y, float scale) {
|
||||||
|
|
||||||
|
public static IconRenderRegion identity() {
|
||||||
|
return new IconRenderRegion(0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IconRenderRegion of(int r, int ix, int iy, int w, int h) {
|
||||||
|
float y = ((r - h) / 2f + iy) / r;
|
||||||
|
float x = ((r - w) / 2f + ix) / r;
|
||||||
|
return new IconRenderRegion(x, y, 1f / r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IconRenderRegion resize(IconRenderRegion inner) {
|
||||||
|
return new IconRenderRegion(x + inner.x() * scale, y + inner.y() * scale, scale * inner.scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package dev.xkmc.l2core.base.effects.api;
|
||||||
|
|
||||||
|
import net.minecraft.world.effect.MobEffect;
|
||||||
|
import net.minecraft.world.effect.MobEffectCategory;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
import net.neoforged.neoforge.common.EffectCure;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class InherentEffect extends MobEffect {
|
||||||
|
|
||||||
|
protected InherentEffect(MobEffectCategory category, int color) {
|
||||||
|
super(category, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fillEffectCures(Set<EffectCure> cures, MobEffectInstance effectInstance) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.base.effects;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
49
src/main/java/dev/xkmc/l2core/base/entity/BaseEntity.java
Normal file
49
src/main/java/dev/xkmc/l2core/base/entity/BaseEntity.java
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package dev.xkmc.l2core.base.entity;
|
||||||
|
|
||||||
|
import dev.xkmc.l2serial.serialization.SerialClass;
|
||||||
|
import dev.xkmc.l2serial.serialization.codec.PacketCodec;
|
||||||
|
import dev.xkmc.l2serial.serialization.codec.TagCodec;
|
||||||
|
import dev.xkmc.l2serial.util.Wrappers;
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.neoforged.neoforge.entity.IEntityWithComplexSpawn;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
||||||
|
@SerialClass
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
public abstract class BaseEntity extends Entity implements IEntityWithComplexSpawn {
|
||||||
|
|
||||||
|
public BaseEntity(EntityType<?> type, Level world) {
|
||||||
|
super(type, world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addAdditionalSaveData(CompoundTag tag) {
|
||||||
|
tag.put("auto-serial", TagCodec.toTag(new CompoundTag(), this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readAdditionalSaveData(CompoundTag tag) {
|
||||||
|
if (!tag.contains("auto-serial"))
|
||||||
|
return;
|
||||||
|
Wrappers.run(() -> TagCodec.fromTag(tag.getCompound("auto-serial"), this.getClass(), this, f -> true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeSpawnData(FriendlyByteBuf buffer) {
|
||||||
|
PacketCodec.to(buffer, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
|
@Override
|
||||||
|
public void readSpawnData(FriendlyByteBuf data) {
|
||||||
|
PacketCodec.from(data, (Class) this.getClass(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.base.entity;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package dev.xkmc.l2core.base.explosion;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.Explosion;
|
||||||
|
|
||||||
|
public class BaseExplosion extends Explosion {
|
||||||
|
|
||||||
|
public final BaseExplosionContext base;
|
||||||
|
public final ModExplosionContext mod;
|
||||||
|
public final VanillaExplosionContext mc;
|
||||||
|
public final ParticleExplosionContext particle;
|
||||||
|
|
||||||
|
public BaseExplosion(BaseExplosionContext base, VanillaExplosionContext mc, ModExplosionContext mod, ParticleExplosionContext particle) {
|
||||||
|
super(base.level(), mc.entity(), mc.source(), mc.calculator(), base.x(), base.y(), base.z(), base.r(), mc.fire(), mc.type(),
|
||||||
|
particle.small(), particle.large(), particle.sound());
|
||||||
|
this.base = base;
|
||||||
|
this.mod = mod;
|
||||||
|
this.mc = mc;
|
||||||
|
this.particle = particle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return false to cancel hurt
|
||||||
|
*/
|
||||||
|
public boolean hurtEntity(Entity entity) {
|
||||||
|
return mod.hurtEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package dev.xkmc.l2core.base.explosion;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
public record BaseExplosionContext(Level level, double x, double y, double z, float r) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package dev.xkmc.l2core.base.explosion;
|
||||||
|
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundExplodePacket;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Explosion;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.neoforged.neoforge.event.EventHooks;
|
||||||
|
|
||||||
|
public class ExplosionHandler {
|
||||||
|
|
||||||
|
public static void explode(BaseExplosion exp) {
|
||||||
|
if (exp.base.level().isClientSide()) return;
|
||||||
|
if (EventHooks.onExplosionStart(exp.base.level(), exp)) return;
|
||||||
|
exp.explode();
|
||||||
|
Level level = exp.base.level();
|
||||||
|
exp.finalizeExplosion(level.isClientSide());
|
||||||
|
double x = exp.base.x();
|
||||||
|
double y = exp.base.y();
|
||||||
|
double z = exp.base.z();
|
||||||
|
float r = exp.base.r();
|
||||||
|
boolean flag = exp.mc.type() == Explosion.BlockInteraction.KEEP;
|
||||||
|
if (flag) {
|
||||||
|
exp.clearToBlow();
|
||||||
|
}
|
||||||
|
for (Player player : level.players()) {
|
||||||
|
if (player instanceof ServerPlayer serverplayer) {
|
||||||
|
if (serverplayer.distanceToSqr(x, y, z) < 4096.0D) {
|
||||||
|
serverplayer.connection.send(new ClientboundExplodePacket(x, y, z, r,
|
||||||
|
exp.getToBlow(), exp.getHitPlayers().get(serverplayer), exp.mc.type(),
|
||||||
|
exp.particle.small(), exp.particle.large(), exp.particle.sound()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package dev.xkmc.l2core.base.explosion;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
|
||||||
|
public interface ModExplosionContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return false to cancel damage
|
||||||
|
*/
|
||||||
|
boolean hurtEntity(Entity entity);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package dev.xkmc.l2core.base.explosion;
|
||||||
|
|
||||||
|
import net.minecraft.core.particles.ParticleOptions;
|
||||||
|
import net.minecraft.sounds.SoundEvent;
|
||||||
|
|
||||||
|
public record ParticleExplosionContext(ParticleOptions small,
|
||||||
|
ParticleOptions large,
|
||||||
|
SoundEvent sound) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package dev.xkmc.l2core.base.explosion;
|
||||||
|
|
||||||
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.level.Explosion;
|
||||||
|
import net.minecraft.world.level.ExplosionDamageCalculator;
|
||||||
|
import net.minecraft.world.level.GameRules;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.neoforged.neoforge.event.EventHooks;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public record VanillaExplosionContext(@Nullable Entity entity, @Nullable DamageSource source,
|
||||||
|
@Nullable ExplosionDamageCalculator calculator,
|
||||||
|
boolean fire, Explosion.BlockInteraction type) {
|
||||||
|
|
||||||
|
public VanillaExplosionContext(Level level, @Nullable Entity entity, @Nullable DamageSource source,
|
||||||
|
@Nullable ExplosionDamageCalculator calculator,
|
||||||
|
boolean fire, Level.ExplosionInteraction type) {
|
||||||
|
this(entity, source, calculator, fire, getType(level, entity, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Explosion.BlockInteraction getType(Level level, @Nullable Entity entity, Level.ExplosionInteraction type) {
|
||||||
|
return switch (type) {
|
||||||
|
case NONE -> Explosion.BlockInteraction.KEEP;
|
||||||
|
case BLOCK -> level.getDestroyType(GameRules.RULE_BLOCK_EXPLOSION_DROP_DECAY);
|
||||||
|
case MOB -> EventHooks.getMobGriefingEvent(level, entity instanceof LivingEntity le ? le : null) ?
|
||||||
|
level.getDestroyType(GameRules.RULE_MOB_EXPLOSION_DROP_DECAY) :
|
||||||
|
Explosion.BlockInteraction.KEEP;
|
||||||
|
case TNT -> level.getDestroyType(GameRules.RULE_TNT_EXPLOSION_DROP_DECAY);
|
||||||
|
case BLOW -> Explosion.BlockInteraction.TRIGGER_BLOCK;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.base.explosion;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.base;
|
||||||
|
|
||||||
|
import dev.xkmc.l2serial.util.Wrappers;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.Container;
|
||||||
|
import net.minecraft.world.SimpleContainer;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
import net.minecraft.world.inventory.MenuType;
|
||||||
|
import net.minecraft.world.inventory.Slot;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.function.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base Class for ContainerMenu.
|
||||||
|
* Containers multiple helper functions.
|
||||||
|
*/
|
||||||
|
public class BaseContainerMenu<T extends BaseContainerMenu<T>> extends AbstractContainerMenu {
|
||||||
|
|
||||||
|
private record SlotKey(String name, int i, int j) {
|
||||||
|
|
||||||
|
private static final Comparator<SlotKey> COMPARATOR;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Comparator<SlotKey> comp = Comparator.comparing(SlotKey::name);
|
||||||
|
comp = comp.thenComparingInt(SlotKey::i);
|
||||||
|
comp = comp.thenComparingInt(SlotKey::j);
|
||||||
|
COMPARATOR = comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* simple container that prevents looping change
|
||||||
|
*/
|
||||||
|
public static class BaseContainer<T extends BaseContainerMenu<T>> extends SimpleContainer {
|
||||||
|
|
||||||
|
protected final T parent;
|
||||||
|
private boolean updating = false;
|
||||||
|
private int max = 64;
|
||||||
|
|
||||||
|
public BaseContainer(int size, T menu) {
|
||||||
|
super(size);
|
||||||
|
parent = menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public BaseContainer<T> setMax(int max) {
|
||||||
|
this.max = max;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxStackSize() {
|
||||||
|
return Math.min(max, super.getMaxStackSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChanged() {
|
||||||
|
super.setChanged();
|
||||||
|
if (!updating) {
|
||||||
|
updating = true;
|
||||||
|
parent.slotsChanged(this);
|
||||||
|
updating = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return items in the slot to player
|
||||||
|
*/
|
||||||
|
public static void clearSlot(Player pPlayer, Container pContainer, int index) {
|
||||||
|
if (!pPlayer.isAlive() || pPlayer instanceof ServerPlayer && ((ServerPlayer) pPlayer).hasDisconnected()) {
|
||||||
|
pPlayer.drop(pContainer.removeItemNoUpdate(index), false);
|
||||||
|
} else {
|
||||||
|
Inventory inventory = pPlayer.getInventory();
|
||||||
|
if (inventory.player instanceof ServerPlayer) {
|
||||||
|
inventory.placeItemBackInInventory(pContainer.removeItemNoUpdate(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Inventory inventory;
|
||||||
|
public final Container container;
|
||||||
|
public final SpriteManager sprite;
|
||||||
|
protected int added = 0;
|
||||||
|
protected final boolean isVirtual;
|
||||||
|
|
||||||
|
private boolean updating = false;
|
||||||
|
|
||||||
|
private final Map<SlotKey, Slot> slotMap = new TreeMap<>(SlotKey.COMPARATOR);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This contructor will bind player inventory first, so player inventory has lower slot index.
|
||||||
|
*
|
||||||
|
* @param type registered menu type
|
||||||
|
* @param wid window id
|
||||||
|
* @param plInv player inventory
|
||||||
|
* @param manager sprite manager used for slot positioning and rendering
|
||||||
|
* @param factory container supplier
|
||||||
|
* @param isVirtual true if the slots should be cleared and item returned to player on menu close.
|
||||||
|
*/
|
||||||
|
protected BaseContainerMenu(MenuType<?> type, int wid, Inventory plInv, SpriteManager manager, Function<T, SimpleContainer> factory, boolean isVirtual) {
|
||||||
|
super(type, wid);
|
||||||
|
this.inventory = plInv;
|
||||||
|
container = factory.apply(Wrappers.cast(this));
|
||||||
|
sprite = manager;
|
||||||
|
int x = manager.get().getPlInvX();
|
||||||
|
int y = manager.get().getPlInvY();
|
||||||
|
this.bindPlayerInventory(plInv, x, y);
|
||||||
|
this.isVirtual = isVirtual;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds player inventory. Should not be called by others, but permits override.
|
||||||
|
*/
|
||||||
|
protected void bindPlayerInventory(Inventory plInv, int x, int y) {
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
for (int j = 0; j < 9; ++j)
|
||||||
|
addSlot(createSlot(plInv, j + i * 9 + 9, x + j * 18, y + i * 18));
|
||||||
|
for (int k = 0; k < 9; ++k)
|
||||||
|
addSlot(createSlot(plInv, k, x + k * 18, y + 58));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by bindPlayerInventory only. Create slots as needed. Some slots could be locked.
|
||||||
|
*/
|
||||||
|
protected Slot createSlot(Inventory inv, int slot, int x, int y) {
|
||||||
|
return shouldLock(inv, slot) ? new SlotLocked(inv, slot, x, y) : new Slot(inv, slot, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock slots you don't want players modifying, such as the slot player is opening backpack in.
|
||||||
|
*/
|
||||||
|
protected boolean shouldLock(Inventory inv, int slot) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add new slots, with item input predicate
|
||||||
|
*/
|
||||||
|
protected void addSlot(String name, Predicate<ItemStack> pred) {
|
||||||
|
sprite.get().getSlot(name, (x, y) -> new PredSlot(container, added++, x, y, pred), this::addSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add new slots, with index-sensitive item input predicate.
|
||||||
|
* The index here is relative to the first slot added by this method.
|
||||||
|
*/
|
||||||
|
protected void addSlot(String name, BiPredicate<Integer, ItemStack> pred) {
|
||||||
|
int current = added;
|
||||||
|
sprite.get().getSlot(name, (x, y) -> {
|
||||||
|
int i = added - current;
|
||||||
|
var ans = new PredSlot(container, added, x, y, e -> pred.test(i, e));
|
||||||
|
added++;
|
||||||
|
return ans;
|
||||||
|
}, this::addSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add new slots, with other modifications to the slot.
|
||||||
|
*/
|
||||||
|
protected void addSlot(String name, Predicate<ItemStack> pred, Consumer<PredSlot> modifier) {
|
||||||
|
sprite.get().getSlot(name, (x, y) -> {
|
||||||
|
PredSlot s = new PredSlot(container, added++, x, y, pred);
|
||||||
|
modifier.accept(s);
|
||||||
|
return s;
|
||||||
|
}, this::addSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add new slots, with index-sensitive modifications to the slot.
|
||||||
|
* The index here is relative to the first slot added by this method.
|
||||||
|
*/
|
||||||
|
protected void addSlot(String name, BiPredicate<Integer, ItemStack> pred, BiConsumer<Integer, PredSlot> modifier) {
|
||||||
|
int current = added;
|
||||||
|
sprite.get().getSlot(name, (x, y) -> {
|
||||||
|
int i = added - current;
|
||||||
|
var ans = new PredSlot(container, added, x, y, e -> pred.test(i, e));
|
||||||
|
modifier.accept(i, ans);
|
||||||
|
added++;
|
||||||
|
return ans;
|
||||||
|
}, this::addSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* internal add slot
|
||||||
|
*/
|
||||||
|
protected void addSlot(String name, int i, int j, Slot slot) {
|
||||||
|
slotMap.put(new SlotKey(name, i, j), slot);
|
||||||
|
this.addSlot(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the slot by name and id in the grid
|
||||||
|
*/
|
||||||
|
protected Slot getSlot(String name, int i, int j) {
|
||||||
|
return slotMap.get(new SlotKey(name, i, j));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a slot as PredSlot, as most slots should be
|
||||||
|
*/
|
||||||
|
public PredSlot getAsPredSlot(String name, int i, int j) {
|
||||||
|
return (PredSlot) getSlot(name, i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a slot as PredSlot, as most slots should be
|
||||||
|
*/
|
||||||
|
public PredSlot getAsPredSlot(String name) {
|
||||||
|
return (PredSlot) getSlot(name, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack quickMoveStack(Player pl, int id) {
|
||||||
|
ItemStack stack = slots.get(id).getItem();
|
||||||
|
int n = container.getContainerSize();
|
||||||
|
boolean moved;
|
||||||
|
if (id >= 36) {
|
||||||
|
moved = moveItemStackTo(stack, 0, 36, true);
|
||||||
|
} else {
|
||||||
|
moved = moveItemStackTo(stack, 36, 36 + n, false);
|
||||||
|
}
|
||||||
|
if (moved) slots.get(id).setChanged();
|
||||||
|
return ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean stillValid(Player player) {
|
||||||
|
return player.isAlive();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removed(Player player) {
|
||||||
|
if (isVirtual && !player.level().isClientSide())
|
||||||
|
clearContainerFiltered(player, container);
|
||||||
|
super.removed(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true (and when isVirtual is true), clear the corresponding slot on menu close.
|
||||||
|
*/
|
||||||
|
protected boolean shouldClear(Container container, int slot) {
|
||||||
|
return isVirtual;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clear slots using shouldClear
|
||||||
|
*/
|
||||||
|
protected void clearContainerFiltered(Player player, Container container) {
|
||||||
|
if (!player.isAlive() || player instanceof ServerPlayer && ((ServerPlayer) player).hasDisconnected()) {
|
||||||
|
for (int j = 0; j < container.getContainerSize(); ++j) {
|
||||||
|
if (shouldClear(container, j)) {
|
||||||
|
player.drop(container.removeItemNoUpdate(j), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Inventory inventory = player.getInventory();
|
||||||
|
for (int i = 0; i < container.getContainerSize(); ++i) {
|
||||||
|
if (shouldClear(container, i)) {
|
||||||
|
if (inventory.player instanceof ServerPlayer) {
|
||||||
|
inventory.placeItemBackInInventory(container.removeItemNoUpdate(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void slotsChanged(Container cont) {
|
||||||
|
if (inventory.player.level().isClientSide()) {
|
||||||
|
super.slotsChanged(cont);
|
||||||
|
} else {
|
||||||
|
if (!updating) {
|
||||||
|
updating = true;
|
||||||
|
securedServerSlotChange(cont);
|
||||||
|
updating = false;
|
||||||
|
}
|
||||||
|
super.slotsChanged(cont);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* server side only slot change detector that will not be called recursively.
|
||||||
|
*/
|
||||||
|
protected void securedServerSlotChange(Container cont) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.base;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.util.Proxy;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
|
||||||
|
public abstract class BaseContainerScreen<T extends BaseContainerMenu<T>> extends AbstractContainerScreen<T> {
|
||||||
|
|
||||||
|
public BaseContainerScreen(T cont, Inventory plInv, Component title) {
|
||||||
|
super(cont, plInv, title);
|
||||||
|
this.imageHeight = menu.sprite.get().getHeight();
|
||||||
|
this.inventoryLabelY = menu.sprite.get().getPlInvY() - 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(GuiGraphics g, int mx, int my, float partial) {
|
||||||
|
super.render(g, mx, my, partial);
|
||||||
|
renderTooltip(g, mx, my);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean click(int btn) {
|
||||||
|
if (menu.clickMenuButton(Proxy.getClientPlayer(), btn) && Minecraft.getInstance().gameMode != null) {
|
||||||
|
Minecraft.getInstance().gameMode.handleInventoryButtonClick(this.menu.containerId, btn);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.base;
|
||||||
|
|
||||||
|
import dev.xkmc.l2serial.serialization.SerialClass;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.inventory.Slot;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@SerialClass
|
||||||
|
public record MenuLayoutConfig(int height, HashMap<String, Rect> side, HashMap<String, Rect> comp) {
|
||||||
|
|
||||||
|
public static ResourceLocation getTexture(ResourceLocation id) {
|
||||||
|
return new ResourceLocation(id.getNamespace(), "textures/gui/container/" + id.getPath() + ".png");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the location of the component on the GUI
|
||||||
|
*/
|
||||||
|
public Rect getComp(String key) {
|
||||||
|
return comp.getOrDefault(key, Rect.ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Height of this GUI
|
||||||
|
*/
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The X position of the player inventory
|
||||||
|
*/
|
||||||
|
public int getPlInvX() {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Y position of the player inventory
|
||||||
|
*/
|
||||||
|
public int getPlInvY() {
|
||||||
|
return height - 82;
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public ScreenRenderer getRenderer(ResourceLocation id, AbstractContainerScreen<?> gui) {
|
||||||
|
return new ScreenRenderer(id, gui);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public ScreenRenderer getRenderer(ResourceLocation id, Screen gui, int x, int y, int w, int h) {
|
||||||
|
return new ScreenRenderer(id, gui, x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the rectangle representing the sprite element on the sprite
|
||||||
|
*/
|
||||||
|
public Rect getSide(String key) {
|
||||||
|
return side.getOrDefault(key, Rect.ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* configure the coordinate of the slot
|
||||||
|
*/
|
||||||
|
public <T extends Slot> void getSlot(String key, SlotFactory<T> fac, SlotAcceptor con) {
|
||||||
|
Rect c = getComp(key);
|
||||||
|
for (int j = 0; j < c.ry; j++)
|
||||||
|
for (int i = 0; i < c.rx; i++) {
|
||||||
|
var slot = fac.getSlot(c.x + i * c.w, c.y + j * c.h);
|
||||||
|
if (slot != null) {
|
||||||
|
con.addSlot(key, i, j, slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return 176;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return if the coordinate is within the rectangle represented by the key
|
||||||
|
*/
|
||||||
|
public boolean within(String key, double x, double y) {
|
||||||
|
Rect c = getComp(key);
|
||||||
|
return x > c.x && x < c.x + c.w && y > c.y && y < c.y + c.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface SlotFactory<T extends Slot> {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
T getSlot(int x, int y);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface SlotAcceptor {
|
||||||
|
|
||||||
|
void addSlot(String name, int i, int j, Slot slot);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SerialClass
|
||||||
|
public static class Rect {
|
||||||
|
|
||||||
|
public static final Rect ZERO = new Rect();
|
||||||
|
|
||||||
|
@SerialClass.SerialField
|
||||||
|
public int x, y, w, h, rx = 1, ry = 1;
|
||||||
|
|
||||||
|
public Rect() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public class ScreenRenderer {
|
||||||
|
|
||||||
|
private final int x, y, w, h;
|
||||||
|
private final Screen scr;
|
||||||
|
|
||||||
|
public final ResourceLocation id;
|
||||||
|
|
||||||
|
public MenuLayoutConfig parent(){
|
||||||
|
return MenuLayoutConfig.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScreenRenderer(ResourceLocation id, Screen gui, int x, int y, int w, int h) {
|
||||||
|
scr = gui;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.w = w;
|
||||||
|
this.h = h;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScreenRenderer(ResourceLocation id, AbstractContainerScreen<?> scrIn) {
|
||||||
|
x = scrIn.getGuiLeft();
|
||||||
|
y = scrIn.getGuiTop();
|
||||||
|
w = scrIn.getXSize();
|
||||||
|
h = scrIn.getYSize();
|
||||||
|
scr = scrIn;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a side sprite on the location specified by the component
|
||||||
|
*/
|
||||||
|
public void draw(GuiGraphics g, String c, String s) {
|
||||||
|
Rect cr = getComp(c);
|
||||||
|
Rect sr = getSide(s);
|
||||||
|
g.blit(getTexture(id), x + cr.x, y + cr.y, sr.x, sr.y, sr.w, sr.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a side sprite on the location specified by the component with offsets
|
||||||
|
*/
|
||||||
|
public void draw(GuiGraphics g, String c, String s, int xoff, int yoff) {
|
||||||
|
Rect cr = getComp(c);
|
||||||
|
Rect sr = getSide(s);
|
||||||
|
g.blit(getTexture(id), x + cr.x + xoff, y + cr.y + yoff, sr.x, sr.y, sr.w, sr.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a side sprite on the location specified by the component. Draw partially
|
||||||
|
* from bottom to top
|
||||||
|
*/
|
||||||
|
public void drawBottomUp(GuiGraphics g, String c, String s, int prog, int max) {
|
||||||
|
if (prog == 0 || max == 0)
|
||||||
|
return;
|
||||||
|
Rect cr = getComp(c);
|
||||||
|
Rect sr = getSide(s);
|
||||||
|
int dh = sr.h * prog / max;
|
||||||
|
g.blit(getTexture(id), x + cr.x, y + cr.y + sr.h - dh, sr.x, sr.y + sr.h - dh, sr.w, dh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a side sprite on the location specified by the component. Draw partially
|
||||||
|
* from left to right
|
||||||
|
*/
|
||||||
|
public void drawLeftRight(GuiGraphics g, String c, String s, int prog, int max) {
|
||||||
|
if (prog == 0 || max == 0)
|
||||||
|
return;
|
||||||
|
Rect cr = getComp(c);
|
||||||
|
Rect sr = getSide(s);
|
||||||
|
int dw = sr.w * prog / max;
|
||||||
|
g.blit(getTexture(id), x + cr.x, y + cr.y, sr.x, sr.y, dw, sr.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill an area with a sprite, repeat as tiles if not enough, start from lower
|
||||||
|
* left corner
|
||||||
|
*/
|
||||||
|
public void drawLiquid(GuiGraphics g, String c, double per, int height, int sw, int sh) {
|
||||||
|
Rect cr = getComp(c);
|
||||||
|
int base = cr.y + height;
|
||||||
|
int h = (int) Math.round(per * height);
|
||||||
|
circularBlit(g, x + cr.x, base - h, 0, -h, cr.w, h, sw, sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bind texture, draw background color, and GUI background
|
||||||
|
*/
|
||||||
|
public void start(GuiGraphics g) {
|
||||||
|
scr.renderTransparentBackground(g);
|
||||||
|
g.blit(getTexture(id), x, y, 0, 0, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void circularBlit(GuiGraphics g, int sx, int sy, int ix, int iy, int w, int h, int iw, int ih) {
|
||||||
|
int x0 = ix, yb = iy, x1 = w, x2 = sx;
|
||||||
|
while (x0 < 0)
|
||||||
|
x0 += iw;
|
||||||
|
while (yb < ih)
|
||||||
|
yb += ih;
|
||||||
|
while (x1 > 0) {
|
||||||
|
int dx = Math.min(x1, iw - x0);
|
||||||
|
int y0 = yb, y1 = h, y2 = sy;
|
||||||
|
while (y1 > 0) {
|
||||||
|
int dy = Math.min(y1, ih - y0);
|
||||||
|
g.blit(getTexture(id), x2, y2, x0, y0, x1, y1);
|
||||||
|
y1 -= dy;
|
||||||
|
y0 += dy;
|
||||||
|
y2 += dy;
|
||||||
|
}
|
||||||
|
x1 -= dx;
|
||||||
|
x0 += dx;
|
||||||
|
x2 += dx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
150
src/main/java/dev/xkmc/l2core/base/menu/base/PredSlot.java
Normal file
150
src/main/java/dev/xkmc/l2core/base/menu/base/PredSlot.java
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.base;
|
||||||
|
|
||||||
|
import net.minecraft.world.Container;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.inventory.Slot;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slot added by BaseContainerMenu. Contains multiple helpers
|
||||||
|
*/
|
||||||
|
public class PredSlot extends Slot {
|
||||||
|
|
||||||
|
private final Predicate<ItemStack> pred;
|
||||||
|
private final int slotCache;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private BooleanSupplier pickup;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private BooleanSupplier inputLockPred;
|
||||||
|
|
||||||
|
private int max = 64;
|
||||||
|
|
||||||
|
private boolean changed = false;
|
||||||
|
private boolean lockInput = false, lockOutput = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be called by BaseContainerMenu::addSlot only.
|
||||||
|
* Predicate supplied from subclasses pf BaseContainerMenu.
|
||||||
|
*/
|
||||||
|
public PredSlot(Container inv, int ind, int x, int y, Predicate<ItemStack> pred) {
|
||||||
|
super(inv, ind, x, y);
|
||||||
|
this.pred = pred;
|
||||||
|
slotCache = ind;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the condition to unlock a slot for input.
|
||||||
|
* Parallel with manual lock and item predicate.
|
||||||
|
*/
|
||||||
|
public PredSlot setInputLockPred(BooleanSupplier pred) {
|
||||||
|
this.inputLockPred = pred;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set restriction for pickup.
|
||||||
|
*/
|
||||||
|
public PredSlot setPickup(BooleanSupplier pickup) {
|
||||||
|
this.pickup = pickup;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PredSlot setMax(int max) {
|
||||||
|
this.max = max;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxStackSize() {
|
||||||
|
return Math.min(max, super.getMaxStackSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mayPlace(ItemStack stack) {
|
||||||
|
if (isInputLocked()) return false;
|
||||||
|
return pred.test(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mayPickup(Player player) {
|
||||||
|
if (isOutputLocked()) return false;
|
||||||
|
return pickup == null || pickup.getAsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChanged() {
|
||||||
|
changed = true;
|
||||||
|
super.setChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* run only if the content of this slot is changed
|
||||||
|
*/
|
||||||
|
public boolean clearDirty(Runnable r) {
|
||||||
|
if (changed) {
|
||||||
|
r.run();
|
||||||
|
changed = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean clearDirty() {
|
||||||
|
if (changed) {
|
||||||
|
changed = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eject the content of this slot if the item is no longer allowed
|
||||||
|
*/
|
||||||
|
public void updateEject(Player player) {
|
||||||
|
if (!mayPlace(getItem())) clearSlot(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock the input of this slot.
|
||||||
|
* Parallel with lock conditions and item predicate
|
||||||
|
*/
|
||||||
|
public void setLockInput(boolean lock) {
|
||||||
|
lockInput = lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if the input is locked manually or locked by lock conditions
|
||||||
|
*/
|
||||||
|
public boolean isInputLocked() {
|
||||||
|
return lockInput || (inputLockPred != null && inputLockPred.getAsBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock the output of this slot.
|
||||||
|
* Parallel with pickup restrictions.
|
||||||
|
*/
|
||||||
|
public void setLockOutput(boolean lock) {
|
||||||
|
lockOutput = lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if the output is locked manually.
|
||||||
|
*/
|
||||||
|
public boolean isOutputLocked() {
|
||||||
|
return lockOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eject the content of this slot.
|
||||||
|
*/
|
||||||
|
public void clearSlot(Player player) {
|
||||||
|
BaseContainerMenu.clearSlot(player, container, slotCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
24
src/main/java/dev/xkmc/l2core/base/menu/base/SlotLocked.java
Normal file
24
src/main/java/dev/xkmc/l2core/base/menu/base/SlotLocked.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.base;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.inventory.Slot;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
public class SlotLocked extends Slot {
|
||||||
|
|
||||||
|
public SlotLocked(Inventory inventory, int index, int x, int y) {
|
||||||
|
super(inventory, index, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mayPickup(Player player) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mayPlace(ItemStack stack) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.base;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.init.L2LibReg;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public record SpriteManager(ResourceLocation id) {
|
||||||
|
|
||||||
|
public SpriteManager(String modid, String path) {
|
||||||
|
this(new ResourceLocation(modid, path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public MenuLayoutConfig get() {
|
||||||
|
return L2LibReg.MENU_LAYOUT.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.base.menu.base;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.data;
|
||||||
|
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
import net.minecraft.world.inventory.DataSlot;
|
||||||
|
|
||||||
|
public class BoolArrayDataSlot {
|
||||||
|
|
||||||
|
private final DataSlot[] array;
|
||||||
|
|
||||||
|
public BoolArrayDataSlot(AbstractContainerMenu menu, int size) {
|
||||||
|
int n = size / 16 + (size % 16 == 0 ? 0 : 1);
|
||||||
|
array = new DataSlot[n];
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
array[i] = menu.addDataSlot(DataSlot.standalone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean get(int i) {
|
||||||
|
return (array[i >> 4].get() & (1 << (i & 0xf))) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(boolean pc, int i) {
|
||||||
|
int val = array[i >> 4].get();
|
||||||
|
int mask = 1 << (i & 0xf);
|
||||||
|
boolean old = (val & mask) != 0;
|
||||||
|
if (old != pc) {
|
||||||
|
val ^= mask;
|
||||||
|
array[i >> 4].set(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.data;
|
||||||
|
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
|
||||||
|
public class DoubleDataSlot {
|
||||||
|
|
||||||
|
private final LongDataSlot data;
|
||||||
|
|
||||||
|
public DoubleDataSlot(AbstractContainerMenu menu) {
|
||||||
|
data = new LongDataSlot(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double get() {
|
||||||
|
return Double.longBitsToDouble(data.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(double pc) {
|
||||||
|
data.set(Double.doubleToLongBits(pc));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.data;
|
||||||
|
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
|
||||||
|
public class FloatDataSlot {
|
||||||
|
|
||||||
|
private final IntDataSlot data;
|
||||||
|
|
||||||
|
public FloatDataSlot(AbstractContainerMenu menu) {
|
||||||
|
data = new IntDataSlot(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float get() {
|
||||||
|
return Float.intBitsToFloat(data.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(float pc) {
|
||||||
|
data.set(Float.floatToIntBits(pc));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.data;
|
||||||
|
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
import net.minecraft.world.inventory.DataSlot;
|
||||||
|
|
||||||
|
public class IntDataSlot {
|
||||||
|
|
||||||
|
private final DataSlot hi, lo;
|
||||||
|
|
||||||
|
public IntDataSlot(AbstractContainerMenu menu) {
|
||||||
|
hi = menu.addDataSlot(DataSlot.standalone());
|
||||||
|
lo = menu.addDataSlot(DataSlot.standalone());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int get() {
|
||||||
|
return hi.get() << 16 | Short.toUnsignedInt((short) lo.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(int pc) {
|
||||||
|
lo.set((short) (pc & 0xFFFF));
|
||||||
|
hi.set(pc >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.data;
|
||||||
|
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
|
||||||
|
public class LongDataSlot {
|
||||||
|
|
||||||
|
private final IntDataSlot lo, hi;
|
||||||
|
|
||||||
|
public LongDataSlot(AbstractContainerMenu menu) {
|
||||||
|
lo = new IntDataSlot(menu);
|
||||||
|
hi = new IntDataSlot(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long get() {
|
||||||
|
return ((long) hi.get()) << 32 | Integer.toUnsignedLong(lo.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(long pc) {
|
||||||
|
lo.set((int) (pc));
|
||||||
|
hi.set((int) (pc >> 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.base.menu.data;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.scroller;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.base.menu.base.MenuLayoutConfig;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
|
public class Scroller {
|
||||||
|
|
||||||
|
private final ScrollerScreen screen;
|
||||||
|
private final MenuLayoutConfig sprite;
|
||||||
|
private final String box, light, dark;
|
||||||
|
private final int bx, by, bw, bh, sh;
|
||||||
|
|
||||||
|
private boolean scrolling;
|
||||||
|
private double percentage;
|
||||||
|
|
||||||
|
public Scroller(ScrollerScreen screen, MenuLayoutConfig sprite, String slider_middle, String slider_light, String slider_dark) {
|
||||||
|
this.screen = screen;
|
||||||
|
this.sprite = sprite;
|
||||||
|
this.box = slider_middle;
|
||||||
|
this.light = slider_light;
|
||||||
|
this.dark = slider_dark;
|
||||||
|
var scroller = sprite.getComp(box);
|
||||||
|
bx = scroller.x;
|
||||||
|
by = scroller.y;
|
||||||
|
bw = scroller.w;
|
||||||
|
bh = scroller.ry;
|
||||||
|
var slider = sprite.getSide(light);
|
||||||
|
sh = slider.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mouseClicked(double mx, double my, int btn) {
|
||||||
|
this.scrolling = false;
|
||||||
|
int cx = screen.getGuiLeft() + bx;
|
||||||
|
int cy = screen.getGuiTop() + by;
|
||||||
|
if (mx >= cx && mx < cx + bw && my >= cy && my < cy + bh) {
|
||||||
|
this.scrolling = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mouseDragged(double mx, double my, int btn, double dx, double dy) {
|
||||||
|
if (this.scrolling && screen.getMenu().getMaxScroll() > 0) {
|
||||||
|
int y0 = screen.getGuiTop() + by;
|
||||||
|
int y1 = y0 + bh;
|
||||||
|
percentage = (my - y0 - sh * 0.5) / ((y1 - y0) - 15.0F);
|
||||||
|
percentage = Mth.clamp(percentage, 0.0F, 1.0F);
|
||||||
|
updateIndex();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mouseScrolled(double mx, double my, double d) {
|
||||||
|
if (screen.getMenu().getMaxScroll() > 0) {
|
||||||
|
int i = screen.getMenu().getMaxScroll();
|
||||||
|
double f = d / i;
|
||||||
|
percentage = Mth.clamp(percentage - f, 0, 1);
|
||||||
|
updateIndex();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateIndex() {
|
||||||
|
screen.scrollTo((int) ((percentage * screen.getMenu().getMaxScroll()) + 0.5D));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void render(GuiGraphics g, MenuLayoutConfig.ScreenRenderer sr) {
|
||||||
|
if (screen.getMenu().getMaxScroll() == 0) {
|
||||||
|
sr.draw(g, box, dark);
|
||||||
|
} else {
|
||||||
|
int off = (int) Math.round((bh - sh) * percentage);
|
||||||
|
sr.draw(g, box, light, 0, off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.scroller;
|
||||||
|
|
||||||
|
public interface ScrollerMenu {
|
||||||
|
|
||||||
|
int getMaxScroll();
|
||||||
|
|
||||||
|
int getScroll();
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.scroller;
|
||||||
|
|
||||||
|
public interface ScrollerScreen {
|
||||||
|
|
||||||
|
ScrollerMenu getMenu();
|
||||||
|
|
||||||
|
int getGuiLeft();
|
||||||
|
|
||||||
|
int getGuiTop();
|
||||||
|
|
||||||
|
void scrollTo(int i);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.base.menu.scroller;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.stacked;
|
||||||
|
|
||||||
|
public record CellEntry(int x, int y, int w, int h) {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.stacked;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.base.menu.base.MenuLayoutConfig;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.Font;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class StackedRenderHandle {
|
||||||
|
|
||||||
|
static final int BTN_X_OFFSET = 3;
|
||||||
|
static final int TEXT_BASE_HEIGHT = 8;
|
||||||
|
|
||||||
|
private static final int SLOT_X_OFFSET = 7, SLOT_SIZE = 18, SPRITE_OFFSET = 176;
|
||||||
|
|
||||||
|
final Screen scr;
|
||||||
|
final GuiGraphics g;
|
||||||
|
final MenuLayoutConfig.ScreenRenderer sm;
|
||||||
|
final Font font;
|
||||||
|
final int text_color;
|
||||||
|
private final int TEXT_Y_OFFSET;
|
||||||
|
private final int TEXT_HEIGHT;
|
||||||
|
private final int text_x_offset;
|
||||||
|
|
||||||
|
private int current_y = 3;
|
||||||
|
private int current_x = 0;
|
||||||
|
|
||||||
|
final List<TextEntry> textList = new ArrayList<>();
|
||||||
|
|
||||||
|
public StackedRenderHandle(Screen scr, GuiGraphics g, MenuLayoutConfig.ScreenRenderer sm) {
|
||||||
|
this(scr, g, sm, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StackedRenderHandle(Screen scr, GuiGraphics g, MenuLayoutConfig.ScreenRenderer sm, int ty) {
|
||||||
|
this(scr, g, 8, 4210752, sm, ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StackedRenderHandle(Screen scr, GuiGraphics g, int x_offset, int color, MenuLayoutConfig.ScreenRenderer sm) {
|
||||||
|
this(scr, g, x_offset, color, sm, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StackedRenderHandle(Screen scr, GuiGraphics g, int x_offset, int color, MenuLayoutConfig.ScreenRenderer sm, int ty) {
|
||||||
|
this.font = Minecraft.getInstance().font;
|
||||||
|
this.g = g;
|
||||||
|
this.scr = scr;
|
||||||
|
this.sm = sm;
|
||||||
|
this.text_color = color;
|
||||||
|
this.text_x_offset = x_offset;
|
||||||
|
this.TEXT_Y_OFFSET = ty;
|
||||||
|
this.TEXT_HEIGHT = font.lineHeight + ty + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawText(Component text, boolean shadow) {
|
||||||
|
endCell();
|
||||||
|
int y = current_y + TEXT_Y_OFFSET;
|
||||||
|
textList.add(new TextEntry(text, text_x_offset, y, text_color, shadow));
|
||||||
|
current_y += TEXT_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawTable(Component[][] table, int x_max, boolean shadow) {
|
||||||
|
endCell();
|
||||||
|
int w = table[0].length;
|
||||||
|
int w1 = 0;
|
||||||
|
int ws = 0;
|
||||||
|
for (Component[] c : table) {
|
||||||
|
w1 = Math.max(w1, font.width(c[0]));
|
||||||
|
for (int i = 1; i < w; i++) {
|
||||||
|
ws = Math.max(ws, font.width(c[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int sumw = w1 + ws * (w - 1);
|
||||||
|
int x0 = text_x_offset;
|
||||||
|
int x1 = x_max - text_x_offset;
|
||||||
|
float space = (x1 - x0 - sumw) * 1.0f / (w - 1);
|
||||||
|
for (Component[] c : table) {
|
||||||
|
int y = current_y + TEXT_Y_OFFSET;
|
||||||
|
float x_start = x0;
|
||||||
|
for (int i = 0; i < w; i++) {
|
||||||
|
float wi = i == 0 ? w1 : ws;
|
||||||
|
int x = Math.round(x_start);
|
||||||
|
textList.add(new TextEntry(c[i], x, y, text_color, shadow));
|
||||||
|
x_start += wi + space;
|
||||||
|
}
|
||||||
|
current_y += TEXT_HEIGHT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextButtonHandle drawTextWithButtons(Component text, boolean shadow) {
|
||||||
|
endCell();
|
||||||
|
int y = current_y + TEXT_Y_OFFSET;
|
||||||
|
textList.add(new TextEntry(text, text_x_offset, y, text_color, shadow));
|
||||||
|
int x_off = text_x_offset + font.width(text) + BTN_X_OFFSET;
|
||||||
|
TextButtonHandle ans = new TextButtonHandle(this, x_off, y + font.lineHeight / 2);
|
||||||
|
current_y += TEXT_HEIGHT;
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CellEntry addCell(boolean toggled, boolean disabled) {
|
||||||
|
startCell();
|
||||||
|
int index = toggled ? 1 : disabled ? 2 : 0;
|
||||||
|
int x = SLOT_X_OFFSET + current_x * SLOT_SIZE;
|
||||||
|
int u = SPRITE_OFFSET + index * SLOT_SIZE;
|
||||||
|
g.blit(MenuLayoutConfig.getTexture(sm.id), x, current_y, u, 0, SLOT_SIZE, SLOT_SIZE);
|
||||||
|
var ans = new CellEntry(x + 1, current_y + 1, 16, 16);
|
||||||
|
current_x++;
|
||||||
|
if (current_x == 9) {
|
||||||
|
endCell();
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startCell() {
|
||||||
|
if (current_x < 0) {
|
||||||
|
current_x = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void endCell() {
|
||||||
|
if (current_x > 0) {
|
||||||
|
current_x = -1;
|
||||||
|
current_y += SLOT_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flushText() {
|
||||||
|
textList.forEach(e -> g.drawString(font, e.text(), e.x(), e.y(), e.color(), e.shadow()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.stacked;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.base.menu.base.MenuLayoutConfig;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
|
||||||
|
public class TextButtonHandle {
|
||||||
|
|
||||||
|
private final StackedRenderHandle parent;
|
||||||
|
private final int y;
|
||||||
|
|
||||||
|
private int x;
|
||||||
|
|
||||||
|
|
||||||
|
protected TextButtonHandle(StackedRenderHandle parent, int x, int y) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CellEntry addButton(String btn) {
|
||||||
|
MenuLayoutConfig.Rect r = parent.sm.parent().getSide(btn);
|
||||||
|
int y0 = y - (r.h + 1) / 2;
|
||||||
|
parent.g.blit(MenuLayoutConfig.getTexture(parent.sm.id), x, y0, r.x, r.y, r.w, r.h);
|
||||||
|
CellEntry c1 = new CellEntry(x, y0, r.w, r.h);
|
||||||
|
x += r.w + StackedRenderHandle.BTN_X_OFFSET;
|
||||||
|
return c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawText(CellEntry cell, Component text, boolean shadow) {
|
||||||
|
int x0 = cell.x() + (cell.w() - parent.font.width(text) + 1) / 2;
|
||||||
|
int y0 = cell.y() + (cell.h() + 1) / 2 - parent.font.lineHeight / 2;
|
||||||
|
parent.textList.add(new TextEntry(text, x0, y0, parent.text_color, shadow));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package dev.xkmc.l2core.base.menu.stacked;
|
||||||
|
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
|
||||||
|
public record TextEntry(Component text, int x, int y, int color, boolean shadow) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.base.menu.stacked;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
40
src/main/java/dev/xkmc/l2core/base/overlay/InfoSideBar.java
Normal file
40
src/main/java/dev/xkmc/l2core/base/overlay/InfoSideBar.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package dev.xkmc.l2core.base.overlay;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.init.L2LibraryConfig;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.neoforged.neoforge.client.gui.overlay.ExtendedGui;
|
||||||
|
import net.neoforged.neoforge.client.gui.overlay.IGuiOverlay;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class InfoSideBar<S extends SideBar.Signature<S>> extends SideBar<S> implements IGuiOverlay {
|
||||||
|
|
||||||
|
public InfoSideBar(float duration, float ease) {
|
||||||
|
super(duration, ease);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(ExtendedGui gui, GuiGraphics g, float partialTick, int width, int height) {
|
||||||
|
if (!ease(gui.getGuiTicks() + partialTick))
|
||||||
|
return;
|
||||||
|
var text = getText();
|
||||||
|
if (text.isEmpty()) return;
|
||||||
|
int anchor = L2LibraryConfig.CLIENT.infoAnchor.get();
|
||||||
|
int y = height * anchor / 2;
|
||||||
|
int w = (int) (width * L2LibraryConfig.CLIENT.infoMaxWidth.get());
|
||||||
|
new TextBox(g, 0, anchor, getXOffset(width), y, w)
|
||||||
|
.renderLongText(Minecraft.getInstance().font, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract List<Component> getText();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getXOffset(int width) {
|
||||||
|
float progress = (max_ease - ease_time) / max_ease;
|
||||||
|
return Math.round(-progress * width / 2 + 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package dev.xkmc.l2core.base.overlay;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class ItemSelSideBar<S extends SideBar.Signature<S>> extends SelectionSideBar<ItemStack, S> {
|
||||||
|
|
||||||
|
public ItemSelSideBar(float duration, float ease) {
|
||||||
|
super(duration, ease);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void renderEntry(Context ctx, ItemStack stack, int i, int selected) {
|
||||||
|
boolean shift = Minecraft.getInstance().options.keyShift.isDown();
|
||||||
|
int y = 18 * i + ctx.y0();
|
||||||
|
renderSelection(ctx.g(), ctx.x0(), y, shift ? 127 : 64, isAvailable(stack), selected == i);
|
||||||
|
if (selected == i) {
|
||||||
|
if (!stack.isEmpty() && ease_time == max_ease) {
|
||||||
|
boolean onCenter = onCenter();
|
||||||
|
ctx.g().renderTooltip(ctx.font(), stack.getHoverName(), 0, 0);
|
||||||
|
TextBox box = new TextBox(ctx.g(), onCenter ? 0 : 2, 1, ctx.x0() + (onCenter ? 22 : -6), y + 8, -1);
|
||||||
|
box.renderLongText(ctx.font(), List.of(stack.getHoverName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.renderItem(stack, ctx.x0(), y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderSelection(GuiGraphics g, int x, int y, int a, boolean available, boolean selected) {
|
||||||
|
if (available) {
|
||||||
|
OverlayUtil.fillRect(g, x, y, 16, 16, color(255, 255, 255, a));
|
||||||
|
} else {
|
||||||
|
OverlayUtil.fillRect(g, x, y, 16, 16, color(255, 0, 0, a));
|
||||||
|
}
|
||||||
|
if (selected) {
|
||||||
|
OverlayUtil.drawRect(g, x, y, 16, 16, color(255, 170, 0, 255));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int color(int r, int g, int b, int a) {
|
||||||
|
return a << 24 | r << 16 | g << 8 | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package dev.xkmc.l2core.base.overlay;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
|
||||||
|
public record L2TooltipRenderUtil(GuiGraphics fill, int bg, int bs, int be) {
|
||||||
|
|
||||||
|
public void renderTooltipBackground(int x, int y, int w, int h, int z) {
|
||||||
|
int x1 = x - 3;
|
||||||
|
int y1 = y - 3;
|
||||||
|
int w1 = w + 3 + 3;
|
||||||
|
int h1 = h + 3 + 3;
|
||||||
|
renderHorizontalLine(x1, y1 - 1, w1, z, bg);
|
||||||
|
renderHorizontalLine(x1, y1 + h1, w1, z, bg);
|
||||||
|
renderRectangle(x1, y1, w1, h1, z, bg);
|
||||||
|
renderVerticalLine(x1 - 1, y1, h1, z, bg);
|
||||||
|
renderVerticalLine(x1 + w1, y1, h1, z, bg);
|
||||||
|
renderFrameGradient(x1, y1 + 1, w1, h1, z, bs, be);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderFrameGradient(int x, int y, int w, int h, int z, int c0, int c1) {
|
||||||
|
renderVerticalLineGradient(x, y, h - 2, z, c0, c1);
|
||||||
|
renderVerticalLineGradient(x + w - 1, y, h - 2, z, c0, c1);
|
||||||
|
renderHorizontalLine(x, y - 1, w, z, c0);
|
||||||
|
renderHorizontalLine(x, y - 1 + h - 1, w, z, c1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderVerticalLine(int x, int y, int h, int z, int c) {
|
||||||
|
fill.fillGradient(x, y, x + 1, y + h, z, c, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderVerticalLineGradient(int x, int y, int h, int z, int c0, int c1) {
|
||||||
|
fill.fillGradient(x, y, x + 1, y + h, z, c0, c1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderHorizontalLine(int x, int y, int w, int z, int c) {
|
||||||
|
fill.fillGradient(x, y, x + w, y + 1, z, c, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderRectangle(int x, int y, int w, int h, int z, int c) {
|
||||||
|
fill.fillGradient(x, y, x + w, y + h, z, c, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
105
src/main/java/dev/xkmc/l2core/base/overlay/OverlayUtil.java
Normal file
105
src/main/java/dev/xkmc/l2core/base/overlay/OverlayUtil.java
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package dev.xkmc.l2core.base.overlay;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.init.L2LibraryConfig;
|
||||||
|
import net.minecraft.client.gui.Font;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent;
|
||||||
|
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipPositioner;
|
||||||
|
import net.minecraft.client.gui.screens.inventory.tooltip.TooltipRenderUtil;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import org.joml.Vector2i;
|
||||||
|
import org.joml.Vector2ic;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class OverlayUtil implements ClientTooltipPositioner {
|
||||||
|
|
||||||
|
private static int getBGColor() {
|
||||||
|
return (int) (Math.round(L2LibraryConfig.CLIENT.infoAlpha.get() * 255)) << 24 | 0x100010;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int bg = getBGColor();
|
||||||
|
public int bs = 0x505000FF;
|
||||||
|
public int be = 0x5028007f;
|
||||||
|
public int tc = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
protected final GuiGraphics g;
|
||||||
|
protected final int x0, y0, maxW;
|
||||||
|
|
||||||
|
public OverlayUtil(GuiGraphics g, int x0, int y0, int maxW) {
|
||||||
|
this.g = g;
|
||||||
|
this.x0 = x0;
|
||||||
|
this.y0 = y0;
|
||||||
|
this.maxW = maxW < 0 ? getMaxWidth() : maxW;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxWidth() {
|
||||||
|
return g.guiWidth() / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderLongText(Font font, List<Component> list) {
|
||||||
|
List<ClientTooltipComponent> ans = list.stream().flatMap(text -> font.split(text, maxW).stream())
|
||||||
|
.map(ClientTooltipComponent::create).toList();
|
||||||
|
renderTooltipInternal(font, ans);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderTooltipInternal(Font font, List<ClientTooltipComponent> list) {
|
||||||
|
if (list.isEmpty()) return;
|
||||||
|
int w = 0;
|
||||||
|
int h = list.size() == 1 ? -2 : 0;
|
||||||
|
for (ClientTooltipComponent c : list) {
|
||||||
|
int wi = c.getWidth(font);
|
||||||
|
if (wi > w) {
|
||||||
|
w = wi;
|
||||||
|
}
|
||||||
|
h += c.getHeight();
|
||||||
|
}
|
||||||
|
int wf = w;
|
||||||
|
int hf = h;
|
||||||
|
Vector2ic pos = positionTooltip(g.guiWidth(), g.guiHeight(), x0, y0, wf, hf);
|
||||||
|
int xf = pos.x();
|
||||||
|
int yf = pos.y();
|
||||||
|
g.pose().pushPose();
|
||||||
|
int z = 400;
|
||||||
|
g.drawManaged(() -> TooltipRenderUtil.renderTooltipBackground(g, xf, yf, wf, hf, z, bg, bg, bs, be));
|
||||||
|
g.pose().translate(0.0F, 0.0F, z);
|
||||||
|
int yi = yf;
|
||||||
|
for (int i = 0; i < list.size(); ++i) {
|
||||||
|
ClientTooltipComponent c = list.get(i);
|
||||||
|
c.renderText(font, xf, yi, g.pose().last().pose(), g.bufferSource());
|
||||||
|
yi += c.getHeight() + (i == 0 ? 2 : 0);
|
||||||
|
}
|
||||||
|
yi = yf;
|
||||||
|
for (int i = 0; i < list.size(); ++i) {
|
||||||
|
ClientTooltipComponent c = list.get(i);
|
||||||
|
c.renderImage(font, xf, yi, g);
|
||||||
|
yi += c.getHeight() + (i == 0 ? 2 : 0);
|
||||||
|
}
|
||||||
|
g.pose().popPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector2ic positionTooltip(int gw, int gh, int x, int y, int tw, int th) {
|
||||||
|
if (x < 0) x = Math.round(gw / 8f);
|
||||||
|
if (y < 0) y = Math.round((gh - th) / 2f);
|
||||||
|
return new Vector2i(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* specifies outer size
|
||||||
|
*/
|
||||||
|
public static void fillRect(GuiGraphics g, int x, int y, int w, int h, int col) {
|
||||||
|
g.fill(x, y, x + w, y + h, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* specifies inner size
|
||||||
|
*/
|
||||||
|
public static void drawRect(GuiGraphics g, int x, int y, int w, int h, int col) {
|
||||||
|
fillRect(g, x - 1, y - 1, w + 2, 1, col);
|
||||||
|
fillRect(g, x - 1, y - 1, 1, h + 2, col);
|
||||||
|
fillRect(g, x - 1, y + h, w + 2, 1, col);
|
||||||
|
fillRect(g, x + w, y - 1, 1, h + 2, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package dev.xkmc.l2core.base.overlay;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.Font;
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.neoforged.neoforge.client.gui.overlay.ExtendedGui;
|
||||||
|
import net.neoforged.neoforge.client.gui.overlay.IGuiOverlay;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class SelectionSideBar<T, S extends SideBar.Signature<S>> extends SideBar<S> implements IGuiOverlay {
|
||||||
|
|
||||||
|
public SelectionSideBar(float duration, float ease) {
|
||||||
|
super(duration, ease);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Pair<List<T>, Integer> getItems();
|
||||||
|
|
||||||
|
public abstract boolean isAvailable(T t);
|
||||||
|
|
||||||
|
public abstract boolean onCenter();
|
||||||
|
|
||||||
|
public void initRender() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(ExtendedGui gui, GuiGraphics g, float partialTick, int width, int height) {
|
||||||
|
if (!ease(gui.getGuiTicks() + partialTick))
|
||||||
|
return;
|
||||||
|
initRender();
|
||||||
|
gui.setupOverlayRenderState(true, false);
|
||||||
|
int x0 = this.getXOffset(width);
|
||||||
|
int y0 = this.getYOffset(height);
|
||||||
|
Context ctx = new Context(gui, g, partialTick, Minecraft.getInstance().font, x0, y0);
|
||||||
|
renderContent(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderContent(Context ctx) {
|
||||||
|
Pair<List<T>, Integer> content = getItems();
|
||||||
|
var list = content.getFirst();
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
renderEntry(ctx, list.get(i), i, content.getSecond());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void renderEntry(Context ctx, T t, int index, int select);
|
||||||
|
|
||||||
|
public record Context(ExtendedGui gui, GuiGraphics g, float pTick, Font font, int x0, int y0) {
|
||||||
|
|
||||||
|
public void renderItem(ItemStack stack, int x, int y) {
|
||||||
|
if (!stack.isEmpty()) {
|
||||||
|
g.renderItem(stack, x, y);
|
||||||
|
g.renderItemDecorations(font, stack, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
95
src/main/java/dev/xkmc/l2core/base/overlay/SideBar.java
Normal file
95
src/main/java/dev/xkmc/l2core/base/overlay/SideBar.java
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package dev.xkmc.l2core.base.overlay;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public abstract class SideBar<S extends SideBar.Signature<S>> {
|
||||||
|
|
||||||
|
public interface Signature<S extends Signature<S>> {
|
||||||
|
|
||||||
|
boolean shouldRefreshIdle(SideBar<?> sideBar, @Nullable S old);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public record IntSignature(int val) implements Signature<IntSignature> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldRefreshIdle(SideBar<?> sideBar, @Nullable SideBar.IntSignature old) {
|
||||||
|
return old == null || val != old.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final float max_time;
|
||||||
|
protected final float max_ease;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected S prev;
|
||||||
|
|
||||||
|
protected float idle = 0;
|
||||||
|
protected float ease_time = 0;
|
||||||
|
protected float prev_time = -1;
|
||||||
|
|
||||||
|
public SideBar(float duration, float ease) {
|
||||||
|
this.max_time = duration;
|
||||||
|
this.max_ease = ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract S getSignature();
|
||||||
|
|
||||||
|
public abstract boolean isScreenOn();
|
||||||
|
|
||||||
|
protected boolean isOnHold() {
|
||||||
|
return Minecraft.getInstance().options.keyShift.isDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean ease(float current_time) {
|
||||||
|
if (!isScreenOn()) {
|
||||||
|
prev = null;
|
||||||
|
idle = max_time;
|
||||||
|
ease_time = 0;
|
||||||
|
prev_time = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
float time_diff = prev_time < 0 ? 0 : (current_time - prev_time);
|
||||||
|
prev_time = current_time;
|
||||||
|
|
||||||
|
S signature = getSignature();
|
||||||
|
if (signature.shouldRefreshIdle(this, prev) || isOnHold()) {
|
||||||
|
idle = 0;
|
||||||
|
} else {
|
||||||
|
idle += time_diff;
|
||||||
|
}
|
||||||
|
prev = signature;
|
||||||
|
if (idle < max_time) {
|
||||||
|
if (ease_time < max_ease) {
|
||||||
|
ease_time += time_diff;
|
||||||
|
if (ease_time > max_ease) {
|
||||||
|
ease_time = max_ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ease_time > 0) {
|
||||||
|
ease_time -= time_diff;
|
||||||
|
if (ease_time < 0) {
|
||||||
|
ease_time = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ease_time > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRendering() {
|
||||||
|
return isScreenOn() && ease_time > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getXOffset(int width) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getYOffset(int height) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
30
src/main/java/dev/xkmc/l2core/base/overlay/TextBox.java
Normal file
30
src/main/java/dev/xkmc/l2core/base/overlay/TextBox.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package dev.xkmc.l2core.base.overlay;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
|
import org.joml.Vector2i;
|
||||||
|
import org.joml.Vector2ic;
|
||||||
|
|
||||||
|
public class TextBox extends OverlayUtil {
|
||||||
|
|
||||||
|
private final int anchorX, anchorY;
|
||||||
|
|
||||||
|
public TextBox(GuiGraphics g, int anchorX, int anchorY, int x, int y, int width) {
|
||||||
|
super(g, x, y, width);
|
||||||
|
this.anchorX = anchorX;
|
||||||
|
this.anchorY = anchorY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector2ic positionTooltip(int gw, int gh, int x, int y, int tw, int th) {
|
||||||
|
return new Vector2i(x - tw * anchorX / 2, y - th * anchorY / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxWidth() {
|
||||||
|
if (anchorX == 0) return g.guiWidth() - x0 - 8;
|
||||||
|
if (anchorX == 1) return Math.max(x0 / 2 - 4, g.guiWidth() - x0 / 2 - 4);
|
||||||
|
if (anchorX == 2) return x0 - 8;
|
||||||
|
return g.guiWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.base.overlay;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
63
src/main/java/dev/xkmc/l2core/base/tile/BaseBlockEntity.java
Normal file
63
src/main/java/dev/xkmc/l2core/base/tile/BaseBlockEntity.java
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package dev.xkmc.l2core.base.tile;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.util.ServerOnly;
|
||||||
|
import dev.xkmc.l2serial.serialization.SerialClass;
|
||||||
|
import dev.xkmc.l2serial.serialization.codec.TagCodec;
|
||||||
|
import dev.xkmc.l2serial.util.Wrappers;
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
@SerialClass
|
||||||
|
public class BaseBlockEntity extends BlockEntity {
|
||||||
|
|
||||||
|
public BaseBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||||
|
super(type, pos, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(CompoundTag tag) {
|
||||||
|
super.load(tag);
|
||||||
|
if (tag.contains("auto-serial"))
|
||||||
|
Wrappers.run(() -> TagCodec.fromTag(tag.getCompound("auto-serial"), getClass(), this, f -> true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveAdditional(CompoundTag tag) {
|
||||||
|
super.saveAdditional(tag);
|
||||||
|
CompoundTag ser = Wrappers.get(() -> TagCodec.toTag(new CompoundTag(), getClass(), this, f -> true));
|
||||||
|
if (ser != null) tag.put("auto-serial", ser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientboundBlockEntityDataPacket getUpdatePacket() {
|
||||||
|
return ClientboundBlockEntityDataPacket.create(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ServerOnly
|
||||||
|
public void sync() {
|
||||||
|
if (level != null) {
|
||||||
|
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate data packet from server to client, called from getUpdatePacket()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CompoundTag getUpdateTag() {
|
||||||
|
CompoundTag ans = super.getUpdateTag();
|
||||||
|
CompoundTag ser = Wrappers.get(() -> TagCodec.toTag(new CompoundTag(), getClass(), this, SerialClass.SerialField::toClient));
|
||||||
|
if (ser != null) ans.put("auto-serial", ser);
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
107
src/main/java/dev/xkmc/l2core/base/tile/BaseContainer.java
Normal file
107
src/main/java/dev/xkmc/l2core/base/tile/BaseContainer.java
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package dev.xkmc.l2core.base.tile;
|
||||||
|
|
||||||
|
import dev.xkmc.l2serial.serialization.codec.AliasCollection;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.SimpleContainer;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
public class BaseContainer<T extends BaseContainer<T>> extends SimpleContainer implements AliasCollection<ItemStack> {
|
||||||
|
|
||||||
|
private int max = 64;
|
||||||
|
private Predicate<ItemStack> predicate = e -> true;
|
||||||
|
|
||||||
|
public BaseContainer(int size) {
|
||||||
|
super(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T setMax(int max) {
|
||||||
|
this.max = Mth.clamp(max, 1, 64);
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T setPredicate(Predicate<ItemStack> predicate) {
|
||||||
|
this.predicate = predicate;
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T add(BaseContainerListener t) {
|
||||||
|
addListener(t);
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canAddWhileHaveSpace(ItemStack add, int space) {
|
||||||
|
int ans = 0;
|
||||||
|
for (ItemStack stack : items) {
|
||||||
|
if (stack.isEmpty())
|
||||||
|
ans++;
|
||||||
|
else if (ItemStack.isSameItemSameTags(stack, add) &&
|
||||||
|
stack.getCount() + add.getCount() <=
|
||||||
|
Math.min(stack.getMaxStackSize(), getMaxStackSize())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ans - 1 >= space;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlaceItem(int slot, ItemStack stack) {
|
||||||
|
return predicate.test(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAddItem(ItemStack stack) {
|
||||||
|
return predicate.test(stack) && super.canAddItem(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canRecipeAddItem(ItemStack stack) {
|
||||||
|
stack = stack.copy();
|
||||||
|
for (ItemStack slot : this.items) {
|
||||||
|
if (slot.isEmpty() || ItemStack.isSameItemSameTags(slot, stack)) {
|
||||||
|
int cap = Math.min(getMaxStackSize(), slot.getMaxStackSize());
|
||||||
|
int amount = Math.min(stack.getCount(), cap - slot.getCount());
|
||||||
|
if (amount > 0) {
|
||||||
|
stack.shrink(amount);
|
||||||
|
if (stack.getCount() == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxStackSize() {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getAsList() {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
super.clearContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(int n, int i, ItemStack elem) {
|
||||||
|
items.set(i, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<ItemStack> getElemClass() {
|
||||||
|
return ItemStack.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T getThis() {
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package dev.xkmc.l2core.base.tile;
|
||||||
|
|
||||||
|
import net.minecraft.world.Container;
|
||||||
|
import net.minecraft.world.ContainerListener;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
public interface BaseContainerListener extends ContainerListener {
|
||||||
|
|
||||||
|
void notifyTile();
|
||||||
|
|
||||||
|
@SuppressWarnings({"unsafe", "unchecked"})
|
||||||
|
@Override
|
||||||
|
default void containerChanged(Container cont) {
|
||||||
|
notifyTile();
|
||||||
|
}
|
||||||
|
}
|
||||||
213
src/main/java/dev/xkmc/l2core/base/tile/BaseTank.java
Normal file
213
src/main/java/dev/xkmc/l2core/base/tile/BaseTank.java
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
package dev.xkmc.l2core.base.tile;
|
||||||
|
|
||||||
|
import dev.xkmc.l2serial.serialization.SerialClass;
|
||||||
|
import dev.xkmc.l2serial.serialization.codec.AliasCollection;
|
||||||
|
import net.minecraft.core.NonNullList;
|
||||||
|
import net.neoforged.neoforge.fluids.FluidStack;
|
||||||
|
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
@SerialClass
|
||||||
|
public class BaseTank implements IFluidHandler, AliasCollection<FluidStack> {
|
||||||
|
|
||||||
|
private final int size, capacity;
|
||||||
|
private final List<BaseContainerListener> listeners = new ArrayList<>();
|
||||||
|
|
||||||
|
private Predicate<FluidStack> predicate = e -> true;
|
||||||
|
private BooleanSupplier allowExtract = () -> true;
|
||||||
|
|
||||||
|
@SerialClass.SerialField
|
||||||
|
public NonNullList<FluidStack> list;
|
||||||
|
|
||||||
|
private int click_max;
|
||||||
|
|
||||||
|
public BaseTank(int size, int capacity) {
|
||||||
|
this.size = size;
|
||||||
|
this.capacity = capacity;
|
||||||
|
list = NonNullList.withSize(size, FluidStack.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseTank add(BaseContainerListener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseTank setPredicate(Predicate<FluidStack> predicate) {
|
||||||
|
this.predicate = predicate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseTank setExtract(BooleanSupplier allowExtract) {
|
||||||
|
this.allowExtract = allowExtract;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseTank setClickMax(int max) {
|
||||||
|
this.click_max = max;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTanks() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public FluidStack getFluidInTank(int tank) {
|
||||||
|
return list.get(tank);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTankCapacity(int tank) {
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFluidValid(int tank, @NotNull FluidStack stack) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int fill(FluidStack resource, FluidAction action) {
|
||||||
|
if (resource.isEmpty()) return 0;
|
||||||
|
if (!predicate.test(resource)) return 0;
|
||||||
|
int to_fill = click_max == 0 ? resource.getAmount() : resource.getAmount() >= click_max ? click_max : 0;
|
||||||
|
if (to_fill == 0) return 0;
|
||||||
|
int filled = 0;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
FluidStack stack = list.get(i);
|
||||||
|
if (stack.isFluidEqual(resource)) {
|
||||||
|
int remain = capacity - stack.getAmount();
|
||||||
|
int fill = Math.min(to_fill, remain);
|
||||||
|
filled += fill;
|
||||||
|
to_fill -= fill;
|
||||||
|
if (action == FluidAction.EXECUTE) {
|
||||||
|
resource.shrink(fill);
|
||||||
|
stack.grow(fill);
|
||||||
|
}
|
||||||
|
} else if (stack.isEmpty()) {
|
||||||
|
int fill = Math.min(to_fill, capacity);
|
||||||
|
filled += fill;
|
||||||
|
to_fill -= fill;
|
||||||
|
if (action == FluidAction.EXECUTE) {
|
||||||
|
FluidStack rep = resource.copy();
|
||||||
|
rep.setAmount(fill);
|
||||||
|
list.set(i, rep);
|
||||||
|
resource.shrink(fill);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resource.isEmpty() || to_fill == 0) break;
|
||||||
|
}
|
||||||
|
if (action == FluidAction.EXECUTE && filled > 0) {
|
||||||
|
setChanged();
|
||||||
|
}
|
||||||
|
return filled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public FluidStack drain(FluidStack resource, FluidAction action) {
|
||||||
|
if (resource.isEmpty()) return resource;
|
||||||
|
if (!allowExtract.getAsBoolean()) return FluidStack.EMPTY;
|
||||||
|
int to_drain = resource.getAmount();
|
||||||
|
if (click_max > 0) {
|
||||||
|
if (to_drain < click_max) return FluidStack.EMPTY;
|
||||||
|
to_drain = click_max;
|
||||||
|
}
|
||||||
|
int drained = 0;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
FluidStack stack = list.get(i);
|
||||||
|
if (stack.isFluidEqual(resource)) {
|
||||||
|
int remain = stack.getAmount();
|
||||||
|
int drain = Math.min(to_drain, remain);
|
||||||
|
drained += drain;
|
||||||
|
to_drain -= drain;
|
||||||
|
if (action == FluidAction.EXECUTE) {
|
||||||
|
stack.shrink(drain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (to_drain == 0) break;
|
||||||
|
}
|
||||||
|
if (action == FluidAction.EXECUTE && drained > 0) {
|
||||||
|
setChanged();
|
||||||
|
}
|
||||||
|
FluidStack ans = resource.copy();
|
||||||
|
ans.setAmount(drained);
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||||
|
if (!allowExtract.getAsBoolean()) return FluidStack.EMPTY;
|
||||||
|
FluidStack ans = null;
|
||||||
|
int to_drain = maxDrain;
|
||||||
|
if (click_max > 0) {
|
||||||
|
if (to_drain < click_max) return FluidStack.EMPTY;
|
||||||
|
to_drain = click_max;
|
||||||
|
}
|
||||||
|
int drained = 0;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
FluidStack stack = list.get(i);
|
||||||
|
if (!stack.isEmpty() && (ans == null || stack.isFluidEqual(ans))) {
|
||||||
|
int remain = stack.getAmount();
|
||||||
|
int drain = Math.min(to_drain, remain);
|
||||||
|
drained += drain;
|
||||||
|
to_drain -= drain;
|
||||||
|
if (ans == null) {
|
||||||
|
ans = stack.copy();
|
||||||
|
}
|
||||||
|
if (action == FluidAction.EXECUTE) {
|
||||||
|
stack.shrink(drain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (to_drain == 0) break;
|
||||||
|
}
|
||||||
|
if (action == FluidAction.EXECUTE && drained > 0) {
|
||||||
|
setChanged();
|
||||||
|
}
|
||||||
|
if (ans == null) {
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
}
|
||||||
|
ans.setAmount(drained);
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChanged() {
|
||||||
|
listeners.forEach(BaseContainerListener::notifyTile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FluidStack> getAsList() {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(int n, int i, FluidStack elem) {
|
||||||
|
list.set(i, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<FluidStack> getElemClass() {
|
||||||
|
return FluidStack.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
for (FluidStack stack : list) {
|
||||||
|
if (!stack.isEmpty())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
182
src/main/java/dev/xkmc/l2core/base/tile/CombinedTankWrapper.java
Normal file
182
src/main/java/dev/xkmc/l2core/base/tile/CombinedTankWrapper.java
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
package dev.xkmc.l2core.base.tile;
|
||||||
|
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import net.neoforged.neoforge.fluids.FluidStack;
|
||||||
|
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
|
||||||
|
import net.neoforged.neoforge.items.wrapper.EmptyHandler;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* from Create
|
||||||
|
*/
|
||||||
|
public class CombinedTankWrapper implements IFluidHandler {
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
INSERT, EXTRACT, ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<Pair<IFluidHandler, Type>> list = new ArrayList<>();
|
||||||
|
|
||||||
|
protected int[] baseIndex;
|
||||||
|
protected int tankCount;
|
||||||
|
protected boolean enforceVariety;
|
||||||
|
|
||||||
|
public CombinedTankWrapper build() {
|
||||||
|
this.baseIndex = new int[list.size()];
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
index += list.get(i).getFirst().getTanks();
|
||||||
|
baseIndex[i] = index;
|
||||||
|
}
|
||||||
|
this.tankCount = index;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CombinedTankWrapper add(Type type, IFluidHandler... handlers) {
|
||||||
|
for (IFluidHandler handler : handlers) {
|
||||||
|
list.add(Pair.of(handler, type));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected Iterable<IFluidHandler> fillable() {
|
||||||
|
return list.stream().filter(e -> e.getSecond() != Type.EXTRACT).map(Pair::getFirst).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Iterable<IFluidHandler> drainable() {
|
||||||
|
return list.stream().filter(e -> e.getSecond() != Type.INSERT).map(Pair::getFirst).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CombinedTankWrapper enforceVariety() {
|
||||||
|
enforceVariety = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTanks() {
|
||||||
|
return tankCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidStack getFluidInTank(int tank) {
|
||||||
|
int index = getIndexForSlot(tank);
|
||||||
|
IFluidHandler handler = getHandlerFromIndex(index);
|
||||||
|
tank = getSlotFromIndex(tank, index);
|
||||||
|
return handler.getFluidInTank(tank);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTankCapacity(int tank) {
|
||||||
|
int index = getIndexForSlot(tank);
|
||||||
|
IFluidHandler handler = getHandlerFromIndex(index);
|
||||||
|
int localSlot = getSlotFromIndex(tank, index);
|
||||||
|
return handler.getTankCapacity(localSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFluidValid(int tank, FluidStack stack) {
|
||||||
|
int index = getIndexForSlot(tank);
|
||||||
|
IFluidHandler handler = getHandlerFromIndex(index);
|
||||||
|
int localSlot = getSlotFromIndex(tank, index);
|
||||||
|
return handler.isFluidValid(localSlot, stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int fill(FluidStack resource, FluidAction action) {
|
||||||
|
if (resource.isEmpty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int filled = 0;
|
||||||
|
resource = resource.copy();
|
||||||
|
|
||||||
|
boolean fittingHandlerFound = false;
|
||||||
|
Outer:
|
||||||
|
for (boolean searchPass : new boolean[]{true, false}) {
|
||||||
|
for (IFluidHandler iFluidHandler : fillable()) {
|
||||||
|
|
||||||
|
for (int i = 0; i < iFluidHandler.getTanks(); i++)
|
||||||
|
if (searchPass && iFluidHandler.getFluidInTank(i)
|
||||||
|
.isFluidEqual(resource))
|
||||||
|
fittingHandlerFound = true;
|
||||||
|
|
||||||
|
if (searchPass && !fittingHandlerFound)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int filledIntoCurrent = iFluidHandler.fill(resource, action);
|
||||||
|
resource.shrink(filledIntoCurrent);
|
||||||
|
filled += filledIntoCurrent;
|
||||||
|
|
||||||
|
if (resource.isEmpty() || fittingHandlerFound || enforceVariety && filledIntoCurrent != 0)
|
||||||
|
break Outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidStack drain(FluidStack resource, FluidAction action) {
|
||||||
|
if (resource.isEmpty())
|
||||||
|
return resource;
|
||||||
|
|
||||||
|
FluidStack drained = FluidStack.EMPTY;
|
||||||
|
resource = resource.copy();
|
||||||
|
|
||||||
|
for (IFluidHandler iFluidHandler : drainable()) {
|
||||||
|
FluidStack drainedFromCurrent = iFluidHandler.drain(resource, action);
|
||||||
|
int amount = drainedFromCurrent.getAmount();
|
||||||
|
resource.shrink(amount);
|
||||||
|
|
||||||
|
if (!drainedFromCurrent.isEmpty() && (drained.isEmpty() || drainedFromCurrent.isFluidEqual(drained)))
|
||||||
|
drained = new FluidStack(drainedFromCurrent.getFluid(), amount + drained.getAmount(),
|
||||||
|
drainedFromCurrent.getTag());
|
||||||
|
if (resource.isEmpty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return drained;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||||
|
FluidStack drained = FluidStack.EMPTY;
|
||||||
|
|
||||||
|
for (IFluidHandler iFluidHandler : drainable()) {
|
||||||
|
FluidStack drainedFromCurrent = iFluidHandler.drain(maxDrain, action);
|
||||||
|
int amount = drainedFromCurrent.getAmount();
|
||||||
|
maxDrain -= amount;
|
||||||
|
|
||||||
|
if (!drainedFromCurrent.isEmpty() && (drained.isEmpty() || drainedFromCurrent.isFluidEqual(drained)))
|
||||||
|
drained = new FluidStack(drainedFromCurrent.getFluid(), amount + drained.getAmount(),
|
||||||
|
drainedFromCurrent.getTag());
|
||||||
|
if (maxDrain == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return drained;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getIndexForSlot(int slot) {
|
||||||
|
if (slot < 0)
|
||||||
|
return -1;
|
||||||
|
for (int i = 0; i < baseIndex.length; i++)
|
||||||
|
if (slot - baseIndex[i] < 0)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IFluidHandler getHandlerFromIndex(int index) {
|
||||||
|
if (index < 0 || index >= list.size())
|
||||||
|
return (IFluidHandler) EmptyHandler.INSTANCE;
|
||||||
|
return list.get(index).getFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getSlotFromIndex(int slot, int index) {
|
||||||
|
if (index <= 0 || index >= baseIndex.length)
|
||||||
|
return slot;
|
||||||
|
return slot - baseIndex[index - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.base.tile;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package dev.xkmc.l2core.capability.attachment;
|
||||||
|
|
||||||
|
import dev.xkmc.l2serial.serialization.codec.TagCodec;
|
||||||
|
import dev.xkmc.l2serial.util.Wrappers;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.neoforged.neoforge.attachment.AttachmentType;
|
||||||
|
import net.neoforged.neoforge.attachment.IAttachmentHolder;
|
||||||
|
import net.neoforged.neoforge.attachment.IAttachmentSerializer;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class AttachmentDef<E> implements IAttachmentSerializer<CompoundTag, E> {
|
||||||
|
private final Class<E> cls;
|
||||||
|
private final Supplier<E> sup;
|
||||||
|
private AttachmentType<E> type;
|
||||||
|
|
||||||
|
public AttachmentDef(Class<E> cls, Supplier<E> sup) {
|
||||||
|
this.cls = cls;
|
||||||
|
this.sup = sup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttachmentType<E> type() {
|
||||||
|
if (type != null) return type;
|
||||||
|
var builder = AttachmentType.builder(sup);
|
||||||
|
builder.serialize(this);
|
||||||
|
if (copyOnDeath())
|
||||||
|
builder.copyOnDeath();
|
||||||
|
type = builder.build();
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean copyOnDeath() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E read(IAttachmentHolder holder, CompoundTag tag) {
|
||||||
|
return Objects.requireNonNull(Wrappers.get(() -> TagCodec.fromTag(tag, cls, null, f -> true)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag write(E attachment) {
|
||||||
|
return Objects.requireNonNull(TagCodec.toTag(new CompoundTag(), attachment));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<E> cls() {
|
||||||
|
return cls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFor(IAttachmentHolder holder) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package dev.xkmc.l2core.capability.attachment;
|
||||||
|
|
||||||
|
public class BaseAttachment {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package dev.xkmc.l2core.capability.attachment;
|
||||||
|
|
||||||
|
import dev.xkmc.l2serial.util.Wrappers;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.neoforged.neoforge.attachment.IAttachmentHolder;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* only entities will be automatically attached by default for efficiency
|
||||||
|
*/
|
||||||
|
public class GeneralCapabilityHolder<E extends IAttachmentHolder, T extends GeneralCapabilityTemplate<E, T>> extends AttachmentDef<T> {
|
||||||
|
|
||||||
|
public static final Map<ResourceLocation, GeneralCapabilityHolder<?, ?>> INTERNAL_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public final ResourceLocation id;
|
||||||
|
public final Class<E> entity_class;
|
||||||
|
private final Predicate<E> pred;
|
||||||
|
|
||||||
|
|
||||||
|
public GeneralCapabilityHolder(ResourceLocation id, Class<T> holder_class, Supplier<T> sup,
|
||||||
|
Class<E> entity_class, Predicate<E> pred) {
|
||||||
|
super(holder_class, sup);
|
||||||
|
this.id = id;
|
||||||
|
this.entity_class = entity_class;
|
||||||
|
this.pred = pred;
|
||||||
|
INTERNAL_MAP.put(id, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T get(E e) {
|
||||||
|
return e.getData(type());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFor(IAttachmentHolder holder) {
|
||||||
|
return entity_class.isInstance(holder) && isProper(Wrappers.cast(holder));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isProper(E entity) {
|
||||||
|
return pred.test(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package dev.xkmc.l2core.capability.attachment;
|
||||||
|
|
||||||
|
import dev.xkmc.l2serial.util.Wrappers;
|
||||||
|
|
||||||
|
public class GeneralCapabilityTemplate<E, T extends GeneralCapabilityTemplate<E, T>> {
|
||||||
|
|
||||||
|
public T getThis() {
|
||||||
|
return Wrappers.cast(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick(E e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.capability.attachment;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package dev.xkmc.l2core.capability.conditionals;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.init.L2LibReg;
|
||||||
|
import dev.xkmc.l2core.util.Proxy;
|
||||||
|
import dev.xkmc.l2serial.util.Wrappers;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
|
public class ClientDataHandler {
|
||||||
|
|
||||||
|
public static <T extends ConditionalToken> void handle(TokenKey<T> key, T token) {
|
||||||
|
Player player = Proxy.getClientPlayer();
|
||||||
|
if (player == null) return;
|
||||||
|
ConditionalToken old = L2LibReg.CONDITIONAL.type().get(player).data.put(key, token);
|
||||||
|
if (token instanceof NetworkSensitiveToken<?> t) {
|
||||||
|
t.onSync(Wrappers.cast(old), player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package dev.xkmc.l2core.capability.conditionals;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.capability.player.PlayerCapabilityTemplate;
|
||||||
|
import dev.xkmc.l2core.init.L2LibraryConfig;
|
||||||
|
import dev.xkmc.l2serial.serialization.SerialClass;
|
||||||
|
import dev.xkmc.l2serial.util.Wrappers;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@SerialClass
|
||||||
|
public class ConditionalData extends PlayerCapabilityTemplate<ConditionalData> {
|
||||||
|
|
||||||
|
@SerialClass.SerialField
|
||||||
|
public HashMap<TokenKey<?>, ConditionalToken> data = new HashMap<>();
|
||||||
|
@SerialClass.SerialField
|
||||||
|
public int tickSinceDeath = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClone(boolean isWasDeath) {
|
||||||
|
tickSinceDeath = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends ConditionalToken, C extends Context> T getOrCreateData(TokenProvider<T, C> setEffect, C ent) {
|
||||||
|
return Wrappers.cast(data.computeIfAbsent(setEffect.getKey(), e -> setEffect.getData(ent)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public <T extends ConditionalToken> T getData(TokenKey<T> setEffect) {
|
||||||
|
return Wrappers.cast(data.get(setEffect));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(Player player) {
|
||||||
|
tickSinceDeath++;
|
||||||
|
if (L2LibraryConfig.SERVER.restoreFullHealthOnRespawn.get() &&
|
||||||
|
tickSinceDeath < 60 && player.getHealth() < player.getMaxHealth()) {
|
||||||
|
player.setHealth(player.getMaxHealth());
|
||||||
|
}
|
||||||
|
data.entrySet().removeIf(e -> e.getValue().tick(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasData(TokenKey<?> eff) {
|
||||||
|
return data.containsKey(eff);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package dev.xkmc.l2core.capability.conditionals;
|
||||||
|
|
||||||
|
import dev.xkmc.l2serial.serialization.SerialClass;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
|
@SerialClass
|
||||||
|
public class ConditionalToken {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true to remove
|
||||||
|
*/
|
||||||
|
public boolean tick(Player player) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package dev.xkmc.l2core.capability.conditionals;
|
||||||
|
|
||||||
|
public interface Context {
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package dev.xkmc.l2core.capability.conditionals;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.init.L2Core;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public interface NetworkSensitiveToken<T extends ConditionalToken> {
|
||||||
|
void onSync(@Nullable T old, Player player);
|
||||||
|
|
||||||
|
default void sync(TokenKey<T> key, T token, ServerPlayer sp) {
|
||||||
|
L2Core.PACKET_HANDLER.toClientPlayer(TokenToClient.of(key, token), sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package dev.xkmc.l2core.capability.conditionals;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public record TokenKey<T extends ConditionalToken>(String type, String id) {
|
||||||
|
|
||||||
|
public static <T extends ConditionalToken> TokenKey<T> of(ResourceLocation id) {
|
||||||
|
return new TokenKey<>(id.getNamespace(), id.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceLocation asLocation() {
|
||||||
|
return new ResourceLocation(type, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package dev.xkmc.l2core.capability.conditionals;
|
||||||
|
|
||||||
|
public interface TokenProvider<T extends ConditionalToken, C extends Context> {
|
||||||
|
|
||||||
|
T getData(C ent);
|
||||||
|
|
||||||
|
TokenKey<T> getKey();
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package dev.xkmc.l2core.capability.conditionals;
|
||||||
|
|
||||||
|
import dev.xkmc.l2serial.network.SerialPacketBase;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public record TokenToClient(ResourceLocation id, ConditionalToken token)
|
||||||
|
implements SerialPacketBase<TokenToClient> {
|
||||||
|
|
||||||
|
public static <T extends ConditionalToken> TokenToClient of(TokenKey<T> key, T token) {
|
||||||
|
return new TokenToClient(key.asLocation(), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(@Nullable Player player) {
|
||||||
|
ClientDataHandler.handle(TokenKey.of(id), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.capability.conditionals;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package dev.xkmc.l2core.capability.level;
|
||||||
|
|
||||||
|
import dev.xkmc.l2serial.serialization.SerialClass;
|
||||||
|
import dev.xkmc.l2serial.serialization.codec.TagCodec;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.world.level.saveddata.SavedData;
|
||||||
|
|
||||||
|
@SerialClass
|
||||||
|
public class BaseSavedData extends SavedData {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag save(CompoundTag tag) {
|
||||||
|
TagCodec.toTag(tag, this);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDirty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.capability.level;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package dev.xkmc.l2core.capability.player;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.util.Proxy;
|
||||||
|
import dev.xkmc.l2serial.serialization.SerialClass;
|
||||||
|
import dev.xkmc.l2serial.serialization.codec.PacketCodec;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
public class ClientSyncHandler {
|
||||||
|
|
||||||
|
public static <T extends PlayerCapabilityTemplate<T>> void parse(byte[] tag, PlayerCapabilityHolder<T> holder, Predicate<SerialClass.SerialField> pred) {
|
||||||
|
PacketCodec.fromBytes(tag, holder.cls(), Proxy.getClientPlayer().getData(holder.type()), pred);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package dev.xkmc.l2core.capability.player;
|
||||||
|
|
||||||
|
import dev.xkmc.l2serial.network.SerialPacketBase;
|
||||||
|
import dev.xkmc.l2serial.serialization.SerialClass;
|
||||||
|
import dev.xkmc.l2serial.serialization.codec.PacketCodec;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
@SerialClass
|
||||||
|
public record PlayerCapToClient(Action action, ResourceLocation holderID, byte[] data, UUID playerID)
|
||||||
|
implements SerialPacketBase<PlayerCapToClient> {
|
||||||
|
|
||||||
|
public static <T extends PlayerCapabilityTemplate<T>> PlayerCapToClient
|
||||||
|
of(ServerPlayer player, Action action, PlayerCapabilityHolder<T> holder, T handler) {
|
||||||
|
return new PlayerCapToClient(action, holder.id,
|
||||||
|
PacketCodec.toBytes(handler, holder.cls(), action.pred),
|
||||||
|
player.getUUID());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(@Nullable Player player) {
|
||||||
|
ClientSyncHandler.parse(data, PlayerCapabilityHolder.INTERNAL_MAP.get(holderID), action.pred);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Action {
|
||||||
|
ALL(e -> true),
|
||||||
|
CLIENT(SerialClass.SerialField::toClient),
|
||||||
|
TRACK(SerialClass.SerialField::toTracking),
|
||||||
|
;
|
||||||
|
public final Predicate<SerialClass.SerialField> pred;
|
||||||
|
|
||||||
|
Action(Predicate<SerialClass.SerialField> pred) {
|
||||||
|
this.pred = pred;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package dev.xkmc.l2core.capability.player;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.capability.attachment.GeneralCapabilityHolder;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class PlayerCapabilityHolder<T extends PlayerCapabilityTemplate<T>> extends GeneralCapabilityHolder<Player, T> {
|
||||||
|
|
||||||
|
public static final Map<ResourceLocation, PlayerCapabilityHolder<?>> INTERNAL_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public final PlayerCapabilityNetworkHandler<T> network;
|
||||||
|
|
||||||
|
public PlayerCapabilityHolder(ResourceLocation id, Class<T> cls, Supplier<T> sup, NetworkFactory<T> network) {
|
||||||
|
super(id, cls, sup, Player.class, e -> true);
|
||||||
|
this.network = network.create(this);
|
||||||
|
INTERNAL_MAP.put(id, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean copyOnDeath() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface NetworkFactory<T extends PlayerCapabilityTemplate<T>> {
|
||||||
|
|
||||||
|
PlayerCapabilityNetworkHandler<T> create(PlayerCapabilityHolder<T> holder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package dev.xkmc.l2core.capability.player;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.init.L2Core;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
|
||||||
|
public class PlayerCapabilityNetworkHandler<T extends PlayerCapabilityTemplate<T>> {
|
||||||
|
|
||||||
|
public final PlayerCapabilityHolder<T> holder;
|
||||||
|
|
||||||
|
public PlayerCapabilityNetworkHandler(PlayerCapabilityHolder<T> holder) {
|
||||||
|
this.holder = holder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toClient(ServerPlayer e) {
|
||||||
|
L2Core.PACKET_HANDLER.toClientPlayer(PlayerCapToClient.of(e, PlayerCapToClient.Action.CLIENT, holder, holder.get(e)), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toTracking(ServerPlayer e) {
|
||||||
|
L2Core.PACKET_HANDLER.toTrackingOnly(PlayerCapToClient.of(e, PlayerCapToClient.Action.TRACK, holder, holder.get(e)), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startTracking(ServerPlayer tracker, ServerPlayer target) {
|
||||||
|
L2Core.PACKET_HANDLER.toClientPlayer(PlayerCapToClient.of(target, PlayerCapToClient.Action.TRACK, holder, holder.get(target)), tracker);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package dev.xkmc.l2core.capability.player;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.capability.attachment.GeneralCapabilityTemplate;
|
||||||
|
import dev.xkmc.l2serial.serialization.SerialClass;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
|
||||||
|
@SerialClass
|
||||||
|
public class PlayerCapabilityTemplate<T extends PlayerCapabilityTemplate<T>> extends GeneralCapabilityTemplate<Player, T> {
|
||||||
|
|
||||||
|
public void init(Player player) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onClone(boolean isWasDeath) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.capability.player;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package dev.xkmc.l2core.compat.curios;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public record CurioEntityBuilder(
|
||||||
|
ArrayList<ResourceLocation> entities,
|
||||||
|
ArrayList<String> slots,
|
||||||
|
ArrayList<SlotCondition> conditions) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package dev.xkmc.l2core.compat.curios;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static dev.xkmc.l2core.compat.curios.CurioSlotBuilder.Operation.SET;
|
||||||
|
|
||||||
|
public record CurioSlotBuilder(int order, String icon, int size,
|
||||||
|
Operation operation,
|
||||||
|
boolean add_cosmetic,
|
||||||
|
boolean use_native_gui,
|
||||||
|
boolean render_toggle,
|
||||||
|
boolean replace, ArrayList<SlotCondition> conditions) {
|
||||||
|
|
||||||
|
public CurioSlotBuilder(int order, String icon) {
|
||||||
|
this(order, icon, 1, SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CurioSlotBuilder(int order, String icon, int size,
|
||||||
|
Operation operation) {
|
||||||
|
this(order, icon, size, operation,
|
||||||
|
false, true, true, false, SlotCondition.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Operation {
|
||||||
|
SET, ADD, REMOVE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package dev.xkmc.l2core.compat.curios;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public record SlotCondition(String type, String modid) {
|
||||||
|
|
||||||
|
public static ArrayList<SlotCondition> of(String... ids) {
|
||||||
|
ArrayList<SlotCondition> ans = new ArrayList<>();
|
||||||
|
for (String id : ids) {
|
||||||
|
ans.add(new SlotCondition(id));
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotCondition(String modid) {
|
||||||
|
this("forge:mod_loaded", modid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
|
||||||
|
package dev.xkmc.l2core.compat.curios;
|
||||||
|
|
||||||
|
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
47
src/main/java/dev/xkmc/l2core/init/L2Core.java
Normal file
47
src/main/java/dev/xkmc/l2core/init/L2Core.java
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package dev.xkmc.l2core.init;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.base.effects.EffectToClient;
|
||||||
|
import dev.xkmc.l2core.capability.conditionals.TokenToClient;
|
||||||
|
import dev.xkmc.l2core.capability.player.PlayerCapToClient;
|
||||||
|
import dev.xkmc.l2core.serial.config.SyncPacket;
|
||||||
|
import dev.xkmc.l2serial.network.PacketHandler;
|
||||||
|
import dev.xkmc.l2serial.serialization.custom_handler.Handlers;
|
||||||
|
import net.neoforged.bus.api.IEventBus;
|
||||||
|
import net.neoforged.bus.api.SubscribeEvent;
|
||||||
|
import net.neoforged.fml.common.EventBusSubscriber;
|
||||||
|
import net.neoforged.fml.common.Mod;
|
||||||
|
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import static dev.xkmc.l2serial.network.PacketHandler.NetDir.PLAY_TO_CLIENT;
|
||||||
|
|
||||||
|
// The value here should match an entry in the META-INF/mods.toml file
|
||||||
|
@Mod(L2Core.MODID)
|
||||||
|
@EventBusSubscriber(modid = L2Core.MODID, bus = EventBusSubscriber.Bus.MOD)
|
||||||
|
public class L2Core {
|
||||||
|
|
||||||
|
public static final String MODID = "l2core";
|
||||||
|
public static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
|
||||||
|
// TODO public static final L2Registrate REGISTRATE = new L2Registrate(MODID);
|
||||||
|
|
||||||
|
public static final PacketHandler PACKET_HANDLER = new PacketHandler(MODID, 1,
|
||||||
|
e -> e.create(SyncPacket.class, PLAY_TO_CLIENT),
|
||||||
|
e -> e.create(EffectToClient.class, PLAY_TO_CLIENT),
|
||||||
|
e -> e.create(PlayerCapToClient.class, PLAY_TO_CLIENT),
|
||||||
|
e -> e.create(TokenToClient.class, PLAY_TO_CLIENT)
|
||||||
|
);
|
||||||
|
|
||||||
|
public L2Core(IEventBus bus) {
|
||||||
|
Handlers.register();
|
||||||
|
L2LibReg.register(bus);
|
||||||
|
L2LibraryConfig.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onPacketReg(RegisterPayloadHandlersEvent event) {
|
||||||
|
PACKET_HANDLER.register(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
49
src/main/java/dev/xkmc/l2core/init/L2LibReg.java
Normal file
49
src/main/java/dev/xkmc/l2core/init/L2LibReg.java
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package dev.xkmc.l2core.init;
|
||||||
|
|
||||||
|
import dev.xkmc.l2core.base.effects.ClientEffectCap;
|
||||||
|
import dev.xkmc.l2core.base.menu.base.MenuLayoutConfig;
|
||||||
|
import dev.xkmc.l2core.capability.conditionals.ConditionalData;
|
||||||
|
import dev.xkmc.l2core.capability.player.PlayerCapabilityNetworkHandler;
|
||||||
|
import dev.xkmc.l2core.init.reg.datapack.DatapackReg;
|
||||||
|
import dev.xkmc.l2core.init.reg.simple.*;
|
||||||
|
import dev.xkmc.l2core.serial.conditions.*;
|
||||||
|
import dev.xkmc.l2core.serial.ingredients.EnchantmentIngredient;
|
||||||
|
import dev.xkmc.l2core.serial.ingredients.MobEffectIngredient;
|
||||||
|
import dev.xkmc.l2core.serial.ingredients.PotionIngredient;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.neoforged.bus.api.IEventBus;
|
||||||
|
import net.neoforged.neoforge.common.conditions.ICondition;
|
||||||
|
import net.neoforged.neoforge.registries.NeoForgeRegistries;
|
||||||
|
|
||||||
|
public class L2LibReg {
|
||||||
|
|
||||||
|
public static final Reg REG = new Reg(L2Core.MODID);
|
||||||
|
|
||||||
|
// ingredients
|
||||||
|
public static final IngReg INGREDIENT = IngReg.of(REG);
|
||||||
|
public static final IngVal<EnchantmentIngredient> ING_ENCH = INGREDIENT.reg("enchantment", EnchantmentIngredient.class);
|
||||||
|
public static final IngVal<PotionIngredient> ING_POTION = INGREDIENT.reg("potion", PotionIngredient.class);
|
||||||
|
public static final IngVal<MobEffectIngredient> ING_EFF = INGREDIENT.reg("mob_effect", MobEffectIngredient.class);
|
||||||
|
|
||||||
|
// conditions
|
||||||
|
public static final CdcReg<ICondition> CONDITION = CdcReg.of(REG, NeoForgeRegistries.CONDITION_SERIALIZERS);
|
||||||
|
public static final CdcVal<BooleanValueCondition> CONDITION_BOOL = CONDITION.reg("bool_config", BooleanValueCondition.class);
|
||||||
|
public static final CdcVal<IntValueCondition> CONDITION_INT = CONDITION.reg("int_config", IntValueCondition.class);
|
||||||
|
public static final CdcVal<DoubleValueCondition> CONDITION_DOUBLE = CONDITION.reg("double_config", DoubleValueCondition.class);
|
||||||
|
public static final CdcVal<StringValueCondition> CONDITION_STR = CONDITION.reg("string_config", StringValueCondition.class);
|
||||||
|
public static final CdcVal<ListStringValueCondition> CONDITION_LIST_STR = CONDITION.reg("string_list_config", ListStringValueCondition.class);
|
||||||
|
|
||||||
|
// attachments
|
||||||
|
public static final AttReg ATTACHMENT = AttReg.of(REG);
|
||||||
|
public static final AttVal.CapVal<LivingEntity, ClientEffectCap> EFFECT = ATTACHMENT.entity("effect",
|
||||||
|
ClientEffectCap.class, ClientEffectCap::new, LivingEntity.class, e -> e.level().isClientSide());
|
||||||
|
public static final AttVal.PlayerVal<ConditionalData> CONDITIONAL = ATTACHMENT.player("conditionals",
|
||||||
|
ConditionalData.class, ConditionalData::new, PlayerCapabilityNetworkHandler::new);
|
||||||
|
|
||||||
|
public static final DatapackReg<MenuLayoutConfig> MENU_LAYOUT = REG.dataReg("menu_layout", MenuLayoutConfig.class);
|
||||||
|
|
||||||
|
public static void register(IEventBus bus) {
|
||||||
|
REG.register(bus);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user