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