Goodbye 2

This commit is contained in:
cyberpwn 2022-06-25 19:06:45 -04:00
parent 43bd96a679
commit 80dff702fc
845 changed files with 0 additions and 114835 deletions

View File

@ -1,63 +0,0 @@
name: Iris Bug Report
description: File a bug report for Iris
labels: [ bug ]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill this out!
If this does not work for you, feel free to use the [blank](https://github.com/VolmitSoftware/Iris/issues/new) format.
- type: textarea
id: how
attributes:
label: Problem
description: Please give a text description of how you reached the problem
value: |
1. Install Iris...
2. Do this...
3. Do that...
4. Observe the error...
validations:
required: true
- type: textarea
id: what
attributes:
label: Solution
description: Explain where you think the problem comes from (optional)
placeholder: The code to place a is missing b and c...
validations:
required: false
- type: dropdown
id: mcversion
attributes:
label: Minecraft Version
description: What version of Minecraft is the server on?
options:
- 1.14.X
- 1.15.X
- 1.16.X
- 1.17
- 1.17.1
- 1.18
validations:
required: true
- type: input
id: irisversion
attributes:
label: Iris Version
description: What version of Iris are you running? (see console)
placeholder: DO NOT SAY "LATEST"
validations:
required: true
- type: input
id: logs
attributes:
label: Log
description: Paste a full log. Always use [mclogs](https://mclo.gs) Or [Pastebin](https://pastebin.com/). Must not be a crash report. Must be a full log. Must not be a screenshot of a log.
placeholder: https://mslog.gs/...
validations:
required: true
- type: markdown
id: thanks
attributes:
value: "Thank you for filling out the form! We will be with you soon. Please do not ask support to review your report."

View File

@ -1,46 +0,0 @@
name: Iris Feature Request
description: File a feature request for Iris. If you want to report a bug this is not the place.
labels: [ feature ]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill this out!
If this does not work for you, feel free to use the [blank](https://github.com/VolmitSoftware/Iris/issues/new) format.
- type: dropdown
id: arc
attributes:
label: Adding, Removing, or Changing
description: What are you doing
options:
- Adding
- Removing
- Changing
validations:
required: true
- type: input
id: atype
attributes:
label: Type of Modification
description: What is it for?
value: I want to ...
validations:
required: true
- type: textarea
id: desc
attributes:
label: What are you trying to modify
description: Give as detailed of a description as you can for the modification that you want done (include pictures if applicable)
value: The way I would implement this is ...
validations:
required: true
- type: textarea
id: alternative
attributes:
label: Alternatives
description: What alternatives have you considered?
value: If this could not be implemented I would ...
- type: markdown
id: thanks
attributes:
value: "Thank you for filling out the form! We will be with you soon. Please do not ask support to review your report."

BIN
IRIS.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -1,518 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for software and other kinds of works.
The licenses for most software and other practical works are designed to take away your freedom to share and change the
works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all
versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use
the GNU General Public License for most of our software; it applies also to any other work released this way by its
authors. You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make
sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive
source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and
that you know you can do these things.
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights.
Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it:
responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients
the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must
show them these terms so they know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute
and/or modify it.
For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software.
For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems
will not be attributed erroneously to authors of previous versions.
Some devices are designed to deny users access to install or run modified versions of the software inside them, although
the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the
software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely
where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we stand ready to extend this provision to those
domains in future versions of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict
development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger
that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "
Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission,
other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a
work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based on the Program.
To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily
liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy.
Propagation includes copying, distribution (with or without modification), making available to the public, and in some
countries other activities as well.
To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction
with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright
notice, and (2)
tells the user that there is no warranty for the work (except to the extent that warranties are provided), that
licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a
list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means
any non-source form of a work.
A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body,
or, in the case of interfaces specified for a particular programming language, one that is widely used among developers
working in that language.
The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in
the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to
enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is
available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used
to run it.
The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (
for an executable work) run the object code and to modify the work, including scripts to control those activities.
However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs
which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding
Source includes interface definition files associated with source files for the work, and the source code for shared
libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data
communication or control flow between those subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the
Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided
the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program.
The output from running a covered work is covered by this License only if the output, given its content, constitutes a
covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without conditions so long as your license
otherwise remains in force. You may convey covered works to others for the sole purpose of having them make
modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do not control copyright. Those thus making or running
the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that
prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not
allowed; section 10 makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling
obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or
restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the
extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you
disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users,
your or third parties' legal rights to forbid circumvention of technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating
that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices
of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for
a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source
code under the terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of
the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or
distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the
compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause
this License to apply to the other parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License, in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library,
need not be included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used
for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In
determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a
particular product received by a particular user, "normally used" refers to a typical or common use of that class of
product, regardless of the status of the particular user or of the way in which the particular user actually uses, or
expects or is expected to use, the product. A product is a consumer product regardless of whether the product has
substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of
the product.
"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information
required to install and execute modified versions of a covered work in that User Product from a modified version of its
Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code
is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the
conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to
the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding
Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not
apply if neither you nor any third party retains the ability to install modified object code on the User Product (for
example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support
service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product
in which it has been modified or installed. Access to a network may be denied when the modification itself materially
and adversely affects the operation of the network or violates the rules and protocols for communication across the
network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format
that is publicly documented (and with an implementation available to the public in source code form), and must require
no special password or key for unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of
its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were
included in this License, to the extent that they are valid under applicable law. If additional permissions apply only
to part of the Program, that part may be used separately under those permissions, but the entire Program remains
governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or
from any part of it. (Additional permissions may be written to require their own removal in certain cases when you
modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have
or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by
the copyright holders of that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the
Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with
a term that is a further restriction, you may remove that term. If a license document contains a further restriction but
permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of
that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a
statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as
exceptions; the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to
propagate or modify it is void, and will automatically terminate your rights under this License (including any patent
licenses granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a particular copyright holder is
reinstated (a)
provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b)
permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days
after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you
of the violation by some reasonable means, this is the first time you have received notice of violation of this
License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the
notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or
rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not
qualify to receive new licenses for the same material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a
covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not
require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered
work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run,
modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third
parties with this License.
An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or
subdividing an organization, or merging organizations. If propagation of a covered work results from an entity
transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work
the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with
reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For
example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License,
and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using,
selling, offering for sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the
Program is based. The work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already
acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or
selling its contributor version, but do not include claims that would be infringed only as a consequence of further
modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent
sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential
patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its
contributor version.
In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not
to enforce a patent
(such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a
patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not
available for anyone to copy, free of charge and under the terms of this License, through a publicly available network
server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available,
or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a
manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "
Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in
a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in
that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring
conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing
them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is
automatically extended to all recipients of the covered work and works based on it.
A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of,
or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You
may not convey a covered work if you are a party to an arrangement with a third party that is in the business of
distributing software, under which you make payment to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a
discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from
those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered
work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to
infringement that may otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this
License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to
satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence
you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further
conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License
would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work
licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the
resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special
requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply
to the combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to
time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new
problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the
GNU General Public License "or any later version" applies to it, you have the option of following the terms and
conditions either of that numbered version or of any later version published by the Free Software Foundation. If the
Program does not specify a version number of the GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used,
that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the
Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed
on any author or copyright holder as a result of your choosing to follow a later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING
THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU
ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO
MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO
LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to
their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil
liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program
in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve
this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to
most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer
to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of
course, your program's commands might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for
the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is
a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If
this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View File

@ -1,323 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2021 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
id 'java'
id 'java-library'
id "io.freefair.lombok" version "6.3.0"
id "com.github.johnrengelman.shadow" version "7.1.2"
id "de.undercouch.download" version "5.0.1"
}
version '2.2.1-1.19' // Needs to be version specific
def nmsVersion = "1.19"
def apiVersion = '1.19'
def spigotJarVersion = '1.19-R0.1-SNAPSHOT'
def name = getRootProject().getName() // Defined in settings.gradle
def main = 'com.volmit.iris.Iris'
// ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED
// ======================== WINDOWS =============================
registerCustomOutputTask('Cyberpwn', 'C://Users/cyberpwn/Documents/development/server/plugins')
registerCustomOutputTask('Psycho', 'D://Dan/MinecraftDevelopment/server/plugins')
registerCustomOutputTask('ArcaneArts', 'C://Users/arcane/Documents/development/server/plugins')
registerCustomOutputTask('Coco', 'D://Documents/MC/plugins')
registerCustomOutputTask('Strange', 'D://Servers/1.17 Test Server/plugins')
registerCustomOutputTask('Vatuu', 'D://Minecraft/Servers/1.19/plugins')
// ========================== UNIX ==============================
registerCustomOutputTaskUnix('CyberpwnLT', '/Users/danielmills/development/server/plugins')
registerCustomOutputTaskUnix('PsychoLT', '/Users/brianfopiano/Desktop/REMOTES/RemoteMinecraft/plugins')
// ==============================================================
/**
* Gradle is weird sometimes, we need to delete the plugin yml from the build folder to actually filter properly.
*/
file(jar.archiveFile.get().getAsFile().getParentFile().getParentFile().getParentFile().getAbsolutePath() + '/build/resources/main/plugin.yml').delete()
/**
* Expand properties into plugin yml
*/
processResources {
filesMatching('**/plugin.yml') {
expand(
'name': name.toString(),
'version': version.toString(),
'main': main.toString(),
'apiversion': apiVersion.toString()
)
}
}
/**
* Unified repo
*/
repositories {
mavenLocal {
content {
includeGroup("org.bukkit")
includeGroup("org.spigotmc")
}
}
maven { url "https://dl.cloudsmith.io/public/arcane/archive/maven/" }
maven { url "https://maven.enginehub.org/repo/" }
mavenCentral()
mavenLocal()
maven { url "https://jitpack.io"}
}
/**
* We need parameter meta for the decree command system
*/
compileJava {
options.compilerArgs << '-parameters'
}
/**
* Configure Iris for shading
*/
shadowJar {
//minimize()
append("plugin.yml")
relocate 'com.dfsek.paralithic', 'com.volmit.iris.util.paralithic'
relocate 'io.papermc.lib', 'com.volmit.iris.util.paper'
relocate 'net.kyori', 'com.volmit.iris.util.kyori'
dependencies {
include(dependency('io.papermc:paperlib'))
include(dependency('com.dfsek:Paralithic'))
include(dependency('net.kyori:'))
}
}
configurations.all {
resolutionStrategy.cacheChangingModulesFor 60, 'minutes'
resolutionStrategy.cacheDynamicVersionsFor 60, 'minutes'
}
/**
* Dependencies.
*
* Provided or classpath dependencies are not shaded and are available on the runtime classpath
*
* Shaded dependencies are not available at runtime, nor are they available on mvn central so they
* need to be shaded into the jar (increasing binary size)
*
* Dynamically loaded dependencies are defined in the plugin.yml (updating these must be updated in the
* plugin.yml also, otherwise they wont be available). These do not increase binary size). Only declare
* these dependencies if they are available on mvn central.
*/
dependencies {
// Provided or Classpath
compileOnly 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
implementation 'org.spigotmc:spigot-api:1.19-R0.1-SNAPSHOT'
implementation 'me.clip:placeholderapi:2.11.1'
implementation 'io.th0rgal:oraxen:1.94.0'
implementation 'org.bukkit:craftbukkit:1.19-R0.1-SNAPSHOT:remapped-mojang'
implementation 'com.github.LoneDev6:api-itemsadder:3.1.0b'
// Shaded
implementation 'com.dfsek:Paralithic:0.4.0'
implementation 'io.papermc:paperlib:1.0.5'
implementation "net.kyori:adventure-text-minimessage:4.11.0"
implementation 'net.kyori:adventure-platform-bukkit:4.1.0'
implementation 'net.kyori:adventure-api:4.11.0'
// Dynamically Loaded
implementation 'io.timeandspace:smoothie-map:2.0.2'
implementation 'it.unimi.dsi:fastutil:8.5.8'
implementation 'com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2'
implementation 'org.zeroturnaround:zt-zip:1.14'
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'org.ow2.asm:asm:9.2'
implementation 'com.google.guava:guava:31.1-jre'
implementation 'bsf:bsf:2.4.0'
implementation 'rhino:js:1.7R2'
implementation 'com.github.ben-manes.caffeine:caffeine:3.0.6'
implementation 'org.apache.commons:commons-lang3:3.12.0'
}
if (JavaVersion.current().toString() != "17") {
System.err.println()
System.err.println("=========================================================================================================")
System.err.println("You must run gradle on Java 17. You are using " + JavaVersion.current())
System.err.println()
System.err.println("=== For IDEs ===")
System.err.println("1. Configure the project for Java 17")
System.err.println("2. Configure the bundled gradle to use Java 17 in settings")
System.err.println()
System.err.println("=== For Command Line (gradlew) ===")
System.err.println("1. Install JDK 17 from https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html")
System.err.println("2. Set JAVA_HOME environment variable to the new jdk installation folder such as C:\\Program Files\\Java\\jdk-17.0.1")
System.err.println("3. Open a new command prompt window to get the new environment variables if need be.")
System.err.println("=========================================================================================================")
System.err.println()
System.exit(69);
}
def buildToolsJar = new File(buildDir, "buildtools/BuildTools.jar");
def specialSourceJar = new File(buildDir, "specialsource/SpecialSource.jar");
def buildToolsFolder = new File(buildDir, "buildtools");
def specialSourceFolder = new File(buildDir, "specialsource");
def buildToolsHint = new File(buildDir, "buildtools/craftbukkit-" + nmsVersion + ".jar");
def outputShadeJar = new File(buildDir, "libs/Iris-" + version + "-all.jar");
def ssiJar = new File(buildDir, "specialsource/Iris-" + version + "-all.jar");
def ssobfJar = new File(buildDir, "specialsource/Iris-" + version + "-rmo.jar");
def ssJar = new File(buildDir, "specialsource/Iris-" + version + "-rma.jar");
def homePath = System.properties['user.home']
def m2 = new File(homePath + "/.m2/repository")
def m2s = m2.getAbsolutePath();
// ======================== Building Mapped Jars =============================
task downloadBuildtools(type: Download) {
group "remapping"
src 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar'
dest buildToolsJar
onlyIf {
!buildToolsJar.exists()
}
}
task downloadSpecialSource(type: Download) {
group "remapping"
src 'https://repo.maven.apache.org/maven2/net/md-5/SpecialSource/1.10.0/SpecialSource-1.10.0-shaded.jar'
dest specialSourceJar
onlyIf {
!specialSourceJar.exists()
}
}
task executeBuildTools(dependsOn: downloadBuildtools, type: JavaExec)
{
group "remapping"
classpath = files(buildToolsJar)
workingDir = buildToolsFolder
args = [
"--rev",
nmsVersion,
"--compile",
"craftbukkit",
"--remap"
]
onlyIf {
!buildToolsHint.exists()
}
}
task copyBuildToSpecialSource(type: Copy)
{
group "remapping"
from outputShadeJar
into specialSourceFolder
dependsOn(downloadSpecialSource, shadowJar)
}
task specialSourceRemapObfuscate(type: JavaExec)
{
group "remapping"
dependsOn(copyBuildToSpecialSource, downloadSpecialSource, shadowJar)
workingDir = specialSourceFolder
classpath = files(specialSourceJar,
new File(m2s + "/org/spigotmc/spigot/" + spigotJarVersion + "/spigot-" + spigotJarVersion + "-remapped-mojang.jar"))
mainClass = "net.md_5.specialsource.SpecialSource"
args = [
"--live",
"-i",
ssiJar.getName(),
"-o",
ssobfJar.getName(),
"-m",
m2s + "/org/spigotmc/minecraft-server/" + spigotJarVersion + "/minecraft-server-" + spigotJarVersion + "-maps-mojang.txt",
"--reverse",
]
}
task specialSourceRemap(type: JavaExec)
{
group "remapping"
dependsOn(specialSourceRemapObfuscate)
workingDir = specialSourceFolder
classpath = files(specialSourceJar,
new File(m2s + "/org/spigotmc/spigot/" + spigotJarVersion + "/spigot-" + spigotJarVersion + "-remapped-obf.jar"))
mainClass = "net.md_5.specialsource.SpecialSource"
args = [
"--live",
"-i",
ssobfJar.getName(),
"-o",
ssJar.getName(),
"-m",
m2s + "/org/spigotmc/minecraft-server/" + spigotJarVersion + "/minecraft-server-" + spigotJarVersion + "-maps-spigot.csrg"
]
}
tasks.compileJava.dependsOn(executeBuildTools)
compileJava {
options.encoding = "UTF-8"
}
task setup()
{
group("iris")
dependsOn(clean, executeBuildTools)
}
task iris(type: Copy)
{
group "iris"
from ssJar
into buildDir
rename { String fileName ->
fileName.replace('Iris-' + version + '-rma.jar', "Iris-" + version + ".jar")
}
dependsOn(specialSourceRemap)
}
def registerCustomOutputTask(name, path) {
if (!System.properties['os.name'].toLowerCase().contains('windows')) {
return;
}
tasks.register('build' + name, Copy) {
group('development')
outputs.upToDateWhen { false }
dependsOn(iris)
from(new File(buildDir, "Iris-" + version + ".jar"))
into(file(path))
rename { String fileName ->
fileName.replace("Iris-" + version + ".jar", "Iris.jar")
}
}
}
def registerCustomOutputTaskUnix(name, path) {
if (System.properties['os.name'].toLowerCase().contains('windows')) {
return;
}
tasks.register('build' + name, Copy) {
group('development')
outputs.upToDateWhen { false }
dependsOn(iris)
from(new File(buildDir, "Iris-" + version + ".jar"))
into(file(path))
rename { String fileName ->
fileName.replace("Iris-" + version + ".jar", "Iris.jar")
}
}
}

View File

@ -1,22 +0,0 @@
#
# Iris is a World Generator for Minecraft Bukkit Servers
# Copyright (c) 2022 Arcane Arts (Volmit Software)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx3072m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.caching=true
org.gradle.configureondemand=false

Binary file not shown.

View File

@ -1,5 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

234
gradlew vendored
View File

@ -1,234 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

89
gradlew.bat vendored
View File

@ -1,89 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

View File

@ -1,10 +0,0 @@
[
"overworld IrisDimensions/overworld",
"vanilla IrisDimensions/vanilla",
"flat IrisDimensions/flat",
"redstone IrisDimensions/redstone",
"mars IrisDimensions/mars",
"example IrisDimensions/example"
"newhorizons IrisDimensions/newhorizons",
"theend IrisDimensions/theend"
]

View File

@ -1,2 +0,0 @@
# This file is generated by the 'io.freefair.lombok' Gradle plugin
config.stopBubbling = true

View File

@ -1,21 +0,0 @@
name: ${name}
version: ${version}
main: ${main}
load: STARTUP
authors: [ cyberpwn, NextdoorPsycho ]
website: volmit.com
description: More than a Dimension!
libraries:
- org.zeroturnaround:zt-zip:1.14
- com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2
- org.ow2.asm:asm:9.2
- com.google.code.gson:gson:2.8.7
- it.unimi.dsi:fastutil:8.5.4
- com.google.guava:guava:30.1.1-jre
- bsf:bsf:2.4.0
- rhino:js:1.7R2
commands:
iris:
aliases: [ ir, irs ]
api-version: ${apiversion}
hotload-dependencies: false

View File

@ -1,3 +0,0 @@
.DS_Store
*.code-workspace
*.txt

View File

@ -1,26 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2021 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pluginManagement {
repositories {
mavenLocal()
mavenCentral()
gradlePluginPortal()
maven { url "https://dl.cloudsmith.io/public/arcane/archive/maven/" }
}
}
rootProject.name = 'Iris'

View File

@ -1,729 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.link.*;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.EnginePanic;
import com.volmit.iris.engine.object.IrisCompat;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisWorld;
import com.volmit.iris.engine.platform.BukkitChunkGenerator;
import com.volmit.iris.engine.platform.DummyChunkGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.exceptions.IrisException;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.function.NastyRunnable;
import com.volmit.iris.util.io.*;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.Metrics;
import com.volmit.iris.util.plugin.VolmitPlugin;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.reflect.ShadeFix;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Queue;
import com.volmit.iris.util.scheduling.ShurikenQueue;
import io.papermc.lib.PaperLib;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.serializer.ComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.block.data.BlockData;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.IllegalPluginAccessException;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
@SuppressWarnings("CanBeFinal")
public class Iris extends VolmitPlugin implements Listener {
private static final Queue<Runnable> syncJobs = new ShurikenQueue<>();
public static Iris instance;
public static BukkitAudiences audiences;
public static MultiverseCoreLink linkMultiverseCore;
public static MythicMobsLink linkMythicMobs;
public static IrisCompat compat;
public static FileWatcher configWatcher;
private static VolmitSender sender;
static {
try {
fixShading();
InstanceState.updateInstanceId();
} catch(Throwable ignored) {
}
}
private final KList<Runnable> postShutdown = new KList<>();
private KMap<Class<? extends IrisService>, IrisService> services;
public static VolmitSender getSender() {
return sender;
}
@SuppressWarnings("unchecked")
public static <T> T service(Class<T> c) {
return (T) instance.services.get(c);
}
public static void callEvent(Event e) {
if(!e.isAsynchronous()) {
J.s(() -> Bukkit.getPluginManager().callEvent(e));
} else {
Bukkit.getPluginManager().callEvent(e);
}
}
public static KList<Object> initialize(String s, Class<? extends Annotation> slicedClass) {
JarScanner js = new JarScanner(instance.getJarFile(), s);
KList<Object> v = new KList<>();
J.attempt(js::scan);
for(Class<?> i : js.getClasses()) {
if(slicedClass == null || i.isAnnotationPresent(slicedClass)) {
try {
v.add(i.getDeclaredConstructor().newInstance());
} catch(Throwable ignored) {
}
}
}
return v;
}
public static KList<Class<?>> getClasses(String s, Class<? extends Annotation> slicedClass) {
JarScanner js = new JarScanner(instance.getJarFile(), s);
KList<Class<?>> v = new KList<>();
J.attempt(js::scan);
for(Class<?> i : js.getClasses()) {
if(slicedClass == null || i.isAnnotationPresent(slicedClass)) {
try {
v.add(i);
} catch(Throwable ignored) {
}
}
}
return v;
}
public static KList<Object> initialize(String s) {
return initialize(s, null);
}
public static void sq(Runnable r) {
synchronized(syncJobs) {
syncJobs.queue(r);
}
}
public static File getTemp() {
return instance.getDataFolder("cache", "temp");
}
public static void msg(String string) {
try {
sender.sendMessage(string);
} catch(Throwable e) {
try {
System.out.println(instance.getTag() + string.replaceAll("(<([^>]+)>)", ""));
} catch(Throwable ignored1) {
}
}
}
public static File getCached(String name, String url) {
String h = IO.hash(name + "@" + url);
File f = Iris.instance.getDataFile("cache", h.substring(0, 2), h.substring(3, 5), h);
if(!f.exists()) {
try(BufferedInputStream in = new BufferedInputStream(new URL(url).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) {
byte[] dataBuffer = new byte[1024];
int bytesRead;
while((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
Iris.verbose("Aquiring " + name);
}
} catch(IOException e) {
Iris.reportError(e);
}
}
return f.exists() ? f : null;
}
public static String getNonCached(String name, String url) {
String h = IO.hash(name + "*" + url);
File f = Iris.instance.getDataFile("cache", h.substring(0, 2), h.substring(3, 5), h);
try(BufferedInputStream in = new BufferedInputStream(new URL(url).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) {
byte[] dataBuffer = new byte[1024];
int bytesRead;
while((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
}
} catch(IOException e) {
Iris.reportError(e);
}
try {
return IO.readAll(f);
} catch(IOException e) {
Iris.reportError(e);
}
return "";
}
public static File getNonCachedFile(String name, String url) {
String h = IO.hash(name + "*" + url);
File f = Iris.instance.getDataFile("cache", h.substring(0, 2), h.substring(3, 5), h);
Iris.verbose("Download " + name + " -> " + url);
try(BufferedInputStream in = new BufferedInputStream(new URL(url).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) {
byte[] dataBuffer = new byte[1024];
int bytesRead;
while((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
}
fileOutputStream.flush();
} catch(IOException e) {
e.printStackTrace();
Iris.reportError(e);
}
return f;
}
public static void warn(String format, Object... objs) {
msg(C.YELLOW + String.format(format, objs));
}
public static void error(String format, Object... objs) {
msg(C.RED + String.format(format, objs));
}
public static void debug(String string) {
if(!IrisSettings.get().getGeneral().isDebug()) {
return;
}
try {
throw new RuntimeException();
} catch(Throwable e) {
try {
String[] cc = e.getStackTrace()[1].getClassName().split("\\Q.\\E");
if(cc.length > 5) {
debug(cc[3] + "/" + cc[4] + "/" + cc[cc.length - 1], e.getStackTrace()[1].getLineNumber(), string);
} else {
debug(cc[3] + "/" + cc[4], e.getStackTrace()[1].getLineNumber(), string);
}
} catch(Throwable ex) {
debug("Origin", -1, string);
}
}
}
public static void debug(String category, int line, String string) {
if(!IrisSettings.get().getGeneral().isDebug()) {
return;
}
if(IrisSettings.get().getGeneral().isUseConsoleCustomColors()) {
msg("<gradient:#095fe0:#a848db>" + category + " <#bf3b76>" + line + "<reset> " + C.LIGHT_PURPLE + string.replaceAll("\\Q<\\E", "[").replaceAll("\\Q>\\E", "]"));
} else {
msg(C.BLUE + category + ":" + C.AQUA + line + C.RESET + C.LIGHT_PURPLE + " " + string.replaceAll("\\Q<\\E", "[").replaceAll("\\Q>\\E", "]"));
}
}
public static void verbose(String string) {
debug(string);
}
public static void success(String string) {
msg(C.IRIS + string);
}
public static void info(String string) {
msg(C.WHITE + string);
}
@SuppressWarnings("deprecation")
public static void later(NastyRunnable object) {
try {
Bukkit.getScheduler().scheduleAsyncDelayedTask(instance, () ->
{
try {
object.run();
} catch(Throwable e) {
e.printStackTrace();
Iris.reportError(e);
}
}, RNG.r.i(100, 1200));
} catch(IllegalPluginAccessException ignored) {
}
}
public static int jobCount() {
return syncJobs.size();
}
public static void clearQueues() {
synchronized(syncJobs) {
syncJobs.clear();
}
}
private static int getJavaVersion() {
String version = System.getProperty("java.version");
if(version.startsWith("1.")) {
version = version.substring(2, 3);
} else {
int dot = version.indexOf(".");
if(dot != -1) {
version = version.substring(0, dot);
}
}
return Integer.parseInt(version);
}
public static void reportErrorChunk(int x, int z, Throwable e, String extra) {
if(IrisSettings.get().getGeneral().isDebug()) {
File f = instance.getDataFile("debug", "chunk-errors", "chunk." + x + "." + z + ".txt");
if(!f.exists()) {
J.attempt(() -> {
PrintWriter pw = new PrintWriter(f);
pw.println("Thread: " + Thread.currentThread().getName());
pw.println("First: " + new Date(M.ms()));
e.printStackTrace(pw);
pw.close();
});
}
Iris.debug("Chunk " + x + "," + z + " Exception Logged: " + e.getClass().getSimpleName() + ": " + C.RESET + "" + C.LIGHT_PURPLE + e.getMessage());
}
}
public static void reportError(Throwable e) {
if(IrisSettings.get().getGeneral().isDebug()) {
String n = e.getClass().getCanonicalName() + "-" + e.getStackTrace()[0].getClassName() + "-" + e.getStackTrace()[0].getLineNumber();
if(e.getCause() != null) {
n += "-" + e.getCause().getStackTrace()[0].getClassName() + "-" + e.getCause().getStackTrace()[0].getLineNumber();
}
File f = instance.getDataFile("debug", "caught-exceptions", n + ".txt");
if(!f.exists()) {
J.attempt(() -> {
PrintWriter pw = new PrintWriter(f);
pw.println("Thread: " + Thread.currentThread().getName());
pw.println("First: " + new Date(M.ms()));
e.printStackTrace(pw);
pw.close();
});
}
Iris.debug("Exception Logged: " + e.getClass().getSimpleName() + ": " + C.RESET + "" + C.LIGHT_PURPLE + e.getMessage());
}
}
private void enable() {
instance = this;
services = new KMap<>();
initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class<? extends IrisService>) i.getClass(), (IrisService) i));
INMS.get();
IO.delete(new File("iris"));
setupAudience();
sender = new VolmitSender(Bukkit.getConsoleSender());
sender.setTag(getTag());
instance = this;
compat = IrisCompat.configured(getDataFile("compat.json"));
linkMultiverseCore = new MultiverseCoreLink();
linkMythicMobs = new MythicMobsLink();
configWatcher = new FileWatcher(getDataFile("settings.json"));
services.values().forEach(IrisService::onEnable);
services.values().forEach(this::registerListener);
J.s(() -> {
J.a(() -> PaperLib.suggestPaper(this));
J.a(() -> IO.delete(getTemp()));
J.a(this::bstats);
J.ar(this::checkConfigHotload, 60);
J.sr(this::tickQueue, 0);
J.s(this::setupPapi);
J.a(ServerConfigurator::configure, 20);
splash();
autoStartStudio();
checkForBukkitWorlds();
IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName());
IrisToolbelt.retainMantleDataForSlice(BlockData.class.getCanonicalName());
});
}
private void checkForBukkitWorlds() {
FileConfiguration fc = new YamlConfiguration();
try {
fc.load(new File("bukkit.yml"));
searching: for(String i : fc.getKeys(true))
{
if(i.startsWith("worlds.") && i.endsWith(".generator")) {
String worldName = i.split("\\Q.\\E")[1];
String generator = IrisSettings.get().getGenerator().getDefaultWorldType();
if(fc.getString(i).startsWith("Iris:")) {
generator = fc.getString(i).split("\\Q:\\E")[1];
} else if(fc.getString(i).equals("Iris")) {
generator = IrisSettings.get().getGenerator().getDefaultWorldType();
} else {
continue;
}
for(World j : Bukkit.getWorlds())
{
if(j.getName().equals(worldName))
{
continue searching;
}
}
Iris.warn("Detected an Iris World in the bukkit yml '" + worldName + "' using Iris that was not loaded by bukkit. Good Guy Iris will load it up for you!");
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + worldName + "' using Iris:" + generator);
World world = new WorldCreator(worldName)
.generator(getDefaultWorldGenerator(worldName, generator))
.environment(IrisData.loadAnyDimension(generator).getEnvironment())
.createWorld();
Iris.info(C.LIGHT_PURPLE + "Loaded " + worldName + "!");
}
}
} catch(Throwable e) {
e.printStackTrace();
}
}
private void autoStartStudio() {
if(IrisSettings.get().getStudio().isAutoStartDefaultStudio()) {
Iris.info("Starting up auto Studio!");
try {
Player r = new KList<>(getServer().getOnlinePlayers()).getRandom();
Iris.service(StudioSVC.class).open(r != null ? new VolmitSender(r) : sender, 1337, IrisSettings.get().getGenerator().getDefaultWorldType(), (w) -> {
J.s(() -> {
for(Player i : getServer().getOnlinePlayers()) {
i.setGameMode(GameMode.SPECTATOR);
i.teleport(new Location(w, 0, 200, 0));
}
});
});
} catch(IrisException e) {
e.printStackTrace();
}
}
}
private void setupAudience() {
try {
audiences = BukkitAudiences.create(this);
} catch(Throwable e) {
e.printStackTrace();
IrisSettings.get().getGeneral().setUseConsoleCustomColors(false);
IrisSettings.get().getGeneral().setUseCustomColorsIngame(false);
Iris.error("Failed to setup Adventure API... No custom colors :(");
}
}
public static void dump() {
try {
File fi = Iris.instance.getDataFile("dump", "td-" + new java.sql.Date(M.ms()) + ".txt");
FileOutputStream fos = new FileOutputStream(fi);
Map<Thread, StackTraceElement[]> f = Thread.getAllStackTraces();
PrintWriter pw = new PrintWriter(fos);
for(Thread i : f.keySet()) {
pw.println("========================================");
pw.println("Thread: '" + i.getName() + "' ID: " + i.getId() + " STATUS: " + i.getState().name());
for(StackTraceElement j : f.get(i)) {
pw.println(" @ " + j.toString());
}
pw.println("========================================");
pw.println();
pw.println();
}
pw.close();
System.out.println("DUMPED! See " + fi.getAbsolutePath());
} catch(Throwable e) {
e.printStackTrace();
}
}
public void postShutdown(Runnable r) {
postShutdown.add(r);
}
public static void panic() {
EnginePanic.panic();
}
public static void addPanic(String s, String v) {
EnginePanic.add(s, v);
}
public void onEnable() {
enable();
super.onEnable();
Bukkit.getPluginManager().registerEvents(this, this);
}
public void onDisable() {
services.values().forEach(IrisService::onDisable);
Bukkit.getScheduler().cancelTasks(this);
HandlerList.unregisterAll((Plugin) this);
postShutdown.forEach(Runnable::run);
services.clear();
MultiBurst.burst.close();
super.onDisable();
}
private static void fixShading() {
ShadeFix.fix(ComponentSerializer.class);
}
private void setupPapi() {
if(Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
new IrisPapiExpansion().register();
}
}
@Override
public void start() {
}
@Override
public void stop() {
}
@Override
public String getTag(String subTag) {
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.IRIS + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
}
private void checkConfigHotload() {
if(configWatcher.checkModified()) {
IrisSettings.invalidate();
IrisSettings.get();
configWatcher.checkModified();
Iris.info("Hotloaded settings.json ");
}
}
private void tickQueue() {
synchronized(Iris.syncJobs) {
if(!Iris.syncJobs.hasNext()) {
return;
}
long ms = M.ms();
while(Iris.syncJobs.hasNext() && M.ms() - ms < 25) {
try {
Iris.syncJobs.next().run();
} catch(Throwable e) {
e.printStackTrace();
Iris.reportError(e);
}
}
}
}
private void bstats() {
if(IrisSettings.get().getGeneral().isPluginMetrics()) {
J.s(() -> new Metrics(Iris.instance, 8757));
}
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
return super.onCommand(sender, command, label, args);
}
public void imsg(CommandSender s, String msg) {
s.sendMessage(C.IRIS + "[" + C.DARK_GRAY + "Iris" + C.IRIS + "]" + C.GRAY + ": " + msg);
}
@Nullable
@Override
public BiomeProvider getDefaultBiomeProvider(@NotNull String worldName, @Nullable String id) {
Iris.debug("Biome Provider Called for " + worldName + " using ID: " + id);
return super.getDefaultBiomeProvider(worldName, id);
}
@Override
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
Iris.debug("Default World Generator Called for " + worldName + " using ID: " + id);
if(worldName.equals("test")) {
try {
throw new RuntimeException();
} catch(Throwable e) {
Iris.info(e.getStackTrace()[1].getClassName());
if(e.getStackTrace()[1].getClassName().contains("com.onarandombox.MultiverseCore")) {
Iris.debug("MVC Test detected, Quick! Send them the dummy!");
return new DummyChunkGenerator();
}
}
}
IrisDimension dim;
if(id == null || id.isEmpty()) {
dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType());
} else {
dim = IrisData.loadAnyDimension(id);
}
Iris.debug("Generator ID: " + id + " requested by bukkit/plugin");
if(dim == null) {
Iris.warn("Unable to find dimension type " + id + " Looking for online packs...");
service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, true);
dim = IrisData.loadAnyDimension(id);
if(dim == null) {
throw new RuntimeException("Can't find dimension " + id + "!");
} else {
Iris.info("Resolved missing dimension, proceeding with generation.");
}
}
Iris.debug("Assuming IrisDimension: " + dim.getName());
IrisWorld w = IrisWorld.builder()
.name(worldName)
.seed(1337)
.environment(dim.getEnvironment())
.worldFolder(new File(worldName))
.minHeight(dim.getMinHeight())
.maxHeight(dim.getMaxHeight())
.build();
Iris.debug("Generator Config: " + w.toString());
File ff = new File(w.worldFolder(), "iris/pack");
if(!ff.exists() || ff.listFiles().length == 0) {
ff.mkdirs();
service(StudioSVC.class).installIntoWorld(sender, dim.getLoadKey(), ff.getParentFile());
}
return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey());
}
public void splash() {
if(!IrisSettings.get().getGeneral().isSplashLogoStartup()) {
return;
}
// @NoArgsConstructor
String padd = Form.repeat(" ", 8);
String padd2 = Form.repeat(" ", 4);
String[] info = {"", "", "", "", "", padd2 + C.IRIS + " Iris", padd2 + C.GRAY + " by " + "<rainbow>Volmit Software", padd2 + C.GRAY + " v" + C.IRIS + getDescription().getVersion(),
};
String[] splash = {
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.IRIS + " .(((()))). ",
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.IRIS + " .((((((())))))). ",
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.IRIS + " ((((((((())))))))) " + C.GRAY + " @",
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.IRIS + " ((((((((-))))))))) " + C.GRAY + " @@",
padd + C.GRAY + "@@@&&" + C.IRIS + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
padd + C.GRAY + "@@" + C.IRIS + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
padd + C.GRAY + "@" + C.IRIS + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
padd + C.GRAY + "" + C.IRIS + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
padd + C.GRAY + "" + C.IRIS + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
};
//@done
Iris.info("Server type & version: " + Bukkit.getVersion());
Iris.info("Bukkit version: " + Bukkit.getBukkitVersion());
Iris.info("Java version: " + getJavaVersion());
Iris.info("Custom Biomes: " + INMS.get().countCustomBiomes());
printPacks();
for(int i = 0; i < info.length; i++) {
splash[i] += info[i];
}
Iris.info("\n\n " + new KList<>(splash).toString("\n") + "\n");
}
private void printPacks() {
File packFolder = Iris.service(StudioSVC.class).getWorkspaceFolder();
File[] packs = packFolder.listFiles(File::isDirectory);
if(packs == null || packs.length == 0)
return;
Iris.info("Custom Dimensions: " + packs.length);
for(File f : packs)
printPack(f);
}
private void printPack(File pack) {
String dimName = pack.getName();
String version = "???";
try(FileReader r = new FileReader(new File(pack, "dimensions/" + dimName + ".json"))) {
JsonObject json = JsonParser.parseReader(r).getAsJsonObject();
if(json.has("version"))
version = json.get("version").getAsString();
} catch(IOException | JsonParseException ignored) { }
Iris.info(" " + dimName + " v" + version);
}
}

View File

@ -1,186 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core;
import com.google.gson.Gson;
import com.volmit.iris.Iris;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONException;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.plugin.VolmitSender;
import lombok.Data;
import java.io.File;
import java.io.IOException;
@SuppressWarnings("SynchronizeOnNonFinalField")
@Data
public class IrisSettings {
public static IrisSettings settings;
private IrisSettingsGeneral general = new IrisSettingsGeneral();
private IrisSettingsWorld world = new IrisSettingsWorld();
private IrisSettingsGUI gui = new IrisSettingsGUI();
private IrisSettingsAutoconfiguration autoConfiguration = new IrisSettingsAutoconfiguration();
private IrisSettingsGenerator generator = new IrisSettingsGenerator();
private IrisSettingsConcurrency concurrency = new IrisSettingsConcurrency();
private IrisSettingsStudio studio = new IrisSettingsStudio();
private IrisSettingsPerformance performance = new IrisSettingsPerformance();
public static int getThreadCount(int c) {
return switch(c) {
case -1, -2, -4 -> Runtime.getRuntime().availableProcessors() / -c;
case 0, 1, 2 -> 1;
default -> Math.max(c, 2);
};
}
@Data
public static class IrisSettingsAutoconfiguration {
public boolean configureSpigotTimeoutTime = true;
public boolean configurePaperWatchdogDelay = true;
public boolean autoRestartOnCustomBiomeInstall = true;
}
@Data
public static class IrisAsyncTeleport {
public boolean enabled = false;
public int loadViewDistance = 2;
public boolean urgent = false;
}
@Data
public static class IrisSettingsWorld {
public IrisAsyncTeleport asyncTeleport = new IrisAsyncTeleport();
public boolean postLoadBlockUpdates = true;
public boolean forcePersistEntities = true;
public boolean anbientEntitySpawningSystem = true;
public long asyncTickIntervalMS = 700;
public double targetSpawnEntitiesPerChunk = 0.95;
public boolean markerEntitySpawningSystem = true;
public boolean effectSystem = true;
public boolean worldEditWandCUI = true;
}
@Data
public static class IrisSettingsConcurrency {
public int parallelism = -1;
}
@Data
public static class IrisSettingsPerformance {
public boolean trimMantleInStudio = false;
public int mantleKeepAlive = 30;
public int cacheSize = 4_096;
public int resourceLoaderCacheSize = 1_024;
public int objectLoaderCacheSize = 4_096;
public int scriptLoaderCacheSize = 512;
}
@Data
public static class IrisSettingsGeneral {
public boolean commandSounds = true;
public boolean debug = false;
public boolean disableNMS = false;
public boolean pluginMetrics = true;
public boolean splashLogoStartup = true;
public boolean useConsoleCustomColors = true;
public boolean useCustomColorsIngame = true;
public String forceMainWorld = "";
public int spinh = -20;
public int spins = 7;
public int spinb = 8;
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean canUseCustomColors(VolmitSender volmitSender) {
return volmitSender.isPlayer() ? useCustomColorsIngame : useConsoleCustomColors;
}
}
@Data
public static class IrisSettingsGUI {
public boolean useServerLaunchedGuis = true;
public boolean maximumPregenGuiFPS = false;
}
@Data
public static class IrisSettingsGenerator {
public String defaultWorldType = "overworld";
public int maxBiomeChildDepth = 4;
public boolean preventLeafDecay = true;
}
@Data
public static class IrisSettingsStudio {
public boolean studio = true;
public boolean openVSCode = true;
public boolean disableTimeAndWeather = true;
public boolean autoStartDefaultStudio = false;
}
public static IrisSettings get() {
if(settings != null) {
return settings;
}
settings = new IrisSettings();
File s = Iris.instance.getDataFile("settings.json");
if(!s.exists()) {
try {
IO.writeAll(s, new JSONObject(new Gson().toJson(settings)).toString(4));
} catch(JSONException | IOException e) {
e.printStackTrace();
Iris.reportError(e);
}
} else {
try {
String ss = IO.readAll(s);
settings = new Gson().fromJson(ss, IrisSettings.class);
try {
IO.writeAll(s, new JSONObject(new Gson().toJson(settings)).toString(4));
} catch(IOException e) {
e.printStackTrace();
}
} catch(Throwable ee) {
// Iris.reportError(ee); causes a self-reference & stackoverflow
Iris.error("Configuration Error in settings.json! " + ee.getClass().getSimpleName() + ": " + ee.getMessage());
}
}
return settings;
}
public static void invalidate() {
synchronized(settings) {
settings = null;
}
}
public void forceSave() {
File s = Iris.instance.getDataFile("settings.json");
try {
IO.writeAll(s, new JSONObject(new Gson().toJson(settings)).toString(4));
} catch(JSONException | IOException e) {
e.printStackTrace();
Iris.reportError(e);
}
}
}

View File

@ -1,270 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class ServerConfigurator {
public static void configure() {
IrisSettings.IrisSettingsAutoconfiguration s = IrisSettings.get().getAutoConfiguration();
if(s.isConfigureSpigotTimeoutTime()) {
J.attempt(ServerConfigurator::increaseKeepAliveSpigot);
}
if(s.isConfigurePaperWatchdogDelay()) {
J.attempt(ServerConfigurator::increasePaperWatchdog);
}
installDataPacks(true);
}
private static void increaseKeepAliveSpigot() throws IOException, InvalidConfigurationException {
File spigotConfig = new File("config/spigot.yml");
FileConfiguration f = new YamlConfiguration();
f.load(spigotConfig);
long tt = f.getLong("settings.timeout-time");
if(tt < TimeUnit.MINUTES.toSeconds(5)) {
Iris.warn("Updating spigot.yml timeout-time: " + tt + " -> " + TimeUnit.MINUTES.toSeconds(5) + " (5 minutes)");
Iris.warn("You can disable this change (autoconfigureServer) in Iris settings, then change back the value.");
f.set("settings.timeout-time", TimeUnit.MINUTES.toSeconds(5));
f.save(spigotConfig);
}
}
private static void increasePaperWatchdog() throws IOException, InvalidConfigurationException {
File spigotConfig = new File("config/paper-global.yml");
FileConfiguration f = new YamlConfiguration();
f.load(spigotConfig);
long tt = f.getLong("watchdog.early-warning-delay");
if(tt < TimeUnit.MINUTES.toMillis(3)) {
Iris.warn("Updating paper.yml watchdog early-warning-delay: " + tt + " -> " + TimeUnit.MINUTES.toMillis(3) + " (3 minutes)");
Iris.warn("You can disable this change (autoconfigureServer) in Iris settings, then change back the value.");
f.set("watchdog.early-warning-delay", TimeUnit.MINUTES.toMillis(3));
f.save(spigotConfig);
}
}
private static File getDatapacksFolder() {
if(!IrisSettings.get().getGeneral().forceMainWorld.isEmpty()) {
return new File(IrisSettings.get().getGeneral().forceMainWorld + "/datapacks");
}
File props = new File("server.properties");
if(props.exists()) {
try {
KList<String> m = new KList<>(IO.readAll(props).split("\\Q\n\\E"));
for(String i : m) {
if(i.trim().startsWith("level-name=")) {
return new File(i.trim().split("\\Q=\\E")[1] + "/datapacks");
}
}
} catch(IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
}
return null;
}
public static void installDataPacks(boolean fullInstall) {
Iris.info("Checking Data Packs...");
boolean reboot = false;
File packs = new File("plugins/Iris/packs");
File dpacks = getDatapacksFolder();
if(dpacks == null) {
Iris.error("Cannot find the datapacks folder! Please try generating a default world first maybe? Is this a new server?");
return;
}
if(packs.exists()) {
for(File i : packs.listFiles()) {
if(i.isDirectory()) {
Iris.verbose("Checking Pack: " + i.getPath());
IrisData data = IrisData.get(i);
File dims = new File(i, "dimensions");
if(dims.exists()) {
for(File j : dims.listFiles()) {
if(j.getName().endsWith(".json")) {
IrisDimension dim = data.getDimensionLoader().load(j.getName().split("\\Q.\\E")[0]);
if(dim == null) {
continue;
}
Iris.verbose(" Checking Dimension " + dim.getLoadFile().getPath());
if(dim.installDataPack(() -> data, dpacks)) {
reboot = true;
}
}
}
}
}
}
}
Iris.info("Data Packs Setup!");
if(fullInstall) {
verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall());
}
}
private static void verifyDataPacksPost(boolean allowRestarting) {
File packs = new File("plugins/Iris/packs");
File dpacks = getDatapacksFolder();
if(dpacks == null) {
Iris.error("Cannot find the datapacks folder! Please try generating a default world first maybe? Is this a new server?");
return;
}
boolean bad = false;
if(packs.exists()) {
for(File i : packs.listFiles()) {
if(i.isDirectory()) {
Iris.verbose("Checking Pack: " + i.getPath());
IrisData data = IrisData.get(i);
File dims = new File(i, "dimensions");
if(dims.exists()) {
for(File j : dims.listFiles()) {
if(j.getName().endsWith(".json")) {
IrisDimension dim = data.getDimensionLoader().load(j.getName().split("\\Q.\\E")[0]);
if(dim == null) {
Iris.error("Failed to load " + j.getPath() + " ");
continue;
}
if(!verifyDataPackInstalled(dim)) {
bad = true;
}
}
}
}
}
}
}
if(bad) {
if(allowRestarting) {
restart();
} else if(INMS.get().supportsDataPacks()) {
Iris.error("============================================================================");
Iris.error(C.ITALIC + "You need to restart your server to properly generate custom biomes.");
Iris.error(C.ITALIC + "By continuing, Iris will use backup biomes in place of the custom biomes.");
Iris.error("----------------------------------------------------------------------------");
Iris.error(C.UNDERLINE + "IT IS HIGHLY RECOMMENDED YOU RESTART THE SERVER BEFORE GENERATING!");
Iris.error("============================================================================");
for(Player i : Bukkit.getOnlinePlayers()) {
if(i.isOp() || i.hasPermission("iris.all")) {
VolmitSender sender = new VolmitSender(i, Iris.instance.getTag("WARNING"));
sender.sendMessage("There are some Iris Packs that have custom biomes in them");
sender.sendMessage("You need to restart your server to use these packs.");
}
}
J.sleep(3000);
}
}
}
public static void restart() {
J.s(() -> {
Iris.warn("New data pack entries have been installed in Iris! Restarting server!");
Iris.warn("This will only happen when your pack changes (updates/first time setup)");
Iris.warn("(You can disable this auto restart in iris settings)");
J.s(() -> {
Iris.warn("Looks like the restart command diddn't work. Stopping the server instead!");
Bukkit.shutdown();
}, 100);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart");
});
}
public static boolean verifyDataPackInstalled(IrisDimension dimension) {
IrisData idm = IrisData.get(Iris.instance.getDataFolder("packs", dimension.getLoadKey()));
KSet<String> keys = new KSet<>();
boolean warn = false;
for(IrisBiome i : dimension.getAllBiomes(() -> idm)) {
if(i.isCustom()) {
for(IrisBiomeCustom j : i.getCustomDerivitives()) {
keys.add(dimension.getLoadKey() + ":" + j.getId());
}
}
}
if(!INMS.get().supportsDataPacks()) {
if(!keys.isEmpty()) {
Iris.warn("===================================================================================");
Iris.warn("Pack " + dimension.getLoadKey() + " has " + keys.size() + " custom biome(s). ");
Iris.warn("Your server version does not yet support datapacks for iris.");
Iris.warn("The world will generate these biomes as backup biomes.");
Iris.warn("====================================================================================");
}
return true;
}
for(String i : keys) {
Object o = INMS.get().getCustomBiomeBaseFor(i);
if(o == null) {
Iris.warn("The Biome " + i + " is not registered on the server.");
warn = true;
}
}
if(warn) {
Iris.error("The Pack " + dimension.getLoadKey() + " is INCAPABLE of generating custom biomes");
Iris.error("If not done automatically, restart your server before generating with this pack!");
}
return !warn;
}
}

View File

@ -1,185 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisCave;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisJigsawPiece;
import com.volmit.iris.engine.object.IrisJigsawPool;
import com.volmit.iris.engine.object.IrisJigsawStructure;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C;
import java.awt.Desktop;
@Decree(name = "edit", origin = DecreeOrigin.PLAYER, studio = true, description = "Edit something")
public class CommandEdit implements DecreeExecutor {
private boolean noStudio() {
if(!sender().isPlayer()) {
sender().sendMessage(C.RED + "Players only!");
return true;
}
if(!Iris.service(StudioSVC.class).isProjectOpen()) {
sender().sendMessage(C.RED + "No studio world is open!");
return true;
}
if(!engine().isStudio()) {
sender().sendMessage(C.RED + "You must be in a studio world!");
return true;
}
return false;
}
@Decree(description = "Edit the biome you specified", aliases = {"b"}, origin = DecreeOrigin.PLAYER)
public void biome(@Param(contextual = false, description = "The biome to edit") IrisBiome biome) {
if(noStudio()) {
return;
}
try {
if(biome == null || biome.getLoadFile() == null) {
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
return;
}
Desktop.getDesktop().open(biome.getLoadFile());
sender().sendMessage(C.GREEN + "Opening " + biome.getTypeName() + " " + biome.getLoadFile().getName().split("\\Q.\\E")[0] + " in VSCode! ");
} catch(Throwable e) {
Iris.reportError(e);
sender().sendMessage(C.RED + "Cant find the file. Or registrant does not exist");
}
}
@Decree(description = "Edit the region you specified", aliases = {"r"}, origin = DecreeOrigin.PLAYER)
public void region(@Param(contextual = false, description = "The region to edit") IrisRegion region) {
if(noStudio()) {
return;
}
try {
if(region == null || region.getLoadFile() == null) {
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
return;
}
Desktop.getDesktop().open(region.getLoadFile());
sender().sendMessage(C.GREEN + "Opening " + region.getTypeName() + " " + region.getLoadFile().getName().split("\\Q.\\E")[0] + " in VSCode! ");
} catch(Throwable e) {
Iris.reportError(e);
sender().sendMessage(C.RED + "Cant find the file. Or registrant does not exist");
}
}
@Decree(description = "Edit the dimension you specified", aliases = {"d"}, origin = DecreeOrigin.PLAYER)
public void dimension(@Param(contextual = false, description = "The dimension to edit") IrisDimension dimension) {
if(noStudio()) {
return;
}
try {
if(dimension == null || dimension.getLoadFile() == null) {
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
return;
}
Desktop.getDesktop().open(dimension.getLoadFile());
sender().sendMessage(C.GREEN + "Opening " + dimension.getTypeName() + " " + dimension.getLoadFile().getName().split("\\Q.\\E")[0] + " in VSCode! ");
} catch(Throwable e) {
Iris.reportError(e);
sender().sendMessage(C.RED + "Cant find the file. Or registrant does not exist");
}
}
@Decree(description = "Edit the cave file you specified", aliases = {"c"}, origin = DecreeOrigin.PLAYER)
public void cave(@Param(contextual = false, description = "The cave to edit") IrisCave cave) {
if(noStudio()) {
return;
}
try {
if(cave == null || cave.getLoadFile() == null) {
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
return;
}
Desktop.getDesktop().open(cave.getLoadFile());
sender().sendMessage(C.GREEN + "Opening " + cave.getTypeName() + " " + cave.getLoadFile().getName().split("\\Q.\\E")[0] + " in VSCode! ");
} catch(Throwable e) {
Iris.reportError(e);
sender().sendMessage(C.RED + "Cant find the file. Or registrant does not exist");
}
}
@Decree(description = "Edit the structure file you specified", aliases = {"jigsawstructure", "structure"}, origin = DecreeOrigin.PLAYER)
public void jigsaw(@Param(contextual = false, description = "The jigsaw structure to edit") IrisJigsawStructure jigsaw) {
if(noStudio()) {
return;
}
try {
if(jigsaw == null || jigsaw.getLoadFile() == null) {
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
return;
}
Desktop.getDesktop().open(jigsaw.getLoadFile());
sender().sendMessage(C.GREEN + "Opening " + jigsaw.getTypeName() + " " + jigsaw.getLoadFile().getName().split("\\Q.\\E")[0] + " in VSCode! ");
} catch(Throwable e) {
Iris.reportError(e);
sender().sendMessage(C.RED + "Cant find the file. Or registrant does not exist");
}
}
@Decree(description = "Edit the pool file you specified", aliases = {"jigsawpool", "pool"}, origin = DecreeOrigin.PLAYER)
public void jigsawPool(@Param(contextual = false, description = "The jigsaw pool to edit") IrisJigsawPool pool) {
if(noStudio()) {
return;
}
try {
if(pool == null || pool.getLoadFile() == null) {
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
return;
}
Desktop.getDesktop().open(pool.getLoadFile());
sender().sendMessage(C.GREEN + "Opening " + pool.getTypeName() + " " + pool.getLoadFile().getName().split("\\Q.\\E")[0] + " in VSCode! ");
} catch(Throwable e) {
Iris.reportError(e);
sender().sendMessage(C.RED + "Cant find the file. Or registrant does not exist");
}
}
@Decree(description = "Edit the jigsaw piece file you specified", aliases = {"jigsawpiece", "piece"}, origin = DecreeOrigin.PLAYER)
public void jigsawPiece(@Param(contextual = false, description = "The jigsaw piece to edit") IrisJigsawPiece piece) {
if(noStudio()) {
return;
}
try {
if(piece == null || piece.getLoadFile() == null) {
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
return;
}
Desktop.getDesktop().open(piece.getLoadFile());
sender().sendMessage(C.GREEN + "Opening " + piece.getTypeName() + " " + piece.getLoadFile().getName().split("\\Q.\\E")[0] + " in VSCode! ");
} catch(Throwable e) {
Iris.reportError(e);
sender().sendMessage(C.RED + "Cant find the file. Or registrant does not exist");
}
}
}

View File

@ -1,93 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisJigsawStructure;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.decree.specialhandlers.ObjectHandler;
import com.volmit.iris.util.format.C;
@Decree(name = "find", origin = DecreeOrigin.PLAYER, description = "Iris Find commands", aliases = "goto")
public class CommandFind implements DecreeExecutor {
@Decree(description = "Find a biome")
public void biome(
@Param(description = "The biome to look for")
IrisBiome biome
) {
Engine e = engine();
if(e == null) {
sender().sendMessage(C.GOLD + "Not in an Iris World!");
return;
}
e.gotoBiome(biome, player());
}
@Decree(description = "Find a region")
public void region(
@Param(description = "The region to look for")
IrisRegion region
) {
Engine e = engine();
if(e == null) {
sender().sendMessage(C.GOLD + "Not in an Iris World!");
return;
}
e.gotoRegion(region, player());
}
@Decree(description = "Find a structure")
public void structure(
@Param(description = "The structure to look for")
IrisJigsawStructure structure
) {
Engine e = engine();
if(e == null) {
sender().sendMessage(C.GOLD + "Not in an Iris World!");
return;
}
e.gotoJigsaw(structure, player());
}
@Decree(description = "Find an object")
public void object(
@Param(description = "The object to look for", customHandler = ObjectHandler.class)
String object
) {
Engine e = engine();
if(e == null) {
sender().sendMessage(C.GOLD + "Not in an Iris World!");
return;
}
e.gotoObject(object, player());
}
}

View File

@ -1,301 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.decree.DecreeContext;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.jobs.QueueJob;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.io.File;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command")
public class CommandIris implements DecreeExecutor {
private CommandStudio studio;
private CommandPregen pregen;
private CommandSettings settings;
private CommandObject object;
private CommandJigsaw jigsaw;
private CommandWhat what;
private CommandEdit edit;
private CommandFind find;
@Decree(description = "Create a new world", aliases = {"+", "c"})
public void create(
@Param(aliases = "world-name", description = "The name of the world to create")
String name,
@Param(aliases = "dimension", description = "The dimension type to create the world with", defaultValue = "default")
IrisDimension type,
@Param(description = "The seed to generate the world with", defaultValue = "1337")
long seed
) {
if(name.equals("iris")) {
sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds.");
sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?");
return;
}
if(new File(name).exists()) {
sender().sendMessage(C.RED + "That folder already exists!");
return;
}
sender().sendMessage(C.RED + "You should not be using this command to create new worlds. Instead, use the tutorial: https://docs.volmit.com/iris/getting-started");
try {
IrisToolbelt.createWorld()
.dimension(type.getLoadKey())
.name(name)
.seed(seed)
.sender(sender())
.studio(false)
.create();
} catch(Throwable e) {
sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details.");
Iris.error("Exception raised during world creation: " + e.getMessage());
Iris.reportError(e);
return;
}
sender().sendMessage(C.GREEN + "Successfully created your world!");
}
@Decree(description = "Print version information")
public void version() {
sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software");
}
@Decree(description = "Print world height information", origin = DecreeOrigin.PLAYER)
public void height() {
sender().sendMessage(C.GREEN + "" + sender().player().getWorld().getMinHeight() + " to " + sender().player().getWorld().getMaxHeight());
sender().sendMessage(C.GREEN + "Total Height: " + (sender().player().getWorld().getMaxHeight() - sender().player().getWorld().getMinHeight()));
}
@Decree(description = "Set aura spins")
public void aura(
@Param(description = "The h color value", defaultValue = "-20")
int h,
@Param(description = "The s color value", defaultValue = "7")
int s,
@Param(description = "The b color value", defaultValue = "8")
int b
) {
IrisSettings.get().getGeneral().setSpinh(h);
IrisSettings.get().getGeneral().setSpins(s);
IrisSettings.get().getGeneral().setSpinb(b);
IrisSettings.get().forceSave();
sender().sendMessage("<rainbow>Aura Spins updated to " + h + " " + s + " " + b);
}
@Decree(description = "Bitwise calculations")
public void bitwise(
@Param(description = "The first value to run calculations on")
int value1,
@Param(description = "The operator: | & ^ ≺≺ ≻≻ ")
String operator,
@Param(description = "The second value to run calculations on")
int value2
) {
Integer v = null;
switch(operator) {
case "|" -> v = value1 | value2;
case "&" -> v = value1 & value2;
case "^" -> v = value1 ^ value2;
case "%" -> v = value1 % value2;
case ">>" -> v = value1 >> value2;
case "<<" -> v = value1 << value2;
}
if(v == null) {
sender().sendMessage(C.RED + "The operator you entered: (" + operator + ") is invalid!");
return;
}
sender().sendMessage(C.GREEN + "" + value1 + " " + C.GREEN + operator.replaceAll("<", "").replaceAll(">", "").replaceAll("%", "") + " " + C.GREEN + value2 + C.GREEN + " returns " + C.GREEN + v);
}
@Decree(description = "Toggle debug")
public void debug(
@Param(name = "on", description = "Whether or not debug should be on", defaultValue = "other")
Boolean on
) {
boolean to = on == null ? !IrisSettings.get().getGeneral().isDebug() : on;
IrisSettings.get().getGeneral().setDebug(to);
IrisSettings.get().forceSave();
sender().sendMessage(C.GREEN + "Set debug to: " + to);
}
@Decree(description = "Download a project.", aliases = "dl")
public void download(
@Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project")
String pack,
@Param(name = "branch", description = "The branch to download from", defaultValue = "main")
String branch,
@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false")
boolean trim,
@Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false")
boolean overwrite
) {
branch = pack.equals("overworld") ? "stable" : branch;
sender().sendMessage(C.GREEN + "Downloading pack: " + pack + "/" + branch + (trim ? " trimmed" : "") + (overwrite ? " overwriting" : ""));
Iris.service(StudioSVC.class).downloadSearch(sender(), "IrisDimensions/" + pack + "/" + branch, trim, overwrite);
}
@Decree(description = "Get metrics for your world", aliases = "measure", origin = DecreeOrigin.PLAYER)
public void metrics() {
if(!IrisToolbelt.isIrisWorld(world())) {
sender().sendMessage(C.RED + "You must be in an Iris world");
return;
}
sender().sendMessage(C.GREEN + "Sending metrics...");
engine().printMetrics(sender());
}
@Decree(description = "Reload configuration file (this is also done automatically)")
public void reload() {
IrisSettings.invalidate();
IrisSettings.get();
sender().sendMessage(C.GREEN + "Hotloaded settings");
}
@Decree(name = "regen", description = "Regenerate nearby chunks.", aliases = "rg", sync = true, origin = DecreeOrigin.PLAYER)
public void regen(
@Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5")
int radius
) {
if(IrisToolbelt.isIrisWorld(player().getWorld())) {
VolmitSender sender = sender();
J.a(() -> {
DecreeContext.touch(sender);
PlatformChunkGenerator plat = IrisToolbelt.access(player().getWorld());
Engine engine = plat.getEngine();
try {
Chunk cx = player().getLocation().getChunk();
KList<Runnable> js = new KList<>();
BurstExecutor b = MultiBurst.burst.burst();
b.setMulticore(false);
int rad = engine.getMantle().getRealRadius();
for(int i = -(radius + rad); i <= radius + rad; i++) {
for(int j = -(radius + rad); j <= radius + rad; j++) {
engine.getMantle().getMantle().deleteChunk(i + cx.getX(), j + cx.getZ());
}
}
for(int i = -radius; i <= radius; i++) {
for(int j = -radius; j <= radius; j++) {
int finalJ = j;
int finalI = i;
b.queue(() -> plat.injectChunkReplacement(player().getWorld(), finalI + cx.getX(), finalJ + cx.getZ(), (f) -> {
synchronized(js) {
js.add(f);
}
}));
}
}
b.complete();
sender().sendMessage(C.GREEN + "Regenerating " + Form.f(js.size()) + " Sections");
QueueJob<Runnable> r = new QueueJob<>() {
final KList<Future<?>> futures = new KList<>();
@Override
public void execute(Runnable runnable) {
futures.add(J.sfut(runnable));
if(futures.size() > 64) {
while(futures.isNotEmpty()) {
try {
futures.remove(0).get();
} catch(InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
@Override
public String getName() {
return "Regenerating";
}
};
r.queue(js);
r.execute(sender());
} catch(Throwable e) {
sender().sendMessage("Unable to parse view-distance");
}
});
} else {
sender().sendMessage(C.RED + "You must be in an Iris World to use regen!");
}
}
@Decree(description = "Update the pack of a world (UNSAFE!)", name = "^world", aliases = "update-world")
public void updateWorld(
@Param(description = "The world to update", contextual = true)
World world,
@Param(description = "The pack to install into the world", contextual = true, aliases = "dimension")
IrisDimension pack,
@Param(description = "Make sure to make a backup & read the warnings first!", defaultValue = "false", aliases = "c")
boolean confirm,
@Param(description = "Should Iris download the pack again for you", defaultValue = "false", name = "fresh-download", aliases = {"fresh", "new"})
boolean freshDownload
) {
if(!confirm) {
sender().sendMessage(new String[] {
C.RED + "You should always make a backup before using this",
C.YELLOW + "Issues caused by this can be, but are not limited to:",
C.YELLOW + " - Broken chunks (cut-offs) between old and new chunks (before & after the update)",
C.YELLOW + " - Regenerated chunks that do not fit in with the old chunks",
C.YELLOW + " - Structures not spawning again when regenerating",
C.YELLOW + " - Caves not lining up",
C.YELLOW + " - Terrain layers not lining up",
C.RED + "Now that you are aware of the risks, and have made a back-up:",
C.RED + "/iris ^world <world> <pack> confirm=true"
});
return;
}
File folder = world.getWorldFolder();
folder.mkdirs();
if(freshDownload) {
Iris.service(StudioSVC.class).downloadSearch(sender(), pack.getLoadKey(), false, true);
}
Iris.service(StudioSVC.class).installIntoWorld(sender(), pack.getLoadKey(), folder);
}
}

View File

@ -1,112 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.edit.JigsawEditor;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.jigsaw.PlannedStructure;
import com.volmit.iris.engine.object.IrisJigsawPiece;
import com.volmit.iris.engine.object.IrisJigsawStructure;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisPosition;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.decree.specialhandlers.ObjectHandler;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import java.io.File;
@Decree(name = "jigsaw", origin = DecreeOrigin.PLAYER, studio = true, description = "Iris jigsaw commands")
public class CommandJigsaw implements DecreeExecutor {
@Decree(description = "Edit a jigsaw piece")
public void edit(
@Param(description = "The jigsaw piece to edit")
IrisJigsawPiece piece
) {
File dest = piece.getLoadFile();
new JigsawEditor(player(), piece, IrisData.loadAnyObject(piece.getObject()), dest);
}
@Decree(description = "Place a jigsaw structure")
public void place(
@Param(description = "The jigsaw structure to place")
IrisJigsawStructure structure
) {
PrecisionStopwatch p = PrecisionStopwatch.start();
PlannedStructure ps = new PlannedStructure(structure, new IrisPosition(player().getLocation()), new RNG());
sender().sendMessage(C.GREEN + "Generated " + ps.getPieces().size() + " pieces in " + Form.duration(p.getMilliseconds(), 2));
ps.place(world());
}
@Decree(description = "Create a jigsaw piece")
public void create(
@Param(description = "The name of the jigsaw piece")
String piece,
@Param(description = "The project to add the jigsaw piece to")
String project,
@Param(description = "The object to use for this piece", customHandler = ObjectHandler.class)
String object
) {
IrisObject o = IrisData.loadAnyObject(object);
if(object == null) {
sender().sendMessage(C.RED + "Failed to find existing object");
return;
}
File dest = Iris.instance.getDataFile("packs", project, "jigsaw-pieces", piece + ".json");
new JigsawEditor(player(), null, o, dest);
sender().sendMessage(C.GRAY + "* Right Click blocks to make them connectors");
sender().sendMessage(C.GRAY + "* Right Click connectors to orient them");
sender().sendMessage(C.GRAY + "* Shift + Right Click connectors to remove them");
sender().sendMessage(C.GREEN + "Remember to use /iris jigsaw save");
}
@Decree(description = "Exit the current jigsaw editor")
public void exit() {
JigsawEditor editor = JigsawEditor.editors.get(player());
if(editor == null) {
sender().sendMessage(C.GOLD + "You don't have any pieces open to exit!");
return;
}
editor.exit();
sender().sendMessage(C.GREEN + "Exited Jigsaw Editor");
}
@Decree(description = "Save & Exit the current jigsaw editor")
public void save() {
JigsawEditor editor = JigsawEditor.editors.get(player());
if(editor == null) {
sender().sendMessage(C.GOLD + "You don't have any pieces open to save!");
return;
}
editor.close();
sender().sendMessage(C.GREEN + "Saved & Exited Jigsaw Editor");
}
}

View File

@ -1,530 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.WorldEditLink;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.service.ObjectSVC;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.service.WandSVC;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IObjectPlacer;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisObjectPlacement;
import com.volmit.iris.engine.object.IrisObjectPlacementScaleInterpolator;
import com.volmit.iris.engine.object.IrisObjectRotation;
import com.volmit.iris.engine.object.TileData;
import com.volmit.iris.util.data.Cuboid;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.decree.specialhandlers.ObjectHandler;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.Direction;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.Queue;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.io.File;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
@Decree(name = "object", aliases = "o", origin = DecreeOrigin.PLAYER, studio = true, description = "Iris object manipulation")
public class CommandObject implements DecreeExecutor {
private static final Set<Material> skipBlocks = Set.of(Material.GRASS, Material.SNOW, Material.VINE, Material.TORCH, Material.DEAD_BUSH,
Material.POPPY, Material.DANDELION);
public static IObjectPlacer createPlacer(World world, Map<Block, BlockData> futureBlockChanges) {
return new IObjectPlacer() {
@Override
public int getHighest(int x, int z, IrisData data) {
return world.getHighestBlockYAt(x, z);
}
@Override
public int getHighest(int x, int z, IrisData data, boolean ignoreFluid) {
return world.getHighestBlockYAt(x, z, ignoreFluid ? HeightMap.OCEAN_FLOOR : HeightMap.MOTION_BLOCKING);
}
@Override
public void set(int x, int y, int z, BlockData d) {
Block block = world.getBlockAt(x, y, z);
//Prevent blocks being set in or bellow bedrock
if(y <= world.getMinHeight() || block.getType() == Material.BEDROCK) return;
futureBlockChanges.put(block, block.getBlockData());
block.setBlockData(d);
}
@Override
public BlockData get(int x, int y, int z) {
return world.getBlockAt(x, y, z).getBlockData();
}
@Override
public boolean isPreventingDecay() {
return false;
}
@Override
public boolean isCarved(int x, int y, int z) {
return false;
}
@Override
public boolean isSolid(int x, int y, int z) {
return world.getBlockAt(x, y, z).getType().isSolid();
}
@Override
public boolean isUnderwater(int x, int z) {
return false;
}
@Override
public int getFluidHeight() {
return 63;
}
@Override
public boolean isDebugSmartBore() {
return false;
}
@Override
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) {
BlockState state = world.getBlockAt(xx, yy, zz).getState();
tile.toBukkitTry(state);
state.update();
}
@Override
public Engine getEngine() {
return null;
}
};
}
@Decree(description = "Check the composition of an object")
public void analyze(
@Param(description = "The object to analyze", customHandler = ObjectHandler.class)
String object
) {
IrisObject o = IrisData.loadAnyObject(object);
sender().sendMessage("Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD() + "");
sender().sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(o.getBlocks().size()));
Queue<BlockData> queue = o.getBlocks().enqueueValues();
Map<Material, Set<BlockData>> unsorted = new HashMap<>();
Map<BlockData, Integer> amounts = new HashMap<>();
Map<Material, Integer> materials = new HashMap<>();
while(queue.hasNext()) {
BlockData block = queue.next();
//unsorted.put(block.getMaterial(), block);
if(!amounts.containsKey(block)) {
amounts.put(block, 1);
} else
amounts.put(block, amounts.get(block) + 1);
if(!materials.containsKey(block.getMaterial())) {
materials.put(block.getMaterial(), 1);
unsorted.put(block.getMaterial(), new HashSet<>());
unsorted.get(block.getMaterial()).add(block);
} else {
materials.put(block.getMaterial(), materials.get(block.getMaterial()) + 1);
unsorted.get(block.getMaterial()).add(block);
}
}
List<Material> sortedMatsList = amounts.keySet().stream().map(BlockData::getMaterial)
.sorted().collect(Collectors.toList());
Set<Material> sortedMats = new TreeSet<>(Comparator.comparingInt(materials::get).reversed());
sortedMats.addAll(sortedMatsList);
sender().sendMessage("== Blocks in object ==");
int n = 0;
for(Material mat : sortedMats) {
int amount = materials.get(mat);
List<BlockData> set = new ArrayList<>(unsorted.get(mat));
set.sort(Comparator.comparingInt(amounts::get).reversed());
BlockData data = set.get(0);
int dataAmount = amounts.get(data);
String string = " - " + mat.toString() + "*" + amount;
if(data.getAsString(true).contains("[")) {
string = string + " --> [" + data.getAsString(true).split("\\[")[1]
.replaceAll("true", ChatColor.GREEN + "true" + ChatColor.GRAY)
.replaceAll("false", ChatColor.RED + "false" + ChatColor.GRAY) + "*" + dataAmount;
}
sender().sendMessage(string);
n++;
if(n >= 10) {
sender().sendMessage(" + " + (sortedMats.size() - n) + " other block types");
return;
}
}
}
@Decree(description = "Get a powder that reveals objects", studio = true, aliases = "d")
public void dust() {
player().getInventory().addItem(WandSVC.createDust());
sender().playSound(Sound.AMBIENT_SOUL_SAND_VALLEY_ADDITIONS, 1f, 1.5f);
}
@Decree(description = "Contract a selection based on your looking direction", aliases = "-")
public void contract(
@Param(description = "The amount to inset by", defaultValue = "1")
int amount
) {
if(!WandSVC.isHoldingWand(player())) {
sender().sendMessage("Hold your wand.");
return;
}
Location[] b = WandSVC.getCuboid(player());
Location a1 = b[0].clone();
Location a2 = b[1].clone();
Cuboid cursor = new Cuboid(a1, a2);
Direction d = Direction.closest(player().getLocation().getDirection()).reverse();
assert d != null;
cursor = cursor.expand(d, -amount);
b[0] = cursor.getLowerNE();
b[1] = cursor.getUpperSW();
player().getInventory().setItemInMainHand(WandSVC.createWand(b[0], b[1]));
player().updateInventory();
sender().playSound(Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 0.55f);
}
@Decree(description = "Set point 1 to look", aliases = "p1")
public void position1(
@Param(description = "Whether to use your current position, or where you look", defaultValue = "true")
boolean here
) {
if(!WandSVC.isHoldingWand(player())) {
sender().sendMessage("Ready your Wand.");
return;
}
if(WandSVC.isHoldingWand(player())) {
Location[] g = WandSVC.getCuboid(player());
if(!here) {
// TODO: WARNING HEIGHT
g[1] = player().getTargetBlock(null, 256).getLocation().clone();
} else {
g[1] = player().getLocation().getBlock().getLocation().clone().add(0, -1, 0);
}
player().setItemInHand(WandSVC.createWand(g[0], g[1]));
}
}
@Decree(description = "Set point 2 to look", aliases = "p2")
public void position2(
@Param(description = "Whether to use your current position, or where you look", defaultValue = "true")
boolean here
) {
if(!WandSVC.isHoldingWand(player())) {
sender().sendMessage("Ready your Wand.");
return;
}
if(WandSVC.isHoldingIrisWand(player())) {
Location[] g = WandSVC.getCuboid(player());
if(!here) {
// TODO: WARNING HEIGHT
g[0] = player().getTargetBlock(null, 256).getLocation().clone();
} else {
g[0] = player().getLocation().getBlock().getLocation().clone().add(0, -1, 0);
}
player().setItemInHand(WandSVC.createWand(g[0], g[1]));
}
}
@Decree(description = "Paste an object", sync = true)
public void paste(
@Param(description = "The object to paste", customHandler = ObjectHandler.class)
String object,
@Param(description = "Whether or not to edit the object (need to hold wand)", defaultValue = "false")
boolean edit,
@Param(description = "The amount of degrees to rotate by", defaultValue = "0")
int rotate,
@Param(description = "The factor by which to scale the object placement", defaultValue = "1")
double scale
// ,
// @Param(description = "The scale interpolator to use", defaultValue = "none")
// IrisObjectPlacementScaleInterpolator interpolator
) {
IrisObject o = IrisData.loadAnyObject(object);
double maxScale = Double.max(10 - o.getBlocks().size() / 10000d, 1);
if(scale > maxScale) {
sender().sendMessage(C.YELLOW + "Indicated scale exceeds maximum. Downscaled to maximum: " + maxScale);
scale = maxScale;
}
sender().playSound(Sound.BLOCK_ENCHANTMENT_TABLE_USE, 1f, 1.5f);
IrisObjectPlacement placement = new IrisObjectPlacement();
placement.setRotation(IrisObjectRotation.of(0, rotate, 0));
ItemStack wand = player().getInventory().getItemInMainHand();
Location block = player().getTargetBlock(skipBlocks, 256).getLocation().clone().add(0, 1, 0);
Map<Block, BlockData> futureChanges = new HashMap<>();
if(scale != 1)
{
o = o.scaled(scale, IrisObjectPlacementScaleInterpolator.TRICUBIC);
}
o.place(block.getBlockX(), block.getBlockY() + (int) o.getCenter().getY(), block.getBlockZ(), createPlacer(block.getWorld(), futureChanges), placement, new RNG(), null);
Iris.service(ObjectSVC.class).addChanges(futureChanges);
if(edit) {
ItemStack newWand = WandSVC.createWand(block.clone().subtract(o.getCenter()).add(o.getW() - 1,
o.getH() + o.getCenter().clone().getY() - 1, o.getD() - 1), block.clone().subtract(o.getCenter().clone().setY(0)));
if(WandSVC.isWand(wand)) {
wand = newWand;
player().getInventory().setItemInMainHand(wand);
sender().sendMessage("Updated wand for " + "objects/" + o.getLoadKey() + ".iob ");
} else {
int slot = WandSVC.findWand(player().getInventory());
if(slot == -1) {
player().getInventory().addItem(newWand);
sender().sendMessage("Given new wand for " + "objects/" + o.getLoadKey() + ".iob ");
} else {
player().getInventory().setItem(slot, newWand);
sender().sendMessage("Updated wand for " + "objects/" + o.getLoadKey() + ".iob ");
}
}
} else {
sender().sendMessage("Placed " + object);
}
}
@Decree(description = "Save an object")
public void save(
@Param(description = "The dimension to store the object in", contextual = true)
IrisDimension dimension,
@Param(description = "The file to store it in, can use / for subfolders")
String name,
@Param(description = "Overwrite existing object files", defaultValue = "false", aliases = "force")
boolean overwrite
) {
IrisObject o = WandSVC.createSchematic(player());
if(o == null) {
sender().sendMessage(C.YELLOW + "You need to hold your wand!");
return;
}
File file = Iris.service(StudioSVC.class).getWorkspaceFile(dimension.getLoadKey(), "objects", name + ".iob");
if(file.exists() && !overwrite) {
sender().sendMessage(C.RED + "File already exists. Set overwrite=true to overwrite it.");
return;
}
try {
o.write(file);
} catch(IOException e) {
sender().sendMessage(C.RED + "Failed to save object because of an IOException: " + e.getMessage());
Iris.reportError(e);
}
sender().playSound(Sound.BLOCK_ENCHANTMENT_TABLE_USE, 1f, 1.5f);
sender().sendMessage(C.GREEN + "Successfully object to saved: " + dimension.getLoadKey() + "/objects/" + name);
}
@Decree(description = "Shift a selection in your looking direction", aliases = "-")
public void shift(
@Param(description = "The amount to shift by", defaultValue = "1")
int amount
) {
if(!WandSVC.isHoldingWand(player())) {
sender().sendMessage("Hold your wand.");
return;
}
Location[] b = WandSVC.getCuboid(player());
Location a1 = b[0].clone();
Location a2 = b[1].clone();
Direction d = Direction.closest(player().getLocation().getDirection()).reverse();
a1.add(d.toVector().multiply(amount));
a2.add(d.toVector().multiply(amount));
Cuboid cursor = new Cuboid(a1, a2);
b[0] = cursor.getLowerNE();
b[1] = cursor.getUpperSW();
player().getInventory().setItemInMainHand(WandSVC.createWand(b[0], b[1]));
player().updateInventory();
sender().playSound(Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 0.55f);
}
@Decree(description = "Undo a number of pastes", aliases = "-")
public void undo(
@Param(description = "The amount of pastes to undo", defaultValue = "1")
int amount
) {
ObjectSVC service = Iris.service(ObjectSVC.class);
int actualReverts = Math.min(service.getUndos().size(), amount);
service.revertChanges(actualReverts);
sender().sendMessage("Reverted " + actualReverts + " pastes!");
}
@Decree(description = "Gets an object wand and grabs the current WorldEdit selection.", aliases = "we", origin = DecreeOrigin.PLAYER, studio = true)
public void we() {
if(!Bukkit.getPluginManager().isPluginEnabled("WorldEdit")) {
sender().sendMessage(C.RED + "You can't get a WorldEdit selection without WorldEdit, you know.");
return;
}
Cuboid locs = WorldEditLink.getSelection(sender().player());
if(locs == null)
{
sender().sendMessage(C.RED + "You don't have a WorldEdit selection in this world.");
return;
}
sender().player().getInventory().addItem(WandSVC.createWand(locs.getLowerNE(), locs.getUpperSW()));
sender().sendMessage(C.GREEN + "A fresh wand with your current WorldEdit selection on it!");
}
@Decree(description = "Get an object wand", sync = true)
public void wand() {
player().getInventory().addItem(WandSVC.createWand());
sender().playSound(Sound.ITEM_ARMOR_EQUIP_NETHERITE, 1f, 1.5f);
sender().sendMessage(C.GREEN + "Poof! Good luck building!");
}
@Decree(name = "x&y", description = "Autoselect up, down & out", sync = true)
public void xay() {
if(!WandSVC.isHoldingWand(player())) {
sender().sendMessage(C.YELLOW + "Hold your wand!");
return;
}
Location[] b = WandSVC.getCuboid(player());
Location a1 = b[0].clone();
Location a2 = b[1].clone();
Location a1x = b[0].clone();
Location a2x = b[1].clone();
Cuboid cursor = new Cuboid(a1, a2);
Cuboid cursorx = new Cuboid(a1, a2);
while(!cursor.containsOnly(Material.AIR)) {
a1.add(new org.bukkit.util.Vector(0, 1, 0));
a2.add(new org.bukkit.util.Vector(0, 1, 0));
cursor = new Cuboid(a1, a2);
}
a1.add(new org.bukkit.util.Vector(0, -1, 0));
a2.add(new org.bukkit.util.Vector(0, -1, 0));
while(!cursorx.containsOnly(Material.AIR)) {
a1x.add(new org.bukkit.util.Vector(0, -1, 0));
a2x.add(new org.bukkit.util.Vector(0, -1, 0));
cursorx = new Cuboid(a1x, a2x);
}
a1x.add(new org.bukkit.util.Vector(0, 1, 0));
a2x.add(new Vector(0, 1, 0));
b[0] = a1;
b[1] = a2x;
cursor = new Cuboid(b[0], b[1]);
cursor = cursor.contract(Cuboid.CuboidDirection.North);
cursor = cursor.contract(Cuboid.CuboidDirection.South);
cursor = cursor.contract(Cuboid.CuboidDirection.East);
cursor = cursor.contract(Cuboid.CuboidDirection.West);
b[0] = cursor.getLowerNE();
b[1] = cursor.getUpperSW();
player().getInventory().setItemInMainHand(WandSVC.createWand(b[0], b[1]));
player().updateInventory();
sender().playSound(Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 0.55f);
sender().sendMessage(C.GREEN + "Auto-select complete!");
}
@Decree(name = "x+y", description = "Autoselect up & out", sync = true)
public void xpy() {
if(!WandSVC.isHoldingWand(player())) {
sender().sendMessage(C.YELLOW + "Hold your wand!");
return;
}
Location[] b = WandSVC.getCuboid(player());
b[0].add(new Vector(0, 1, 0));
b[1].add(new Vector(0, 1, 0));
Location a1 = b[0].clone();
Location a2 = b[1].clone();
Cuboid cursor = new Cuboid(a1, a2);
while(!cursor.containsOnly(Material.AIR)) {
a1.add(new Vector(0, 1, 0));
a2.add(new Vector(0, 1, 0));
cursor = new Cuboid(a1, a2);
}
a1.add(new Vector(0, -1, 0));
a2.add(new Vector(0, -1, 0));
b[0] = a1;
a2 = b[1];
cursor = new Cuboid(a1, a2);
cursor = cursor.contract(Cuboid.CuboidDirection.North);
cursor = cursor.contract(Cuboid.CuboidDirection.South);
cursor = cursor.contract(Cuboid.CuboidDirection.East);
cursor = cursor.contract(Cuboid.CuboidDirection.West);
b[0] = cursor.getLowerNE();
b[1] = cursor.getUpperSW();
player().getInventory().setItemInMainHand(WandSVC.createWand(b[0], b[1]));
player().updateInventory();
sender().playSound(Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 0.55f);
sender().sendMessage(C.GREEN + "Auto-select complete!");
}
}

View File

@ -1,84 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.gui.PregeneratorJob;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.Position2;
import org.bukkit.World;
import org.bukkit.util.Vector;
@Decree(name = "pregen", aliases = "pregenerate", description = "Pregenerate your Iris worlds!")
public class CommandPregen implements DecreeExecutor {
@Decree(description = "Pregenerate a world")
public void start(
@Param(description = "The radius of the pregen in blocks", aliases = "size")
int radius,
@Param(description = "The world to pregen", contextual = true)
World world,
@Param(aliases = "middle", description = "The center location of the pregen. Use \"me\" for your current location", defaultValue = "0,0")
Vector center
) {
try {
if(sender().isPlayer() && access() == null) {
sender().sendMessage(C.RED + "The engine access for this world is null!");
sender().sendMessage(C.RED + "Please make sure the world is loaded & the engine is initialized. Generate a new chunk, for example.");
}
radius = Math.max(radius, 1024);
int w = (radius >> 9 + 1) * 2;
IrisToolbelt.pregenerate(PregenTask
.builder()
.center(new Position2(center))
.width(w)
.height(w)
.build(), world);
String msg = C.GREEN + "Pregen started in " + C.GOLD + world.getName() + C.GREEN + " of " + C.GOLD + (radius * 2) + C.GREEN + " by " + C.GOLD + (radius * 2) + C.GREEN + " blocks from " + C.GOLD + center.getX() + "," + center.getZ();
sender().sendMessage(msg);
Iris.info(msg);
} catch(Throwable e) {
sender().sendMessage(C.RED + "Epic fail. See console.");
Iris.reportError(e);
e.printStackTrace();
}
}
@Decree(description = "Stop the active pregeneration task", aliases = "x")
public void stop() {
if(PregeneratorJob.shutdownInstance()) {
sender().sendMessage(C.GREEN + "Stopped pregeneration task");
} else {
sender().sendMessage(C.YELLOW + "No active pregeneration tasks to stop");
}
}
@Decree(description = "Pause / continue the active pregeneration task", aliases = {"t", "resume", "unpause"})
public void pause() {
if(PregeneratorJob.pauseResume()) {
sender().sendMessage(C.GREEN + "Paused/unpaused pregeneration task, now: " + (PregeneratorJob.isPaused() ? "Paused" : "Running") + ".");
} else {
sender().sendMessage(C.YELLOW + "No active pregeneration tasks to pause/unpause.");
}
}
}

View File

@ -1,25 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.util.decree.DecreeExecutor;
public class CommandSettings implements DecreeExecutor {
}

View File

@ -1,900 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.gui.NoiseExplorerGUI;
import com.volmit.iris.core.gui.VisionGUI;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.project.IrisProject;
import com.volmit.iris.core.service.ConversionSVC;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.InventorySlotType;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomePaletteLayer;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisEntity;
import com.volmit.iris.engine.object.IrisGenerator;
import com.volmit.iris.engine.object.IrisInterpolator;
import com.volmit.iris.engine.object.IrisLootTable;
import com.volmit.iris.engine.object.IrisNoiseGenerator;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisObjectPlacement;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.engine.object.IrisScript;
import com.volmit.iris.engine.object.NoiseStyle;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.function.Function2;
import com.volmit.iris.util.function.NoiseProvider;
import com.volmit.iris.util.interpolation.InterpolationMethod;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.O;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.scheduling.jobs.Job;
import com.volmit.iris.util.scheduling.jobs.JobCollection;
import com.volmit.iris.util.scheduling.jobs.QueueJob;
import com.volmit.iris.util.scheduling.jobs.SingleJob;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.FluidCollisionMode;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.util.BlockVector;
import org.bukkit.util.Vector;
import java.awt.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.attribute.FileTime;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.function.Supplier;
@Decree(name = "studio", aliases = {"std", "s"}, description = "Studio Commands", studio = true)
public class CommandStudio implements DecreeExecutor {
public static String hrf(Duration duration) {
return duration.toString().substring(2).replaceAll("(\\d[HMS])(?!$)", "$1 ").toLowerCase();
}
private CommandFind find;
private CommandEdit edit;
@Decree(description = "Download a project.", aliases = "dl")
public void download(
@Param(name = "pack", description = "The pack to download", defaultValue = "overworld", aliases = "project")
String pack,
@Param(name = "branch", description = "The branch to download from", defaultValue = "master")
String branch,
@Param(name = "trim", description = "Whether or not to download a trimmed version (do not enable when editing)", defaultValue = "false")
boolean trim,
@Param(name = "overwrite", description = "Whether or not to overwrite the pack with the downloaded one", aliases = "force", defaultValue = "false")
boolean overwrite
) {
new CommandIris().download(pack, branch, trim, overwrite);
}
@Decree(description = "Open a new studio world", aliases = "o", sync = true)
public void open(
@Param(defaultValue = "default", description = "The dimension to open a studio for", aliases = "dim")
IrisDimension dimension,
@Param(defaultValue = "1337", description = "The seed to generate the studio with", aliases = "s")
long seed) {
sender().sendMessage(C.GREEN + "Opening studio for the \"" + dimension.getName() + "\" pack (seed: " + seed + ")");
Iris.service(StudioSVC.class).open(sender(), seed, dimension.getLoadKey());
}
@Decree(description = "Open VSCode for a dimension", aliases = {"vsc", "edit"})
public void vscode(
@Param(defaultValue = "default", description = "The dimension to open VSCode for", aliases = "dim")
IrisDimension dimension
) {
sender().sendMessage(C.GREEN + "Opening VSCode for the \"" + dimension.getName() + "\" pack");
Iris.service(StudioSVC.class).openVSCode(sender(), dimension.getLoadKey());
}
@Decree(description = "Close an open studio project", aliases = {"x", "c"}, sync = true)
public void close() {
if(!Iris.service(StudioSVC.class).isProjectOpen()) {
sender().sendMessage(C.RED + "No open studio projects.");
return;
}
Iris.service(StudioSVC.class).close();
sender().sendMessage(C.GREEN + "Project Closed.");
}
@Decree(description = "Create a new studio project", aliases = "+", sync = true)
public void create(
@Param(description = "The name of this new Iris Project.")
String name,
@Param(description = "Copy the contents of an existing project in your packs folder and use it as a template in this new project.", contextual = true)
IrisDimension template) {
if(template != null) {
Iris.service(StudioSVC.class).create(sender(), name, template.getLoadKey());
} else {
Iris.service(StudioSVC.class).create(sender(), name);
}
}
@Decree(description = "Clean an Iris Project, optionally beautifying JSON & fixing block ids with missing keys. Also rebuilds the vscode schemas. ")
public void clean(
@Param(description = "The project to update", contextual = true)
IrisDimension project,
@Param(defaultValue = "true", description = "Filters all valid JSON files with a beautifier (indentation: 4)")
boolean beautify,
@Param(name = "fix-ids", defaultValue = "true", description = "Fixes any block ids used such as \"dirt\" will be converted to \"minecraft:dirt\"")
boolean fixIds,
@Param(name = "rewrite-objects", defaultValue = "false", description = "Imports all objects and re-writes them cleaning up positions & block data in the process.")
boolean rewriteObjects
) {
KList<Job> jobs = new KList<>();
KList<File> files = new KList<File>();
files(Iris.instance.getDataFolder("packs", project.getLoadKey()), files);
MultiBurst burst = MultiBurst.burst;
jobs.add(new SingleJob("Updating Workspace", () -> {
if(!new IrisProject(Iris.service(StudioSVC.class).getWorkspaceFolder(project.getLoadKey())).updateWorkspace()) {
sender().sendMessage(C.GOLD + "Invalid project: " + project.getLoadKey() + ". Try deleting the code-workspace file and try again.");
}
J.sleep(250);
}));
sender().sendMessage("Files: " + files.size());
if(fixIds) {
QueueJob<File> r = new QueueJob<>() {
@Override
public void execute(File f) {
try {
JSONObject p = new JSONObject(IO.readAll(f));
fixBlocks(p);
J.sleep(1);
IO.writeAll(f, p.toString(4));
} catch(IOException e) {
e.printStackTrace();
}
}
@Override
public String getName() {
return "Fixing IDs";
}
};
r.queue(files);
jobs.add(r);
}
if(beautify) {
QueueJob<File> r = new QueueJob<>() {
@Override
public void execute(File f) {
try {
JSONObject p = new JSONObject(IO.readAll(f));
IO.writeAll(f, p.toString(4));
J.sleep(1);
} catch(IOException e) {
e.printStackTrace();
}
}
@Override
public String getName() {
return "Beautify";
}
};
r.queue(files);
jobs.add(r);
}
if(rewriteObjects) {
QueueJob<Runnable> q = new QueueJob<>() {
@Override
public void execute(Runnable runnable) {
runnable.run();
J.sleep(50);
}
@Override
public String getName() {
return "Rewriting Objects";
}
};
IrisData data = IrisData.get(Iris.service(StudioSVC.class).getWorkspaceFolder(project.getLoadKey()));
for(String f : data.getObjectLoader().getPossibleKeys()) {
Future<?> gg = burst.complete(() -> {
File ff = data.getObjectLoader().findFile(f);
IrisObject oo = new IrisObject(0, 0, 0);
try {
oo.read(ff);
} catch(Throwable e) {
Iris.error("FAILER TO READ: " + f);
return;
}
try {
oo.write(ff);
} catch(IOException e) {
Iris.error("FAILURE TO WRITE: " + oo.getLoadFile());
}
});
q.queue(() -> {
try {
gg.get();
} catch(InterruptedException | ExecutionException e) {
e.printStackTrace();
}
});
}
jobs.add(q);
}
new JobCollection("Cleaning", jobs).execute(sender());
}
@Decree(description = "Get the version of a pack")
public void version(
@Param(defaultValue = "default", description = "The dimension get the version of", aliases = "dim", contextual = true)
IrisDimension dimension
) {
sender().sendMessage(C.GREEN + "The \"" + dimension.getName() + "\" pack has version: " + dimension.getVersion());
}
@Decree(description = "Convert objects in the \"convert\" folder")
public void convert() {
Iris.service(ConversionSVC.class).check(sender());
}
@Decree(description = "Execute a script", aliases = "run", origin = DecreeOrigin.PLAYER)
public void execute(
@Param(description = "The script to run")
IrisScript script
) {
engine().getExecution().execute(script.getLoadKey());
}
@Decree(description = "Open the noise explorer (External GUI)", aliases = {"nmap", "n"})
public void noise() {
if(noGUI()) return;
sender().sendMessage(C.GREEN + "Opening Noise Explorer!");
NoiseExplorerGUI.launch();
}
@Decree(description = "Charges all spawners in the area", aliases = "zzt", origin = DecreeOrigin.PLAYER)
public void charge() {
if(!IrisToolbelt.isIrisWorld(world())) {
sender().sendMessage(C.RED + "You must be in an Iris world to charge spawners!");
return;
}
sender().sendMessage(C.GREEN + "Charging spawners!");
engine().getWorldManager().chargeEnergy();
}
@Decree(description = "Preview noise gens (External GUI)", aliases = {"generator", "gen"})
public void explore(
@Param(description = "The generator to explore", contextual = true)
IrisGenerator generator,
@Param(description = "The seed to generate with", defaultValue = "12345")
long seed
) {
if(noGUI()) return;
sender().sendMessage(C.GREEN + "Opening Noise Explorer!");
Supplier<Function2<Double, Double, Double>> l = () -> {
if(generator == null) {
return (x, z) -> 0D;
}
return (x, z) -> generator.getHeight(x, z, new RNG(seed).nextParallelRNG(3245).lmax());
};
NoiseExplorerGUI.launch(l, "Custom Generator");
}
@Decree(description = "Hotload a studio", aliases = {"reload", "h"})
public void hotload() {
if(!Iris.service(StudioSVC.class).isProjectOpen()) {
sender().sendMessage(C.RED + "No studio world open!");
return;
}
Iris.service(StudioSVC.class).getActiveProject().getActiveProvider().getEngine().hotload();
sender().sendMessage(C.GREEN + "Hotloaded");
}
@Decree(description = "Show loot if a chest were right here", origin = DecreeOrigin.PLAYER, sync = true)
public void loot(
@Param(description = "Fast insertion of items in virtual inventory (may cause performance drop)", defaultValue = "false")
boolean fast,
@Param(description = "Whether or not to append to the inventory currently open (if false, clears opened inventory)", defaultValue = "true")
boolean add
) {
if(noStudio()) return;
KList<IrisLootTable> tables = engine().getLootTables(RNG.r, player().getLocation().getBlock());
Inventory inv = Bukkit.createInventory(null, 27 * 2);
try {
engine().addItems(true, inv, RNG.r, tables, InventorySlotType.STORAGE, player().getLocation().getBlockX(), player().getLocation().getBlockY(), player().getLocation().getBlockZ(), 1);
} catch(Throwable e) {
Iris.reportError(e);
sender().sendMessage(C.RED + "Cannot add items to virtual inventory because of: " + e.getMessage());
return;
}
O<Integer> ta = new O<>();
ta.set(-1);
ta.set(Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () ->
{
if(!player().getOpenInventory().getType().equals(InventoryType.CHEST)) {
Bukkit.getScheduler().cancelTask(ta.get());
sender().sendMessage(C.GREEN + "Opened inventory!");
return;
}
if(!add) {
inv.clear();
}
engine().addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player().getLocation().getBlockX(), player().getLocation().getBlockY(), player().getLocation().getBlockZ(), 1);
}, 0, fast ? 5 : 35));
sender().sendMessage(C.GREEN + "Opening inventory now!");
player().openInventory(inv);
}
@Decree(description = "Render a world map (External GUI)", aliases = "render")
public void map(
@Param(name = "world", description = "The world to open the generator for", contextual = true)
World world
) {
if(noGUI()) return;
if(!IrisToolbelt.isIrisWorld(world)) {
sender().sendMessage(C.RED + "You need to be in or specify an Iris-generated world!");
return;
}
VisionGUI.launch(IrisToolbelt.access(world).getEngine(), 0);
sender().sendMessage(C.GREEN + "Opening map!");
}
@Decree(description = "Package a dimension into a compressed format", aliases = "package")
public void pkg(
@Param(name = "dimension", description = "The dimension pack to compress", contextual = true, defaultValue = "default")
IrisDimension dimension,
@Param(name = "obfuscate", description = "Whether or not to obfuscate the pack", defaultValue = "false")
boolean obfuscate,
@Param(name = "minify", description = "Whether or not to minify the pack", defaultValue = "true")
boolean minify
) {
Iris.service(StudioSVC.class).compilePackage(sender(), dimension.getLoadKey(), obfuscate, minify);
}
@Decree(description = "Profiles the performance of a dimension", origin = DecreeOrigin.PLAYER)
public void profile(
@Param(description = "The dimension to profile", contextual = true, defaultValue = "default")
IrisDimension dimension
) {
File pack = dimension.getLoadFile().getParentFile().getParentFile();
File report = Iris.instance.getDataFile("profile.txt");
IrisProject project = new IrisProject(pack);
IrisData data = IrisData.get(pack);
KList<String> fileText = new KList<>();
KMap<NoiseStyle, Double> styleTimings = new KMap<>();
KMap<InterpolationMethod, Double> interpolatorTimings = new KMap<>();
KMap<String, Double> generatorTimings = new KMap<>();
KMap<String, Double> biomeTimings = new KMap<>();
KMap<String, Double> regionTimings = new KMap<>();
sender().sendMessage("Calculating Performance Metrics for Noise generators");
for(NoiseStyle i : NoiseStyle.values()) {
CNG c = i.create(new RNG(i.hashCode()));
for(int j = 0; j < 3000; j++) {
c.noise(j, j + 1000, j * j);
c.noise(j, -j);
}
PrecisionStopwatch px = PrecisionStopwatch.start();
for(int j = 0; j < 100000; j++) {
c.noise(j, j + 1000, j * j);
c.noise(j, -j);
}
styleTimings.put(i, px.getMilliseconds());
}
fileText.add("Noise Style Performance Impacts: ");
for(NoiseStyle i : styleTimings.sortKNumber()) {
fileText.add(i.name() + ": " + styleTimings.get(i));
}
fileText.add("");
sender().sendMessage("Calculating Interpolator Timings...");
for(InterpolationMethod i : InterpolationMethod.values()) {
IrisInterpolator in = new IrisInterpolator();
in.setFunction(i);
in.setHorizontalScale(8);
NoiseProvider np = (x, z) -> Math.random();
for(int j = 0; j < 3000; j++) {
in.interpolate(j, -j, np);
}
PrecisionStopwatch px = PrecisionStopwatch.start();
for(int j = 0; j < 100000; j++) {
in.interpolate(j + 10000, -j - 100000, np);
}
interpolatorTimings.put(i, px.getMilliseconds());
}
fileText.add("Noise Interpolator Performance Impacts: ");
for(InterpolationMethod i : interpolatorTimings.sortKNumber()) {
fileText.add(i.name() + ": " + interpolatorTimings.get(i));
}
fileText.add("");
sender().sendMessage("Processing Generator Scores: ");
KMap<String, KList<String>> btx = new KMap<>();
for(String i : data.getGeneratorLoader().getPossibleKeys()) {
KList<String> vv = new KList<>();
IrisGenerator g = data.getGeneratorLoader().load(i);
KList<IrisNoiseGenerator> composites = g.getAllComposites();
double score = 0;
int m = 0;
for(IrisNoiseGenerator j : composites) {
m++;
score += styleTimings.get(j.getStyle().getStyle());
vv.add("Composite Noise Style " + m + " " + j.getStyle().getStyle().name() + ": " + styleTimings.get(j.getStyle().getStyle()));
}
score += interpolatorTimings.get(g.getInterpolator().getFunction());
vv.add("Interpolator " + g.getInterpolator().getFunction().name() + ": " + interpolatorTimings.get(g.getInterpolator().getFunction()));
generatorTimings.put(i, score);
btx.put(i, vv);
}
fileText.add("Project Generator Performance Impacts: ");
for(String i : generatorTimings.sortKNumber()) {
fileText.add(i + ": " + generatorTimings.get(i));
btx.get(i).forEach((ii) -> fileText.add(" " + ii));
}
fileText.add("");
KMap<String, KList<String>> bt = new KMap<>();
for(String i : data.getBiomeLoader().getPossibleKeys()) {
KList<String> vv = new KList<>();
IrisBiome b = data.getBiomeLoader().load(i);
double score = 0;
int m = 0;
for(IrisBiomePaletteLayer j : b.getLayers()) {
m++;
score += styleTimings.get(j.getStyle().getStyle());
vv.add("Palette Layer " + m + ": " + styleTimings.get(j.getStyle().getStyle()));
}
score += styleTimings.get(b.getBiomeStyle().getStyle());
vv.add("Biome Style: " + styleTimings.get(b.getBiomeStyle().getStyle()));
score += styleTimings.get(b.getChildStyle().getStyle());
vv.add("Child Style: " + styleTimings.get(b.getChildStyle().getStyle()));
biomeTimings.put(i, score);
bt.put(i, vv);
}
fileText.add("Project Biome Performance Impacts: ");
for(String i : biomeTimings.sortKNumber()) {
fileText.add(i + ": " + biomeTimings.get(i));
bt.get(i).forEach((ff) -> fileText.add(" " + ff));
}
fileText.add("");
for(String i : data.getRegionLoader().getPossibleKeys()) {
IrisRegion b = data.getRegionLoader().load(i);
double score = 0;
score += styleTimings.get(b.getLakeStyle().getStyle());
score += styleTimings.get(b.getRiverStyle().getStyle());
regionTimings.put(i, score);
}
fileText.add("Project Region Performance Impacts: ");
for(String i : regionTimings.sortKNumber()) {
fileText.add(i + ": " + regionTimings.get(i));
}
fileText.add("");
double m = 0;
for(double i : biomeTimings.v()) {
m += i;
}
m /= biomeTimings.size();
double mm = 0;
for(double i : generatorTimings.v()) {
mm += i;
}
mm /= generatorTimings.size();
m += mm;
double mmm = 0;
for(double i : regionTimings.v()) {
mmm += i;
}
mmm /= regionTimings.size();
m += mmm;
fileText.add("Average Score: " + m);
sender().sendMessage("Score: " + Form.duration(m, 0));
try {
IO.writeAll(report, fileText.toString("\n"));
} catch(IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
sender().sendMessage(C.GREEN + "Done! " + report.getPath());
}
@Decree(description = "Summon an Iris Entity", origin = DecreeOrigin.PLAYER)
public void summon(
@Param(description = "The Iris Entity to spawn")
IrisEntity entity,
@Param(description = "The location at which to spawn the entity", defaultValue = "self")
Vector location
) {
if(!sender().isPlayer()) {
sender().sendMessage(C.RED + "Players only (this is a config error. Ask support to add DecreeOrigin.PLAYER to the command you tried to run)");
return;
}
sender().sendMessage(C.GREEN + "Spawning entity");
entity.spawn(engine(), new Location(world(), location.getX(), location.getY(), location.getZ()));
}
@Decree(description = "Teleport to the active studio world", aliases = "stp", origin = DecreeOrigin.PLAYER, sync = true)
public void tpstudio() {
if(!Iris.service(StudioSVC.class).isProjectOpen()) {
sender().sendMessage(C.RED + "No studio world is open!");
return;
}
if(IrisToolbelt.isIrisWorld(world()) && engine().isStudio()) {
sender().sendMessage(C.RED + "You are already in a studio world!");
return;
}
sender().sendMessage(C.GREEN + "Sending you to the studio world!");
player().teleport(Iris.service(StudioSVC.class).getActiveProject().getActiveProvider().getTarget().getWorld().spawnLocation());
player().setGameMode(GameMode.SPECTATOR);
}
@Decree(description = "Update your dimension projects VSCode workspace")
public void update(
@Param(description = "The dimension to update the workspace of", contextual = true, defaultValue = "default")
IrisDimension dimension
) {
sender().sendMessage(C.GOLD + "Updating Code Workspace for " + dimension.getName() + "...");
if(new IrisProject(dimension.getLoader().getDataFolder()).updateWorkspace()) {
sender().sendMessage(C.GREEN + "Updated Code Workspace for " + dimension.getName());
} else {
sender().sendMessage(C.RED + "Invalid project: " + dimension.getName() + ". Try deleting the code-workspace file and try again.");
}
}
@Decree(aliases = "find-objects", description = "Get information about nearby structures")
public void objects() {
if(!IrisToolbelt.isIrisWorld(player().getWorld())) {
sender().sendMessage(C.RED + "You must be in an Iris world");
return;
}
World world = player().getWorld();
if(!IrisToolbelt.isIrisWorld(world)) {
sender().sendMessage("You must be in an iris world.");
return;
}
KList<Chunk> chunks = new KList<>();
int bx = player().getLocation().getChunk().getX();
int bz = player().getLocation().getChunk().getZ();
try {
Location l = player().getTargetBlockExact(48, FluidCollisionMode.NEVER).getLocation();
int cx = l.getChunk().getX();
int cz = l.getChunk().getZ();
new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + cx, z + cz))).drain();
} catch(Throwable e) {
Iris.reportError(e);
}
new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + bx, z + bz))).drain();
sender().sendMessage("Capturing IGenData from " + chunks.size() + " nearby chunks.");
try {
File ff = Iris.instance.getDataFile("reports/" + M.ms() + ".txt");
PrintWriter pw = new PrintWriter(ff);
pw.println("=== Iris Chunk Report ===");
pw.println("== General Info ==");
pw.println("Iris Version: " + Iris.instance.getDescription().getVersion());
pw.println("Bukkit Version: " + Bukkit.getBukkitVersion());
pw.println("MC Version: " + Bukkit.getVersion());
pw.println("PaperSpigot: " + (PaperLib.isPaper() ? "Yup!" : "Nope!"));
pw.println("Report Captured At: " + new Date());
pw.println("Chunks: (" + chunks.size() + "): ");
for(Chunk i : chunks) {
pw.println("- [" + i.getX() + ", " + i.getZ() + "]");
}
int regions = 0;
long size = 0;
String age = "No idea...";
try {
for(File i : Objects.requireNonNull(new File(world.getWorldFolder(), "region").listFiles())) {
if(i.isFile()) {
size += i.length();
}
}
} catch(Throwable e) {
Iris.reportError(e);
}
try {
FileTime creationTime = (FileTime) Files.getAttribute(world.getWorldFolder().toPath(), "creationTime");
age = hrf(Duration.of(M.ms() - creationTime.toMillis(), ChronoUnit.MILLIS));
} catch(IOException e) {
Iris.reportError(e);
}
KList<String> biomes = new KList<>();
KList<String> caveBiomes = new KList<>();
KMap<String, KMap<String, KList<String>>> objects = new KMap<>();
for(Chunk i : chunks) {
for(int j = 0; j < 16; j += 3) {
for(int k = 0; k < 16; k += 3) {
assert engine() != null;
IrisBiome bb = engine().getSurfaceBiome((i.getX() * 16) + j, (i.getZ() * 16) + k);
IrisBiome bxf = engine().getCaveBiome((i.getX() * 16) + j, (i.getZ() * 16) + k);
biomes.addIfMissing(bb.getName() + " [" + Form.capitalize(bb.getInferredType().name().toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")");
caveBiomes.addIfMissing(bxf.getName() + " (" + bxf.getLoadFile().getName() + ")");
exportObjects(bb, pw, engine(), objects);
exportObjects(bxf, pw, engine(), objects);
}
}
}
regions = Objects.requireNonNull(new File(world.getWorldFolder().getPath() + "/region").list()).length;
pw.println();
pw.println("== World Info ==");
pw.println("World Name: " + world.getName());
pw.println("Age: " + age);
pw.println("Folder: " + world.getWorldFolder().getPath());
pw.println("Regions: " + Form.f(regions));
pw.println("Chunks: max. " + Form.f(regions * 32 * 32));
pw.println("World Size: min. " + Form.fileSize(size));
pw.println();
pw.println("== Biome Info ==");
pw.println("Found " + biomes.size() + " Biome(s): ");
for(String i : biomes) {
pw.println("- " + i);
}
pw.println();
pw.println("== Object Info ==");
for(String i : objects.k()) {
pw.println("- " + i);
for(String j : objects.get(i).k()) {
pw.println(" @ " + j);
for(String k : objects.get(i).get(j)) {
pw.println(" * " + k);
}
}
}
pw.println();
pw.close();
sender().sendMessage("Reported to: " + ff.getPath());
} catch(FileNotFoundException e) {
e.printStackTrace();
Iris.reportError(e);
}
}
private void exportObjects(IrisBiome bb, PrintWriter pw, Engine g, KMap<String, KMap<String, KList<String>>> objects) {
String n1 = bb.getName() + " [" + Form.capitalize(bb.getInferredType().name().toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")";
int m = 0;
KSet<String> stop = new KSet<>();
for(IrisObjectPlacement f : bb.getObjects()) {
m++;
String n2 = "Placement #" + m + " (" + f.getPlace().size() + " possible objects)";
for(String i : f.getPlace()) {
String nn3 = i + ": [ERROR] Failed to find object!";
try {
if(stop.contains(i)) {
continue;
}
File ff = g.getData().getObjectLoader().findFile(i);
BlockVector sz = IrisObject.sampleSize(ff);
nn3 = i + ": size=[" + sz.getBlockX() + "," + sz.getBlockY() + "," + sz.getBlockZ() + "] location=[" + ff.getPath() + "]";
stop.add(i);
} catch(Throwable e) {
Iris.reportError(e);
}
String n3 = nn3;
objects.computeIfAbsent(n1, (k1) -> new KMap<>())
.computeIfAbsent(n2, (k) -> new KList<>()).addIfMissing(n3);
}
}
}
/**
* @return true if server GUIs are not enabled
*/
private boolean noGUI() {
if(!IrisSettings.get().getGui().isUseServerLaunchedGuis()) {
sender().sendMessage(C.RED + "You must have server launched GUIs enabled in the settings!");
return true;
}
return false;
}
/**
* @return true if no studio is open or the player is not in one
*/
private boolean noStudio() {
if(!sender().isPlayer()) {
sender().sendMessage(C.RED + "Players only!");
return true;
}
if(!Iris.service(StudioSVC.class).isProjectOpen()) {
sender().sendMessage(C.RED + "No studio world is open!");
return true;
}
if(!engine().isStudio()) {
sender().sendMessage(C.RED + "You must be in a studio world!");
return true;
}
return false;
}
public void files(File clean, KList<File> files) {
if(clean.isDirectory()) {
for(File i : clean.listFiles()) {
files(i, files);
}
} else if(clean.getName().endsWith(".json")) {
try {
files.add(clean);
} catch(Throwable e) {
Iris.reportError(e);
Iris.error("Failed to beautify " + clean.getAbsolutePath() + " You may have errors in your json!");
}
}
}
private void fixBlocks(JSONObject obj) {
for(String i : obj.keySet()) {
Object o = obj.get(i);
if(i.equals("block") && o instanceof String && !o.toString().trim().isEmpty() && !o.toString().contains(":")) {
obj.put(i, "minecraft:" + o);
}
if(o instanceof JSONObject) {
fixBlocks((JSONObject) o);
} else if(o instanceof JSONArray) {
fixBlocks((JSONArray) o);
}
}
}
private void fixBlocks(JSONArray obj) {
for(int i = 0; i < obj.length(); i++) {
Object o = obj.get(i);
if(o instanceof JSONObject) {
fixBlocks((JSONObject) o);
} else if(o instanceof JSONArray) {
fixBlocks((JSONArray) o);
}
}
}
}

View File

@ -1,153 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.edit.BlockSignal;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.matter.MatterMarker;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Chunk;
import org.bukkit.FluidCollisionMode;
import org.bukkit.Material;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import java.util.concurrent.atomic.AtomicInteger;
@Decree(name = "what", origin = DecreeOrigin.PLAYER, studio = true, description = "Iris What?")
public class CommandWhat implements DecreeExecutor {
@Decree(description = "What is in my hand?", origin = DecreeOrigin.PLAYER)
public void hand() {
try {
BlockData bd = player().getInventory().getItemInMainHand().getType().createBlockData();
if(!bd.getMaterial().equals(Material.AIR)) {
sender().sendMessage("Material: " + C.GREEN + bd.getMaterial().name());
sender().sendMessage("Full: " + C.WHITE + bd.getAsString(true));
} else {
sender().sendMessage("Please hold a block/item");
}
} catch(Throwable e) {
Iris.reportError(e);
Material bd = player().getInventory().getItemInMainHand().getType();
if(!bd.equals(Material.AIR)) {
sender().sendMessage("Material: " + C.GREEN + bd.name());
} else {
sender().sendMessage("Please hold a block/item");
}
}
}
@Decree(description = "What biome am i in?", origin = DecreeOrigin.PLAYER)
public void biome() {
try {
IrisBiome b = engine().getBiome(player().getLocation().getBlockX(), player().getLocation().getBlockY(), player().getLocation().getBlockZ());
sender().sendMessage("IBiome: " + b.getLoadKey() + " (" + b.getDerivative().name() + ")");
} catch(Throwable e) {
Iris.reportError(e);
sender().sendMessage("Non-Iris Biome: " + player().getLocation().getBlock().getBiome().name());
if(player().getLocation().getBlock().getBiome().equals(Biome.CUSTOM)) {
try {
sender().sendMessage("Data Pack Biome: " + INMS.get().getTrueBiomeBaseKey(player().getLocation()) + " (ID: " + INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(player().getLocation())) + ")");
} catch(Throwable ee) {
Iris.reportError(ee);
}
}
}
}
@Decree(description = "What block am i looking at?", origin = DecreeOrigin.PLAYER)
public void block() {
BlockData bd;
try {
bd = player().getTargetBlockExact(128, FluidCollisionMode.NEVER).getBlockData();
} catch(NullPointerException e) {
Iris.reportError(e);
sender().sendMessage("Please look at any block, not at the sky");
bd = null;
}
if(bd != null) {
sender().sendMessage("Material: " + C.GREEN + bd.getMaterial().name());
sender().sendMessage("Full: " + C.WHITE + bd.getAsString(true));
if(B.isStorage(bd)) {
sender().sendMessage(C.YELLOW + "* Storage Block (Loot Capable)");
}
if(B.isLit(bd)) {
sender().sendMessage(C.YELLOW + "* Lit Block (Light Capable)");
}
if(B.isFoliage(bd)) {
sender().sendMessage(C.YELLOW + "* Foliage Block");
}
if(B.isDecorant(bd)) {
sender().sendMessage(C.YELLOW + "* Decorant Block");
}
if(B.isFluid(bd)) {
sender().sendMessage(C.YELLOW + "* Fluid Block");
}
if(B.isFoliagePlantable(bd)) {
sender().sendMessage(C.YELLOW + "* Plantable Foliage Block");
}
if(B.isSolid(bd)) {
sender().sendMessage(C.YELLOW + "* Solid Block");
}
}
}
@Decree(description = "Show markers in chunk", origin = DecreeOrigin.PLAYER)
public void markers(@Param(description = "Marker name such as cave_floor or cave_ceiling") String marker) {
Chunk c = player().getLocation().getChunk();
if(IrisToolbelt.isIrisWorld(c.getWorld())) {
int m = 1;
AtomicInteger v = new AtomicInteger(0);
for(int xxx = c.getX() - 4; xxx <= c.getX() + 4; xxx++) {
for(int zzz = c.getZ() - 4; zzz <= c.getZ() + 4; zzz++) {
IrisToolbelt.access(c.getWorld()).getEngine().getMantle().findMarkers(xxx, zzz, new MatterMarker(marker))
.convert((i) -> i.toLocation(c.getWorld())).forEach((i) -> {
J.s(() -> BlockSignal.of(i.getBlock(), 100));
v.incrementAndGet();
});
}
}
sender().sendMessage("Found " + v.get() + " Nearby Markers (" + marker + ")");
} else {
sender().sendMessage("Iris worlds only.");
}
}
}

View File

@ -1,43 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.edit;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import java.io.Closeable;
public interface BlockEditor extends Closeable {
long last();
void set(int x, int y, int z, BlockData d);
BlockData get(int x, int y, int z);
void setBiome(int x, int z, Biome b);
void setBiome(int x, int y, int z, Biome b);
@Override
void close();
Biome getBiome(int x, int y, int z);
Biome getBiome(int x, int z);
}

View File

@ -1,107 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.edit;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.SR;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;
@SuppressWarnings("InstantiationOfUtilityClass")
public class BlockSignal {
public static final AtomicInteger active = new AtomicInteger(0);
public BlockSignal(Block block, int ticks) {
active.incrementAndGet();
Location tg = block.getLocation().clone().add(0.5, 0, 0.5);
FallingBlock e = block.getWorld().spawnFallingBlock(tg, block.getBlockData());
e.setGravity(false);
e.setInvulnerable(true);
e.setGlowing(true);
e.setDropItem(false);
e.setHurtEntities(false);
e.setSilent(true);
e.setTicksLived(1);
e.setVelocity(new Vector(0, 0, 0));
J.s(() -> {
e.remove();
active.decrementAndGet();
BlockData type = block.getBlockData();
MultiBurst.burst.lazy(() -> {
for(Player i : block.getWorld().getPlayers()) {
i.sendBlockChange(block.getLocation(), block.getBlockData());
}
});
}, ticks);
}
public static void of(Block block, int ticks) {
new BlockSignal(block, ticks);
}
public static void of(Block block) {
of(block, 100);
}
public static Runnable forever(Block block) {
Location tg = block.getLocation().clone().add(0.5, 0, 0.5).clone();
FallingBlock e = block.getWorld().spawnFallingBlock(tg.clone(), block.getBlockData());
e.setGravity(false);
e.setInvulnerable(true);
e.setGlowing(true);
e.teleport(tg.clone());
e.setDropItem(false);
e.setHurtEntities(false);
e.setSilent(true);
e.setTicksLived(1);
e.setVelocity(new Vector(0, 0, 0));
new SR(20) {
@Override
public void run() {
if(e.isDead()) {
cancel();
return;
}
e.setTicksLived(1);
e.teleport(tg.clone());
e.setVelocity(new Vector(0, 0, 0));
}
};
return () -> {
e.remove();
BlockData type = block.getBlockData();
MultiBurst.burst.lazy(() -> {
for(Player i : block.getWorld().getPlayers()) {
i.sendBlockChange(block.getLocation(), block.getBlockData());
}
});
};
}
}

View File

@ -1,75 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.edit;
import com.volmit.iris.util.math.M;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
@SuppressWarnings("ClassCanBeRecord")
public class BukkitBlockEditor implements BlockEditor {
private final World world;
public BukkitBlockEditor(World world) {
this.world = world;
}
@Override
public void set(int x, int y, int z, BlockData d) {
world.getBlockAt(x, y, z).setBlockData(d, false);
}
@Override
public BlockData get(int x, int y, int z) {
return world.getBlockAt(x, y, z).getBlockData();
}
@Override
public void close() {
}
@Override
public long last() {
return M.ms();
}
@SuppressWarnings("deprecation")
@Override
public void setBiome(int x, int z, Biome b) {
world.setBiome(x, z, b);
}
@Override
public void setBiome(int x, int y, int z, Biome b) {
world.setBiome(x, y, z, b);
}
@Override
public Biome getBiome(int x, int y, int z) {
return world.getBiome(x, y, z);
}
@SuppressWarnings("deprecation")
@Override
public Biome getBiome(int x, int z) {
return world.getBiome(x, z);
}
}

View File

@ -1,127 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.edit;
import com.volmit.iris.Iris;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import lombok.Data;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.block.Block;
@SuppressWarnings("ALL")
@Data
public class DustRevealer {
private final Engine engine;
private final World world;
private final BlockPosition block;
private final String key;
private final KList<BlockPosition> hits;
public DustRevealer(Engine engine, World world, BlockPosition block, String key, KList<BlockPosition> hits) {
this.engine = engine;
this.world = world;
this.block = block;
this.key = key;
this.hits = hits;
J.s(() -> {
new BlockSignal(world.getBlockAt(block.getX(), block.getY(), block.getZ()), 10);
if(M.r(0.25)) {
world.playSound(block.toBlock(world).getLocation(), Sound.BLOCK_AMETHYST_BLOCK_CHIME, 1f, RNG.r.f(0.2f, 2f));
}
J.a(() -> {
while(BlockSignal.active.get() > 128) {
J.sleep(5);
}
try {
is(new BlockPosition(block.getX() + 1, block.getY(), block.getZ()));
is(new BlockPosition(block.getX() - 1, block.getY(), block.getZ()));
is(new BlockPosition(block.getX(), block.getY() + 1, block.getZ()));
is(new BlockPosition(block.getX(), block.getY() - 1, block.getZ()));
is(new BlockPosition(block.getX(), block.getY(), block.getZ() + 1));
is(new BlockPosition(block.getX(), block.getY(), block.getZ() - 1));
is(new BlockPosition(block.getX() + 1, block.getY(), block.getZ() + 1));
is(new BlockPosition(block.getX() + 1, block.getY(), block.getZ() - 1));
is(new BlockPosition(block.getX() - 1, block.getY(), block.getZ() + 1));
is(new BlockPosition(block.getX() - 1, block.getY(), block.getZ() - 1));
is(new BlockPosition(block.getX() + 1, block.getY() + 1, block.getZ()));
is(new BlockPosition(block.getX() + 1, block.getY() - 1, block.getZ()));
is(new BlockPosition(block.getX() - 1, block.getY() + 1, block.getZ()));
is(new BlockPosition(block.getX() - 1, block.getY() - 1, block.getZ()));
is(new BlockPosition(block.getX(), block.getY() + 1, block.getZ() - 1));
is(new BlockPosition(block.getX(), block.getY() + 1, block.getZ() + 1));
is(new BlockPosition(block.getX(), block.getY() - 1, block.getZ() - 1));
is(new BlockPosition(block.getX(), block.getY() - 1, block.getZ() + 1));
is(new BlockPosition(block.getX() - 1, block.getY() + 1, block.getZ() - 1));
is(new BlockPosition(block.getX() - 1, block.getY() + 1, block.getZ() + 1));
is(new BlockPosition(block.getX() - 1, block.getY() - 1, block.getZ() - 1));
is(new BlockPosition(block.getX() - 1, block.getY() - 1, block.getZ() + 1));
is(new BlockPosition(block.getX() + 1, block.getY() + 1, block.getZ() - 1));
is(new BlockPosition(block.getX() + 1, block.getY() + 1, block.getZ() + 1));
is(new BlockPosition(block.getX() + 1, block.getY() - 1, block.getZ() - 1));
is(new BlockPosition(block.getX() + 1, block.getY() - 1, block.getZ() + 1));
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
});
}, RNG.r.i(2, 8));
}
public static void spawn(Block block, VolmitSender sender) {
World world = block.getWorld();
Engine access = IrisToolbelt.access(world).getEngine();
if(access != null) {
String a = access.getObjectPlacementKey(block.getX(), block.getY() - block.getWorld().getMinHeight(), block.getZ());
if(a != null) {
world.playSound(block.getLocation(), Sound.ITEM_LODESTONE_COMPASS_LOCK, 1f, 0.1f);
sender.sendMessage("Found object " + a);
J.a(() -> {
new DustRevealer(access, world, new BlockPosition(block.getX(), block.getY(), block.getZ()), a, new KList<>());
});
}
}
}
private boolean is(BlockPosition a) {
int betterY = a.getY() - world.getMinHeight();
if(isValidTry(a) && engine.getObjectPlacementKey(a.getX(), betterY, a.getZ()) != null && engine.getObjectPlacementKey(a.getX(), betterY, a.getZ()).equals(key)) {
hits.add(a);
new DustRevealer(engine, world, a, key, hits);
return true;
}
return false;
}
private boolean isValidTry(BlockPosition b) {
return !hits.contains(b);
}
}

View File

@ -1,264 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.edit;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.volmit.iris.Iris;
import com.volmit.iris.core.service.WandSVC;
import com.volmit.iris.engine.object.IrisDirection;
import com.volmit.iris.engine.object.IrisJigsawPiece;
import com.volmit.iris.engine.object.IrisJigsawPieceConnector;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisPosition;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.Cuboid;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.util.Vector;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutionException;
public class JigsawEditor implements Listener {
public static final KMap<Player, JigsawEditor> editors = new KMap<>();
private final Player player;
private final IrisObject object;
private final File targetSaveLocation;
private final IrisJigsawPiece piece;
private final Location origin;
private final Cuboid cuboid;
private final int ticker;
private final KMap<IrisPosition, Runnable> falling = new KMap<>();
private final ChronoLatch cl = new ChronoLatch(100);
private Location target;
public JigsawEditor(Player player, IrisJigsawPiece piece, IrisObject object, File saveLocation) {
if(editors.containsKey(player)) {
editors.get(player).close();
}
editors.put(player, this);
if(object == null)
{
throw new RuntimeException("Object is null! " + piece.getObject());
}
this.object = object;
this.player = player;
origin = player.getLocation().clone().add(0, 7, 0);
target = origin;
this.targetSaveLocation = saveLocation;
this.piece = piece == null ? new IrisJigsawPiece() : piece;
this.piece.setObject(object.getLoadKey());
cuboid = new Cuboid(origin.clone(), origin.clone().add(object.getW() - 1, object.getH() - 1, object.getD() - 1));
ticker = J.sr(this::onTick, 0);
J.s(() -> object.placeCenterY(origin));
Iris.instance.registerListener(this);
}
@EventHandler
public void on(PlayerMoveEvent e) {
if(e.getPlayer().equals(player)) {
try {
target = player.getTargetBlockExact(7).getLocation();
} catch(Throwable ex) {
Iris.reportError(ex);
target = player.getLocation();
return;
}
if(cuboid.contains(target)) {
for(IrisPosition i : falling.k()) {
Location at = toLocation(i);
if(at.equals(target)) {
falling.remove(i).run();
}
}
}
}
}
public Location toLocation(IrisPosition i) {
return origin.clone()
.add(new Vector(i.getX(), i.getY(), i.getZ()))
.add(object.getCenter())
.getBlock()
.getLocation();
}
public IrisPosition toPosition(Location l) {
return new IrisPosition(l.clone().getBlock().getLocation()
.subtract(origin.clone())
.subtract(object.getCenter())
.add(1, 1, 1)
.toVector());
}
@EventHandler
public void on(PlayerInteractEvent e) {
if(e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
if(e.getClickedBlock() != null && cuboid.contains(e.getClickedBlock().getLocation()) && e.getPlayer().equals(player)) {
IrisPosition pos = toPosition(e.getClickedBlock().getLocation());
IrisJigsawPieceConnector connector = null;
for(IrisJigsawPieceConnector i : piece.getConnectors()) {
if(i.getPosition().equals(pos)) {
connector = i;
break;
}
}
if(!player.isSneaking() && connector == null) {
connector = new IrisJigsawPieceConnector();
connector.setDirection(IrisDirection.getDirection(e.getBlockFace()));
connector.setPosition(pos);
piece.getConnectors().add(connector);
player.playSound(e.getClickedBlock().getLocation(), Sound.ENTITY_ITEM_FRAME_ADD_ITEM, 1f, 1f);
} else if(player.isSneaking() && connector != null) {
piece.getConnectors().remove(connector);
player.playSound(e.getClickedBlock().getLocation(), Sound.ENTITY_ITEM_FRAME_REMOVE_ITEM, 1f, 1f);
} else if(connector != null && !player.isSneaking()) {
connector.setDirection(IrisDirection.getDirection(e.getBlockFace()));
player.playSound(e.getClickedBlock().getLocation(), Sound.ENTITY_ITEM_FRAME_ROTATE_ITEM, 1f, 1f);
}
}
}
}
private void removeKey(JSONObject o, String... path)
{
if(path.length == 1)
{
o.remove(path[0]);
return;
}
List<String> s = new java.util.ArrayList<>(List.of(path));
s.remove(0);
removeKey(o.getJSONObject(path[0]), s.toArray(new String[0]));
}
private List<JSONObject> getObjectsInArray(JSONObject a, String key)
{
KList<JSONObject> o = new KList<>();
for(int i = 0; i < a.getJSONArray(key).length(); i++)
{
o.add(a.getJSONArray(key).getJSONObject(i));
}
return o;
}
public void close() {
exit();
try {
JSONObject j = new JSONObject(new Gson().toJson(piece));
// Remove sub-key
removeKey(j, "placementOptions", "translateCenter"); // should work
J.attempt(() -> j.getJSONObject("placementOptions").remove("translateCenter")); // otherwise
// remove root key
removeKey(j, "placementOptions"); // should work
j.remove("placementOptions"); // otherwise
// Remove key in all objects in array
for(JSONObject i : getObjectsInArray(j, "connectors"))
{
removeKey(i, "rotateConnector");
}
IO.writeAll(targetSaveLocation, j.toString(4));
} catch(IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
}
public void exit() {
J.car(ticker);
Iris.instance.unregisterListener(this);
try {
J.sfut(() -> {
object.unplaceCenterY(origin);
falling.v().forEach(Runnable::run);
}).get();
} catch(InterruptedException | ExecutionException e) {
e.printStackTrace();
}
editors.remove(player);
}
public void onTick() {
if(cl.flip()) {
Iris.service(WandSVC.class).draw(cuboid, player);
f:
for(IrisPosition i : falling.k()) {
for(IrisJigsawPieceConnector j : piece.getConnectors()) {
if(j.getPosition().equals(i)) {
continue f;
}
}
falling.remove(i).run();
}
for(IrisJigsawPieceConnector i : piece.getConnectors()) {
IrisPosition pos = i.getPosition();
Location at = toLocation(pos);
Vector dir = i.getDirection().toVector().clone();
for(int ix = 0; ix < RNG.r.i(1, 3); ix++) {
at.getWorld().spawnParticle(Particle.SOUL_FIRE_FLAME, at.clone().getBlock().getLocation().add(0.25, 0.25, 0.25).add(RNG.r.d(0.5), RNG.r.d(0.5), RNG.r.d(0.5)), 0, dir.getX(), dir.getY(), dir.getZ(), 0.092 + RNG.r.d(-0.03, 0.08));
}
if(at.getBlock().getLocation().equals(target)) {
continue;
}
if(!falling.containsKey(pos)) {
if(at.getBlock().getType().isAir()) {
at.getBlock().setType(Material.STONE);
}
falling.put(pos, BlockSignal.forever(at.getBlock()));
}
}
}
}
}

View File

@ -1,47 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.events;
import com.volmit.iris.engine.framework.Engine;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
public class IrisEngineEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private Engine engine;
public IrisEngineEvent() {
super(true);
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -1,39 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.events;
import com.volmit.iris.engine.framework.Engine;
import org.bukkit.event.HandlerList;
public class IrisEngineHotloadEvent extends IrisEngineEvent {
private static final HandlerList handlers = new HandlerList();
public IrisEngineHotloadEvent(Engine engine) {
super(engine);
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -1,350 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui;
import com.volmit.iris.Iris;
import com.volmit.iris.core.events.IrisEngineHotloadEvent;
import com.volmit.iris.engine.object.NoiseStyle;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.function.Function2;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import javax.imageio.ImageIO;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JViewport;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
public class NoiseExplorerGUI extends JPanel implements MouseWheelListener, Listener {
private static final long serialVersionUID = 2094606939770332040L;
static JComboBox<String> combo;
@SuppressWarnings("CanBeFinal")
static boolean hd = false;
static double ascale = 10;
static double oxp = 0;
static double ozp = 0;
static double mxx = 0;
static double mzz = 0;
@SuppressWarnings("CanBeFinal")
static boolean down = false;
@SuppressWarnings("CanBeFinal")
RollingSequence r = new RollingSequence(20);
@SuppressWarnings("CanBeFinal")
boolean colorMode = true;
double scale = 1;
CNG cng = NoiseStyle.STATIC.create(new RNG(RNG.r.nextLong()));
@SuppressWarnings("CanBeFinal")
MultiBurst gx = MultiBurst.burst;
ReentrantLock l = new ReentrantLock();
BufferedImage img;
int w = 0;
int h = 0;
Function2<Double, Double, Double> generator;
Supplier<Function2<Double, Double, Double>> loader;
double ox = 0; //Offset X
double oz = 0; //Offset Y
double mx = 0;
double mz = 0;
double lx = Double.MAX_VALUE; //MouseX
double lz = Double.MAX_VALUE; //MouseY
double t;
double tz;
public NoiseExplorerGUI() {
Iris.instance.registerListener(this);
addMouseWheelListener(this);
addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseMoved(MouseEvent e) {
Point cp = e.getPoint();
lx = (cp.getX());
lz = (cp.getY());
mx = lx;
mz = lz;
}
@Override
public void mouseDragged(MouseEvent e) {
Point cp = e.getPoint();
ox += (lx - cp.getX()) * scale;
oz += (lz - cp.getY()) * scale;
lx = cp.getX();
lz = cp.getY();
}
});
}
private static void createAndShowGUI(Supplier<Function2<Double, Double, Double>> loader, String genName) {
JFrame frame = new JFrame("Noise Explorer: " + genName);
NoiseExplorerGUI nv = new NoiseExplorerGUI();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
JLayeredPane pane = new JLayeredPane();
nv.setSize(new Dimension(1440, 820));
pane.add(nv, 1, 0);
nv.loader = loader;
nv.generator = loader.get();
frame.add(pane);
File file = Iris.getCached("Iris Icon", "https://raw.githubusercontent.com/VolmitSoftware/Iris/master/icon.png");
if(file != null) {
try {
frame.setIconImage(ImageIO.read(file));
} catch(IOException e) {
Iris.reportError(e);
}
}
frame.setSize(1440, 820);
frame.setVisible(true);
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("Noise Explorer");
NoiseExplorerGUI nv = new NoiseExplorerGUI();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
KList<String> li = new KList<>(NoiseStyle.values()).toStringList();
combo = new JComboBox<>(li.toArray(new String[0]));
combo.setSelectedItem("STATIC");
combo.setFocusable(false);
combo.addActionListener(e -> {
@SuppressWarnings("unchecked")
String b = (String) (((JComboBox<String>) e.getSource()).getSelectedItem());
NoiseStyle s = NoiseStyle.valueOf(b);
nv.cng = s.create(RNG.r.nextParallelRNG(RNG.r.imax()));
});
combo.setSize(500, 30);
JLayeredPane pane = new JLayeredPane();
nv.setSize(new Dimension(1440, 820));
pane.add(nv, 1, 0);
pane.add(combo, 2, 0);
frame.add(pane);
File file = Iris.getCached("Iris Icon", "https://raw.githubusercontent.com/VolmitSoftware/Iris/master/icon.png");
if(file != null) {
try {
frame.setIconImage(ImageIO.read(file));
} catch(IOException e) {
Iris.reportError(e);
}
}
frame.setSize(1440, 820);
frame.setVisible(true);
frame.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
Iris.instance.unregisterListener(nv);
}
});
}
public static void launch(Supplier<Function2<Double, Double, Double>> gen, String genName) {
EventQueue.invokeLater(() -> createAndShowGUI(gen, genName));
}
public static void launch() {
EventQueue.invokeLater(NoiseExplorerGUI::createAndShowGUI);
}
@EventHandler
public void on(IrisEngineHotloadEvent e) {
if(generator != null)
generator = loader.get();
}
public void mouseWheelMoved(MouseWheelEvent e) {
int notches = e.getWheelRotation();
if(e.isControlDown()) {
t = t + ((0.0025 * t) * notches);
return;
}
scale = scale + ((0.044 * scale) * notches);
scale = Math.max(scale, 0.00001);
}
@Override
public void paint(Graphics g) {
if(scale < ascale) {
ascale -= Math.abs(scale - ascale) * 0.16;
}
if(scale > ascale) {
ascale += Math.abs(ascale - scale) * 0.16;
}
if(t < tz) {
tz -= Math.abs(t - tz) * 0.29;
}
if(t > tz) {
tz += Math.abs(tz - t) * 0.29;
}
if(ox < oxp) {
oxp -= Math.abs(ox - oxp) * 0.16;
}
if(ox > oxp) {
oxp += Math.abs(oxp - ox) * 0.16;
}
if(oz < ozp) {
ozp -= Math.abs(oz - ozp) * 0.16;
}
if(oz > ozp) {
ozp += Math.abs(ozp - oz) * 0.16;
}
if(mx < mxx) {
mxx -= Math.abs(mx - mxx) * 0.16;
}
if(mx > mxx) {
mxx += Math.abs(mxx - mx) * 0.16;
}
if(mz < mzz) {
mzz -= Math.abs(mz - mzz) * 0.16;
}
if(mz > mzz) {
mzz += Math.abs(mzz - mz) * 0.16;
}
PrecisionStopwatch p = PrecisionStopwatch.start();
int accuracy = hd ? 1 : M.clip((r.getAverage() / 12D), 2D, 128D).intValue();
accuracy = down ? accuracy * 4 : accuracy;
int v = 1000;
if(g instanceof Graphics2D gg) {
if(getParent().getWidth() != w || getParent().getHeight() != h) {
w = getParent().getWidth();
h = getParent().getHeight();
img = null;
}
if(img == null) {
img = new BufferedImage(w / accuracy, h / accuracy, BufferedImage.TYPE_INT_RGB);
}
BurstExecutor e = gx.burst(w);
for(int x = 0; x < w / accuracy; x++) {
int xx = x;
int finalAccuracy = accuracy;
e.queue(() -> {
for(int z = 0; z < h / finalAccuracy; z++) {
double n = generator != null ? generator.apply(((xx * finalAccuracy) * ascale) + oxp, ((z * finalAccuracy) * ascale) + ozp) : cng.noise(((xx * finalAccuracy) * ascale) + oxp, ((z * finalAccuracy) * ascale) + ozp);
n = n > 1 ? 1 : n < 0 ? 0 : n;
try {
Color color = colorMode ? Color.getHSBColor((float) (n), 1f - (float) (n * n * n * n * n * n), 1f - (float) n) : Color.getHSBColor(0f, 0f, (float) n);
int rgb = color.getRGB();
img.setRGB(xx, z, rgb);
} catch(Throwable xxx) {
}
}
});
}
e.complete();
gg.drawImage(img, 0, 0, getParent().getWidth() * accuracy, getParent().getHeight() * accuracy, (img, infoflags, x, y, width, height) -> true);
}
p.end();
t += 1D;
r.put(p.getMilliseconds());
if(!isVisible()) {
return;
}
if(!getParent().isVisible()) {
return;
}
if(!getParent().getParent().isVisible()) {
return;
}
EventQueue.invokeLater(() ->
{
J.sleep((long) Math.max(0, 32 - r.getAverage()));
repaint();
});
}
static class HandScrollListener extends MouseAdapter {
private static final Point pp = new Point();
@Override
public void mouseDragged(MouseEvent e) {
JViewport vport = (JViewport) e.getSource();
JComponent label = (JComponent) vport.getView();
Point cp = e.getPoint();
Point vp = vport.getViewPosition();
vp.translate(pp.x - cp.x, pp.y - cp.y);
label.scrollRectToVisible(new Rectangle(vp, vport.getSize()));
pp.setLocation(cp);
}
@Override
public void mousePressed(MouseEvent e) {
pp.setLocation(e.getPoint());
}
}
}

View File

@ -1,441 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.IrisPregenerator;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.format.MemoryMonitor;
import com.volmit.iris.util.function.Consumer2;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
public class PregeneratorJob implements PregenListener {
private static final Color COLOR_EXISTS = parseColor("#4d7d5b");
private static final Color COLOR_BLACK = parseColor("#4d7d5b");
private static final Color COLOR_MANTLE = parseColor("#3c2773");
private static final Color COLOR_GENERATING = parseColor("#66967f");
private static final Color COLOR_NETWORK = parseColor("#a863c2");
private static final Color COLOR_NETWORK_GENERATING = parseColor("#836b8c");
private static final Color COLOR_GENERATED = parseColor("#65c295");
private static final Color COLOR_CLEANED = parseColor("#34eb93");
public static PregeneratorJob instance;
private final MemoryMonitor monitor;
private final PregenTask task;
private final boolean saving;
private final KList<Consumer<Double>> onProgress = new KList<>();
private final KList<Runnable> whenDone = new KList<>();
private final IrisPregenerator pregenerator;
private final Position2 min;
private final Position2 max;
private JFrame frame;
private PregenRenderer renderer;
private int rgc = 0;
private final ChronoLatch cl = new ChronoLatch(TimeUnit.MINUTES.toMillis(1));
private String[] info;
private final Engine engine;
public PregeneratorJob(PregenTask task, PregeneratorMethod method, Engine engine) {
this.engine = engine;
instance = this;
monitor = new MemoryMonitor(50);
saving = false;
info = new String[] {"Initializing..."};
this.task = task;
this.pregenerator = new IrisPregenerator(task, method, this);
max = new Position2(0, 0);
min = new Position2(0, 0);
KList<Runnable> draw = new KList<>();
task.iterateRegions((xx, zz) -> {
min.setX(Math.min(xx << 5, min.getX()));
min.setZ(Math.min(zz << 5, min.getZ()));
max.setX(Math.max((xx << 5) + 31, max.getX()));
max.setZ(Math.max((zz << 5) + 31, max.getZ()));
});
if(IrisSettings.get().getGui().isUseServerLaunchedGuis()) {
open();
}
J.a(this.pregenerator::start, 20);
}
public Mantle getMantle() {
return pregenerator.getMantle();
}
public static boolean shutdownInstance() {
if(instance == null) {
return false;
}
J.a(() -> instance.pregenerator.close());
return true;
}
public static PregeneratorJob getInstance() {
return instance;
}
public static boolean pauseResume() {
if(instance == null) {
return false;
}
if(isPaused()) {
instance.pregenerator.resume();
} else {
instance.pregenerator.pause();
}
return true;
}
public static boolean isPaused() {
if(instance == null) {
return true;
}
return instance.paused();
}
private static Color parseColor(String c) {
String v = (c.startsWith("#") ? c : "#" + c).trim();
try {
return Color.decode(v);
} catch(Throwable e) {
Iris.reportError(e);
Iris.error("Error Parsing 'color', (" + c + ")");
}
return Color.RED;
}
public PregeneratorJob onProgress(Consumer<Double> c) {
onProgress.add(c);
return this;
}
public PregeneratorJob whenDone(Runnable r) {
whenDone.add(r);
return this;
}
public void drawRegion(int x, int z, Color color) {
J.a(() -> {
PregenTask.iterateRegion(x, z, (xx, zz) -> {
draw(xx, zz, color);
J.sleep(3);
});
});
}
public void draw(int x, int z, Color color) {
try {
if(renderer != null && frame != null && frame.isVisible()) {
renderer.func.accept(new Position2(x, z), color);
}
} catch(Throwable ignored) {
}
}
public void stop() {
J.a(() -> {
pregenerator.close();
close();
instance = null;
});
}
public void close() {
J.a(() -> {
try {
monitor.close();
J.sleep(3000);
frame.setVisible(false);
} catch(Throwable e) {
}
});
}
public void open() {
J.a(() -> {
try {
frame = new JFrame("Pregen View");
renderer = new PregenRenderer();
frame.addKeyListener(renderer);
renderer.l = new ReentrantLock();
renderer.frame = frame;
renderer.job = this;
renderer.func = (c, b) ->
{
renderer.l.lock();
renderer.order.add(() -> renderer.draw(c, b, renderer.bg));
renderer.l.unlock();
};
frame.add(renderer);
frame.setSize(1000, 1000);
frame.setVisible(true);
} catch(Throwable e) {
}
});
}
@Override
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method) {
info = new String[] {
(paused() ? "PAUSED" : (saving ? "Saving... " : "Generating")) + " " + Form.f(generated) + " of " + Form.f(totalChunks) + " (" + Form.pc(percent, 0) + " Complete)",
"Speed: " + Form.f(chunksPerSecond, 0) + " Chunks/s, " + Form.f(regionsPerMinute, 1) + " Regions/m, " + Form.f(chunksPerMinute, 0) + " Chunks/m",
Form.duration(eta, 2) + " Remaining " + " (" + Form.duration(elapsed, 2) + " Elapsed)",
"Generation Method: " + method,
"Memory: " + Form.memSize(monitor.getUsedBytes(), 2) + " (" + Form.pc(monitor.getUsagePercent(), 0) + ") Pressure: " + Form.memSize(monitor.getPressure(), 0) + "/s",
};
for(Consumer<Double> i : onProgress) {
i.accept(percent);
}
}
@Override
public void onChunkGenerating(int x, int z) {
if(engine != null) {
return;
}
draw(x, z, COLOR_GENERATING);
}
@Override
public void onChunkGenerated(int x, int z) {
if(engine != null) {
draw(x, z, engine.draw((x << 4) + 8, (z << 4) + 8));
return;
}
draw(x, z, COLOR_GENERATED);
}
@Override
public void onRegionGenerated(int x, int z) {
shouldGc();
rgc++;
}
private void shouldGc() {
if(cl.flip() && rgc > 16) {
System.gc();
}
}
@Override
public void onRegionGenerating(int x, int z) {
}
@Override
public void onChunkCleaned(int x, int z) {
//draw(x, z, COLOR_CLEANED);
}
@Override
public void onRegionSkipped(int x, int z) {
}
@Override
public void onNetworkStarted(int x, int z) {
drawRegion(x, z, COLOR_NETWORK);
}
@Override
public void onNetworkFailed(int x, int z) {
}
@Override
public void onNetworkReclaim(int revert) {
}
@Override
public void onNetworkGeneratedChunk(int x, int z) {
draw(x, z, COLOR_NETWORK_GENERATING);
}
@Override
public void onNetworkDownloaded(int x, int z) {
drawRegion(x, z, COLOR_NETWORK);
}
@Override
public void onClose() {
close();
instance = null;
whenDone.forEach(Runnable::run);
}
@Override
public void onSaving() {
}
@Override
public void onChunkExistsInRegionGen(int x, int z) {
if(engine != null) {
draw(x, z, engine.draw((x << 4) + 8, (z << 4) + 8));
return;
}
draw(x, z, COLOR_EXISTS);
}
private Position2 getMax() {
return max;
}
private Position2 getMin() {
return min;
}
private boolean paused() {
return pregenerator.paused();
}
private String[] getProgress() {
return info;
}
public static class PregenRenderer extends JPanel implements KeyListener {
private static final long serialVersionUID = 2094606939770332040L;
private final KList<Runnable> order = new KList<>();
private final int res = 512;
private final BufferedImage image = new BufferedImage(res, res, BufferedImage.TYPE_INT_RGB);
Graphics2D bg;
private PregeneratorJob job;
private ReentrantLock l;
private Consumer2<Position2, Color> func;
private JFrame frame;
public PregenRenderer() {
}
public void paint(int x, int z, Color c) {
func.accept(new Position2(x, z), c);
}
@Override
public void paint(Graphics gx) {
Graphics2D g = (Graphics2D) gx;
bg = (Graphics2D) image.getGraphics();
l.lock();
while(order.isNotEmpty()) {
try {
order.pop().run();
} catch(Throwable e) {
Iris.reportError(e);
}
}
l.unlock();
g.drawImage(image, 0, 0, getParent().getWidth(), getParent().getHeight(), (img, infoflags, x, y, width, height) -> true);
g.setColor(Color.WHITE);
g.setFont(new Font("Hevetica", Font.BOLD, 13));
String[] prog = job.getProgress();
int h = g.getFontMetrics().getHeight() + 5;
int hh = 20;
if(job.paused()) {
g.drawString("PAUSED", 20, hh += h);
g.drawString("Press P to Resume", 20, hh += h);
} else {
for(String i : prog) {
g.drawString(i, 20, hh += h);
}
g.drawString("Press P to Pause", 20, hh += h);
}
J.sleep(IrisSettings.get().getGui().isMaximumPregenGuiFPS() ? 4 : 250);
repaint();
}
private void draw(Position2 p, Color c, Graphics2D bg) {
double pw = M.lerpInverse(job.getMin().getX(), job.getMax().getX(), p.getX());
double ph = M.lerpInverse(job.getMin().getZ(), job.getMax().getZ(), p.getZ());
double pwa = M.lerpInverse(job.getMin().getX(), job.getMax().getX(), p.getX() + 1);
double pha = M.lerpInverse(job.getMin().getZ(), job.getMax().getZ(), p.getZ() + 1);
int x = (int) M.lerp(0, res, pw);
int z = (int) M.lerp(0, res, ph);
int xa = (int) M.lerp(0, res, pwa);
int za = (int) M.lerp(0, res, pha);
bg.setColor(c);
bg.fillRect(x, z, xa - x, za - z);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_P) {
PregeneratorJob.pauseResume();
}
}
public void close() {
frame.setVisible(false);
}
}
}

View File

@ -1,845 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui;
import com.volmit.iris.Iris;
import com.volmit.iris.core.gui.components.IrisRenderer;
import com.volmit.iris.core.gui.components.RenderType;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.IrisComplex;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.engine.object.IrisWorld;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.O;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.Location;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.MouseInputListener;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.BiFunction;
public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener, MouseMotionListener, MouseInputListener {
private static final long serialVersionUID = 2094606939770332040L;
private final KList<LivingEntity> lastEntities = new KList<>();
private final KMap<String, Long> notifications = new KMap<>();
private final ChronoLatch centities = new ChronoLatch(1000);
private final RollingSequence rs = new RollingSequence(512);
private final O<Integer> m = new O<>();
private final KMap<BlockPosition, BufferedImage> positions = new KMap<>();
private final KMap<BlockPosition, BufferedImage> fastpositions = new KMap<>();
private final KSet<BlockPosition> working = new KSet<>();
private final KSet<BlockPosition> workingfast = new KSet<>();
double tfps = 240D;
int ltc = 3;
private RenderType currentType = RenderType.BIOME;
private boolean help = true;
private boolean helpIgnored = false;
private boolean shift = false;
private Player player = null;
private boolean debug = false;
private boolean control = false;
private boolean eco = false;
private boolean lowtile = false;
private boolean follow = false;
private boolean alt = false;
private IrisRenderer renderer;
private IrisWorld world;
private double velocity = 0;
private int lowq = 12;
private double scale = 128;
private double mscale = 4D;
private int w = 0;
private int h = 0;
private double lx = 0;
private double lz = 0;
private double ox = 0;
private double oz = 0;
private double hx = 0;
private double hz = 0;
private double oxp = 0;
private double ozp = 0;
private Engine engine;
private int tid = 0;
private final ExecutorService e = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), r -> {
tid++;
Thread t = new Thread(r);
t.setName("Iris HD Renderer " + tid);
t.setPriority(Thread.MIN_PRIORITY);
t.setUncaughtExceptionHandler((et, e) ->
{
Iris.info("Exception encountered in " + et.getName());
e.printStackTrace();
});
return t;
});
private final ExecutorService eh = Executors.newFixedThreadPool(ltc, r -> {
tid++;
Thread t = new Thread(r);
t.setName("Iris Renderer " + tid);
t.setPriority(Thread.NORM_PRIORITY);
t.setUncaughtExceptionHandler((et, e) ->
{
Iris.info("Exception encountered in " + et.getName());
e.printStackTrace();
});
return t;
});
private BufferedImage texture;
public VisionGUI(JFrame frame) {
m.set(8);
rs.put(1);
addMouseWheelListener(this);
addMouseMotionListener(this);
addMouseListener(this);
frame.addKeyListener(this);
J.a(() -> {
J.sleep(10000);
if(!helpIgnored && help) {
help = false;
}
});
frame.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
e.shutdown();
eh.shutdown();
}
});
}
private static void createAndShowGUI(Engine r, int s, IrisWorld world) {
JFrame frame = new JFrame("Vision");
VisionGUI nv = new VisionGUI(frame);
nv.world = world;
nv.engine = r;
nv.renderer = new IrisRenderer(r);
frame.add(nv);
frame.setSize(1440, 820);
frame.setVisible(true);
File file = Iris.getCached("Iris Icon", "https://raw.githubusercontent.com/VolmitSoftware/Iris/master/icon.png");
if(file != null) {
try {
nv.texture = ImageIO.read(file);
frame.setIconImage(ImageIO.read(file));
} catch(IOException e) {
Iris.reportError(e);
}
}
}
public static void launch(Engine g, int i) {
J.a(() ->
createAndShowGUI(g, i, g.getWorld()));
}
public boolean updateEngine() {
if(engine.isClosed()) {
if(world.hasRealWorld()) {
try {
engine = IrisToolbelt.access(world.realWorld()).getEngine();
return !engine.isClosed();
} catch(Throwable e) {
}
}
}
return false;
}
@Override
public void mouseMoved(MouseEvent e) {
Point cp = e.getPoint();
lx = (cp.getX());
lz = (cp.getY());
}
@Override
public void mouseDragged(MouseEvent e) {
Point cp = e.getPoint();
ox += (lx - cp.getX()) * scale;
oz += (lz - cp.getY()) * scale;
lx = cp.getX();
lz = cp.getY();
}
public int getColor(double wx, double wz) {
BiFunction<Double, Double, Integer> colorFunction = (d, dx) -> Color.black.getRGB();
switch(currentType) {
case BIOME, DECORATOR_LOAD, OBJECT_LOAD, LAYER_LOAD -> colorFunction = (x, z) -> engine.getComplex().getTrueBiomeStream().get(x, z).getColor(engine, currentType).getRGB();
case BIOME_LAND -> colorFunction = (x, z) -> engine.getComplex().getLandBiomeStream().get(x, z).getColor(engine, currentType).getRGB();
case BIOME_SEA -> colorFunction = (x, z) -> engine.getComplex().getSeaBiomeStream().get(x, z).getColor(engine, currentType).getRGB();
case REGION -> colorFunction = (x, z) -> engine.getComplex().getRegionStream().get(x, z).getColor(engine.getComplex(), currentType).getRGB();
case CAVE_LAND -> colorFunction = (x, z) -> engine.getComplex().getCaveBiomeStream().get(x, z).getColor(engine, currentType).getRGB();
case HEIGHT -> colorFunction = (x, z) -> Color.getHSBColor(engine.getComplex().getHeightStream().get(x, z).floatValue(), 100, 100).getRGB();
}
return colorFunction.apply(wx, wz);
}
public void notify(String s) {
notifications.put(s, M.ms() + 2500);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SHIFT) {
shift = true;
}
if(e.getKeyCode() == KeyEvent.VK_CONTROL) {
control = true;
}
if(e.getKeyCode() == KeyEvent.VK_SEMICOLON) {
debug = true;
}
if(e.getKeyCode() == KeyEvent.VK_SLASH) {
help = true;
helpIgnored = true;
}
if(e.getKeyCode() == KeyEvent.VK_ALT) {
alt = true;
}
}
@Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SEMICOLON) {
debug = false;
}
if(e.getKeyCode() == KeyEvent.VK_SHIFT) {
shift = false;
}
if(e.getKeyCode() == KeyEvent.VK_CONTROL) {
control = false;
}
if(e.getKeyCode() == KeyEvent.VK_SLASH) {
help = false;
helpIgnored = true;
}
if(e.getKeyCode() == KeyEvent.VK_ALT) {
alt = false;
}
// Pushes
if(e.getKeyCode() == KeyEvent.VK_F) {
follow = !follow;
if(player != null && follow) {
notify("Following " + player.getName() + ". Press F to disable");
} else if(follow) {
notify("Can't follow, no one is in the world");
follow = false;
} else {
notify("Follow Off");
}
return;
}
if(e.getKeyCode() == KeyEvent.VK_R) {
dump();
notify("Refreshing Chunks");
return;
}
if(e.getKeyCode() == KeyEvent.VK_P) {
lowtile = !lowtile;
dump();
notify("Rendering " + (lowtile ? "Low" : "High") + " Quality Tiles");
return;
}
if(e.getKeyCode() == KeyEvent.VK_E) {
eco = !eco;
dump();
notify("Using " + (eco ? "60" : "Uncapped") + " FPS Limit");
return;
}
if(e.getKeyCode() == KeyEvent.VK_EQUALS) {
mscale = mscale + ((0.044 * mscale) * -3);
mscale = Math.max(mscale, 0.00001);
dump();
return;
}
if(e.getKeyCode() == KeyEvent.VK_MINUS) {
mscale = mscale + ((0.044 * mscale) * 3);
mscale = Math.max(mscale, 0.00001);
dump();
return;
}
if(e.getKeyCode() == KeyEvent.VK_BACK_SLASH) {
mscale = 1D;
dump();
notify("Zoom Reset");
return;
}
int currentMode = currentType.ordinal();
for(RenderType i : RenderType.values()) {
if(e.getKeyChar() == String.valueOf(i.ordinal() + 1).charAt(0)) {
if(i.ordinal() != currentMode) {
currentType = i;
dump();
notify("Rendering " + Form.capitalizeWords(currentType.name().toLowerCase().replaceAll("\\Q_\\E", " ")));
return;
}
}
}
if(e.getKeyCode() == KeyEvent.VK_M) {
currentType = RenderType.values()[(currentMode + 1) % RenderType.values().length];
notify("Rendering " + Form.capitalizeWords(currentType.name().toLowerCase().replaceAll("\\Q_\\E", " ")));
dump();
}
}
private void dump() {
positions.clear();
fastpositions.clear();
}
public BufferedImage getTile(KSet<BlockPosition> fg, int div, int x, int z, O<Integer> m) {
BlockPosition key = new BlockPosition((int) mscale, Math.floorDiv(x, div), Math.floorDiv(z, div));
fg.add(key);
if(positions.containsKey(key)) {
return positions.get(key);
}
if(fastpositions.containsKey(key)) {
if(!working.contains(key) && working.size() < 9) {
m.set(m.get() - 1);
if(m.get() >= 0 && velocity < 50) {
working.add(key);
double mk = mscale;
double mkd = scale;
e.submit(() ->
{
PrecisionStopwatch ps = PrecisionStopwatch.start();
BufferedImage b = renderer.render(x * mscale, z * mscale, div * mscale, div / (lowtile ? 3 : 1), currentType);
rs.put(ps.getMilliseconds());
working.remove(key);
if(mk == mscale && mkd == scale) {
positions.put(key, b);
}
});
}
}
return fastpositions.get(key);
}
if(workingfast.contains(key) || workingfast.size() > Runtime.getRuntime().availableProcessors()) {
return null;
}
workingfast.add(key);
double mk = mscale;
double mkd = scale;
eh.submit(() ->
{
PrecisionStopwatch ps = PrecisionStopwatch.start();
BufferedImage b = renderer.render(x * mscale, z * mscale, div * mscale, div / lowq, currentType);
rs.put(ps.getMilliseconds());
workingfast.remove(key);
if(mk == mscale && mkd == scale) {
fastpositions.put(key, b);
}
});
return null;
}
private double getWorldX(double screenX) {
//return (mscale * screenX) + ((oxp / scale) * mscale);
return (mscale * screenX) + ((oxp / scale));
}
private double getWorldZ(double screenZ) {
return (mscale * screenZ) + ((ozp / scale) * mscale);
}
private double getScreenX(double x) {
return (x / mscale) - ((oxp / scale));
}
private double getScreenZ(double z) {
return (z / mscale) - ((ozp / scale));
}
@Override
public void paint(Graphics gx) {
if(engine.isClosed()) {
EventQueue.invokeLater(() -> {
try
{
setVisible(false);
}
catch(Throwable e)
{
}
});
return;
}
if(updateEngine()) {
dump();
}
if(ox < oxp) {
velocity = Math.abs(ox - oxp) * 0.36;
oxp -= velocity;
}
if(ox > oxp) {
velocity = Math.abs(oxp - ox) * 0.36;
oxp += velocity;
}
if(oz < ozp) {
velocity = Math.abs(oz - ozp) * 0.36;
ozp -= velocity;
}
if(oz > ozp) {
velocity = Math.abs(ozp - oz) * 0.36;
ozp += velocity;
}
if(lx < hx) {
hx -= Math.abs(lx - hx) * 0.36;
}
if(lx > hx) {
hx += Math.abs(hx - lx) * 0.36;
}
if(lz < hz) {
hz -= Math.abs(lz - hz) * 0.36;
}
if(lz > hz) {
hz += Math.abs(hz - lz) * 0.36;
}
if(centities.flip()) {
J.s(() -> {
synchronized(lastEntities) {
lastEntities.clear();
lastEntities.addAll(world.getEntitiesByClass(LivingEntity.class));
}
});
}
lowq = Math.max(Math.min((int) M.lerp(8, 28, velocity / 1000D), 28), 8);
PrecisionStopwatch p = PrecisionStopwatch.start();
Graphics2D g = (Graphics2D) gx;
w = getWidth();
h = getHeight();
double vscale = scale;
scale = w / 12D;
if(scale != vscale) {
positions.clear();
}
KSet<BlockPosition> gg = new KSet<>();
int iscale = (int) scale;
g.setColor(Color.white);
g.clearRect(0, 0, w, h);
int posX = (int) oxp;
int posZ = (int) ozp;
m.set(3);
for(int r = 0; r < Math.max(w, h); r += iscale) {
for(int i = -iscale; i < w + iscale; i += iscale) {
for(int j = -iscale; j < h + iscale; j += iscale) {
int a = i - (w / 2);
int b = j - (h / 2);
if(a * a + b * b <= r * r) {
BufferedImage t = getTile(gg, iscale, Math.floorDiv((posX / iscale) + i, iscale) * iscale, Math.floorDiv((posZ / iscale) + j, iscale) * iscale, m);
if(t != null) {
g.drawImage(t, i - ((posX / iscale) % (iscale)), j - ((posZ / iscale) % (iscale)), iscale, iscale, (img, infoflags, x, y, width, height) -> true);
}
}
}
}
}
p.end();
for(BlockPosition i : positions.k()) {
if(!gg.contains(i)) {
positions.remove(i);
}
}
hanleFollow();
renderOverlays(g);
if(!isVisible()) {
return;
}
if(!getParent().isVisible()) {
return;
}
if(!getParent().getParent().isVisible()) {
return;
}
J.a(() ->
{
J.sleep(eco ? 15 : 1);
repaint();
});
}
private void hanleFollow() {
if(follow && player != null) {
animateTo(player.getLocation().getX(), player.getLocation().getZ());
}
}
private void renderOverlays(Graphics2D g) {
renderPlayer(g);
if(help) {
renderOverlayHelp(g);
} else if(debug) {
renderOverlayDebug(g);
}
renderOverlayLegend(g);
renderHoverOverlay(g, shift);
if(!notifications.isEmpty()) {
renderNotification(g);
}
}
private void renderOverlayLegend(Graphics2D g) {
KList<String> l = new KList<>();
l.add("Zoom: " + Form.pc(mscale, 0));
l.add("Blocks: " + Form.f((int) mscale * w) + " by " + Form.f((int) mscale * h));
l.add("BPP: " + Form.f(mscale, 1));
l.add("Render Mode: " + Form.capitalizeWords(currentType.name().toLowerCase().replaceAll("\\Q_\\E", " ")));
drawCardBR(g, l);
}
private void renderNotification(Graphics2D g) {
drawCardCB(g, notifications.k());
for(String i : notifications.k()) {
if(M.ms() > notifications.get(i)) {
notifications.remove(i);
}
}
}
private void renderPlayer(Graphics2D g) {
Player b = null;
for(Player i : world.getPlayers()) {
b = i;
renderPosition(g, i.getLocation().getX(), i.getLocation().getZ());
}
synchronized(lastEntities) {
double dist = Double.MAX_VALUE;
LivingEntity h = null;
for(LivingEntity i : lastEntities) {
if(i instanceof Player) {
continue;
}
renderMobPosition(g, i, i.getLocation().getX(), i.getLocation().getZ());
if(shift) {
double d = i.getLocation().distanceSquared(new Location(i.getWorld(), getWorldX(hx), i.getLocation().getY(), getWorldZ(hz)));
if(d < dist) {
dist = d;
h = i;
}
}
}
if(h != null && shift) {
g.setColor(Color.red);
g.fillRoundRect((int) getScreenX(h.getLocation().getX()) - 10, (int) getScreenZ(h.getLocation().getZ()) - 10, 20, 20, 20, 20);
KList<String> k = new KList<>();
k.add(Form.capitalizeWords(h.getType().name().toLowerCase(Locale.ROOT).replaceAll("\\Q_\\E", " ")) + h.getEntityId());
k.add("Pos: " + h.getLocation().getBlockX() + ", " + h.getLocation().getBlockY() + ", " + h.getLocation().getBlockZ());
k.add("UUID: " + h.getUniqueId());
k.add("HP: " + h.getHealth() + " / " + h.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
drawCardTR(g, k);
}
}
player = b;
}
private void animateTo(double wx, double wz) {
double cx = getWorldX(getWidth() / 2);
double cz = getWorldZ(getHeight() / 2);
ox += (wx - cx);
oz += (wz - cz);
}
private void renderPosition(Graphics2D g, double x, double z) {
if(texture != null) {
g.drawImage(texture, (int) getScreenX(x), (int) getScreenZ(z), 66, 66, (img, infoflags, xx, xy, width, height) -> true);
} else {
g.setColor(Color.darkGray);
g.fillRoundRect((int) getScreenX(x) - 15, (int) getScreenZ(z) - 15, 30, 30, 15, 15);
g.setColor(Color.cyan.darker().darker());
g.fillRoundRect((int) getScreenX(x) - 10, (int) getScreenZ(z) - 10, 20, 20, 10, 10);
}
}
private void renderMobPosition(Graphics2D g, LivingEntity e, double x, double z) {
g.setColor(Color.red.darker().darker());
g.fillRoundRect((int) getScreenX(x) - 2, (int) getScreenZ(z) - 2, 4, 4, 4, 4);
}
private void renderHoverOverlay(Graphics2D g, boolean detailed) {
IrisBiome biome = engine.getComplex().getTrueBiomeStream().get(getWorldX(hx), getWorldZ(hz));
IrisRegion region = engine.getComplex().getRegionStream().get(getWorldX(hx), getWorldZ(hz));
KList<String> l = new KList<>();
l.add("Biome: " + biome.getName());
l.add("Region: " + region.getName() + "(" + region.getLoadKey() + ")");
l.add("Block " + (int) getWorldX(hx) + ", " + (int) getWorldZ(hz));
if(detailed) {
l.add("Chunk " + ((int) getWorldX(hx) >> 4) + ", " + ((int) getWorldZ(hz) >> 4));
l.add("Region " + (((int) getWorldX(hx) >> 4) >> 5) + ", " + (((int) getWorldZ(hz) >> 4) >> 5));
l.add("Key: " + biome.getLoadKey());
l.add("File: " + biome.getLoadFile());
}
drawCardAt((float) hx, (float) hz, 0, 0, g, l);
}
private void renderOverlayDebug(Graphics2D g) {
KList<String> l = new KList<>();
l.add("Velocity: " + (int) velocity);
l.add("Center Pos: " + Form.f((int) getWorldX(getWidth() / 2)) + ", " + Form.f((int) getWorldZ(getHeight() / 2)));
drawCardBL(g, l);
}
private void renderOverlayHelp(Graphics2D g) {
KList<String> l = new KList<>();
l.add("/ to show this help screen");
l.add("R to repaint the screen");
l.add("F to follow first player");
l.add("+/- to Change Zoom");
l.add("\\ to reset zoom to 1");
l.add("M to cycle render modes");
l.add("P to toggle Tile Quality Mode");
l.add("E to toggle Eco FPS Mode");
int ff = 0;
for(RenderType i : RenderType.values()) {
ff++;
l.add(ff + " to view " + Form.capitalizeWords(i.name().toLowerCase().replaceAll("\\Q_\\E", " ")));
}
l.add("Shift for additional biome details (at cursor)");
l.add("CTRL + Click to teleport to location");
l.add("ALT + Click to open biome in VSCode");
drawCardTL(g, l);
}
private void drawCardTL(Graphics2D g, KList<String> text) {
drawCardAt(0, 0, 0, 0, g, text);
}
private void drawCardBR(Graphics2D g, KList<String> text) {
drawCardAt(getWidth(), getHeight(), 1, 1, g, text);
}
private void drawCardBL(Graphics2D g, KList<String> text) {
drawCardAt(0, getHeight(), 0, 1, g, text);
}
private void drawCardTR(Graphics2D g, KList<String> text) {
drawCardAt(getWidth(), 0, 1, 0, g, text);
}
private void open() {
IrisComplex complex = engine.getComplex();
File r = null;
switch(currentType) {
case BIOME, LAYER_LOAD, DECORATOR_LOAD, OBJECT_LOAD, HEIGHT -> r = complex.getTrueBiomeStream().get(getWorldX(hx), getWorldZ(hz)).openInVSCode();
case BIOME_LAND -> r = complex.getLandBiomeStream().get(getWorldX(hx), getWorldZ(hz)).openInVSCode();
case BIOME_SEA -> r = complex.getSeaBiomeStream().get(getWorldX(hx), getWorldZ(hz)).openInVSCode();
case REGION -> r = complex.getRegionStream().get(getWorldX(hx), getWorldZ(hz)).openInVSCode();
case CAVE_LAND -> r = complex.getCaveBiomeStream().get(getWorldX(hx), getWorldZ(hz)).openInVSCode();
}
notify("Opening " + r.getPath() + " in VSCode");
}
private void teleport() {
J.s(() -> {
if(player != null) {
int xx = (int) getWorldX(hx);
int zz = (int) getWorldZ(hz);
int h = engine.getComplex().getRoundedHeighteightStream().get(xx, zz);
player.teleport(new Location(player.getWorld(), xx, h, zz));
notify("Teleporting to " + xx + ", " + h + ", " + zz);
} else {
notify("No player in world, can't teleport.");
}
});
}
private void drawCardCB(Graphics2D g, KList<String> text) {
drawCardAt(getWidth() / 2, getHeight(), 0.5, 1, g, text);
}
private void drawCardCT(Graphics2D g, KList<String> text) {
drawCardAt(getWidth() / 2, 0, 0.5, 0, g, text);
}
private void drawCardAt(float x, float y, double pushX, double pushZ, Graphics2D g, KList<String> text) {
g.setFont(new Font("Hevetica", Font.BOLD, 16));
int h = 0;
int w = 0;
for(String i : text) {
h += g.getFontMetrics().getHeight();
w = Math.max(w, g.getFontMetrics().stringWidth(i));
}
w += 28;
h += 14;
int cw = (int) ((w + 26) * pushX);
int ch = (int) ((h + 26) * pushZ);
g.setColor(Color.darkGray);
g.fillRect((int) x + 7 + 2 - cw, (int) y + 12 + 2 - ch, w + 7, h); // Shadow
g.setColor(Color.gray);
g.fillRect((int) x + 7 + 1 - cw, (int) y + 12 + 1 - ch, w + 7, h); // Shadow
g.setColor(Color.white);
g.fillRect((int) x + 7 - cw, (int) y + 12 - ch, w + 7, h);
g.setColor(Color.black);
int m = 0;
for(String i : text) {
g.drawString(i, x + 14 - cw, y + 14 - ch + (++m * g.getFontMetrics().getHeight()));
}
}
public void mouseWheelMoved(MouseWheelEvent e) {
int notches = e.getWheelRotation();
if(e.isControlDown()) {
return;
}
//Iris.info("Blocks/Pixel: " + (mscale) + ", Blocks Wide: " + (w * mscale));
positions.clear();
fastpositions.clear();
mscale = mscale + ((0.25 * mscale) * notches);
mscale = Math.max(mscale, 0.00001);
}
@Override
public void mouseClicked(MouseEvent e) {
if(control) {
teleport();
} else if(alt) {
open();
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}

View File

@ -1,62 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui.components;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.interpolation.IrisInterpolation;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.function.BiFunction;
@SuppressWarnings("ClassCanBeRecord")
public class IrisRenderer {
private final Engine renderer;
public IrisRenderer(Engine renderer) {
this.renderer = renderer;
}
public BufferedImage render(double sx, double sz, double size, int resolution, RenderType currentType) {
BufferedImage image = new BufferedImage(resolution, resolution, BufferedImage.TYPE_INT_RGB);
BiFunction<Double, Double, Integer> colorFunction = (d, dx) -> Color.black.getRGB();
switch(currentType) {
case BIOME, DECORATOR_LOAD, OBJECT_LOAD, LAYER_LOAD -> colorFunction = (x, z) -> renderer.getComplex().getTrueBiomeStream().get(x, z).getColor(renderer, currentType).getRGB();
case BIOME_LAND -> colorFunction = (x, z) -> renderer.getComplex().getLandBiomeStream().get(x, z).getColor(renderer, currentType).getRGB();
case BIOME_SEA -> colorFunction = (x, z) -> renderer.getComplex().getSeaBiomeStream().get(x, z).getColor(renderer, currentType).getRGB();
case REGION -> colorFunction = (x, z) -> renderer.getComplex().getRegionStream().get(x, z).getColor(renderer.getComplex(), currentType).getRGB();
case CAVE_LAND -> colorFunction = (x, z) -> renderer.getComplex().getCaveBiomeStream().get(x, z).getColor(renderer, currentType).getRGB();
case HEIGHT -> colorFunction = (x, z) -> Color.getHSBColor(renderer.getComplex().getHeightStream().get(x, z).floatValue(), 100, 100).getRGB();
}
double x, z;
int i, j;
for(i = 0; i < resolution; i++) {
x = IrisInterpolation.lerp(sx, sx + size, (double) i / (double) (resolution));
for(j = 0; j < resolution; j++) {
z = IrisInterpolation.lerp(sz, sz + size, (double) j / (double) (resolution));
image.setRGB(i, j, colorFunction.apply(x, z));
}
}
return image;
}
}

View File

@ -1,23 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui.components;
public enum RenderType {
BIOME, BIOME_LAND, BIOME_SEA, REGION, CAVE_LAND, HEIGHT, OBJECT_LOAD, DECORATOR_LOAD, LAYER_LOAD
}

View File

@ -1,26 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui.components;
import java.awt.Color;
@FunctionalInterface
public interface Renderer {
Color draw(double x, double z);
}

View File

@ -1,31 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.gui.components;
import lombok.Builder;
import lombok.Data;
import java.awt.image.BufferedImage;
@Builder
@Data
public class TileRender {
private BufferedImage image;
private int quality;
}

View File

@ -1,36 +0,0 @@
package com.volmit.iris.core.link;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import java.util.MissingResourceException;
@RequiredArgsConstructor
public abstract class ExternalDataProvider {
@Getter
private final String pluginId;
public Plugin getPlugin() {
return Bukkit.getPluginManager().getPlugin(pluginId);
}
public boolean isPresent() {
return getPlugin() != null;
}
public abstract void init();
public abstract BlockData getBlockData(NamespacedKey blockId) throws MissingResourceException;
public abstract ItemStack getItemStack(NamespacedKey itemId) throws MissingResourceException;
public abstract NamespacedKey[] getBlockTypes();
public abstract boolean isValidProvider(NamespacedKey namespace);
}

View File

@ -1,110 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
// See/update https://app.gitbook.com/@volmitsoftware/s/iris/compatability/papi/
public class IrisPapiExpansion extends PlaceholderExpansion {
@Override
public String getIdentifier() {
return "iris";
}
@Override
public String getAuthor() {
return "Volmit Software";
}
@Override
public String getVersion() {
return Iris.instance.getDescription().getVersion();
}
@Override
public boolean persist() {
return false;
}
@Override
public String onRequest(OfflinePlayer player, String p) {
Location l = null;
PlatformChunkGenerator a = null;
if(player.isOnline()) {
l = player.getPlayer().getLocation();
a = IrisToolbelt.access(l.getWorld());
}
if(p.equalsIgnoreCase("biome_name")) {
if(a != null) {
return a.getEngine().getBiome(l).getName();
}
} else if(p.equalsIgnoreCase("biome_id")) {
if(a != null) {
return a.getEngine().getBiome(l).getLoadKey();
}
} else if(p.equalsIgnoreCase("biome_file")) {
if(a != null) {
return a.getEngine().getBiome(l).getLoadFile().getPath();
}
} else if(p.equalsIgnoreCase("region_name")) {
if(a != null) {
return a.getEngine().getRegion(l).getName();
}
} else if(p.equalsIgnoreCase("region_id")) {
if(a != null) {
return a.getEngine().getRegion(l).getLoadKey();
}
} else if(p.equalsIgnoreCase("region_file")) {
if(a != null) {
return a.getEngine().getRegion(l).getLoadFile().getPath();
}
} else if(p.equalsIgnoreCase("terrain_slope")) {
if(a != null) {
return (a.getEngine())
.getComplex().getSlopeStream()
.get(l.getX(), l.getZ()) + "";
}
} else if(p.equalsIgnoreCase("terrain_height")) {
if(a != null) {
return Math.round(a.getEngine().getHeight(l.getBlockX(), l.getBlockZ())) + "";
}
} else if(p.equalsIgnoreCase("world_mode")) {
if(a != null) {
return a.isStudio() ? "Studio" : "Production";
}
} else if(p.equalsIgnoreCase("world_seed")) {
if(a != null) {
return a.getEngine().getSeedManager().getSeed() + "";
}
} else if(p.equalsIgnoreCase("world_speed")) {
if(a != null) {
return a.getEngine().getGeneratedPerSecond() + "/s";
}
}
return null;
}
}

View File

@ -1,51 +0,0 @@
package com.volmit.iris.core.link;
import com.volmit.iris.util.collection.KList;
import dev.lone.itemsadder.api.CustomBlock;
import dev.lone.itemsadder.api.CustomStack;
import dev.lone.itemsadder.api.ItemsAdder;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import java.util.MissingResourceException;
public class ItemAdderDataProvider extends ExternalDataProvider {
public ItemAdderDataProvider() {
super("ItemsAdder");
}
@Override
public void init() { }
@Override
public BlockData getBlockData(NamespacedKey blockId) throws MissingResourceException {
return CustomBlock.getBaseBlockData(blockId.toString());
}
@Override
public ItemStack getItemStack(NamespacedKey itemId) throws MissingResourceException {
CustomStack stack = CustomStack.getInstance(itemId.toString());
if(stack == null)
throw new MissingResourceException("Failed to find ItemData!", itemId.getNamespace(), itemId.getKey());
return stack.getItemStack();
}
@Override
public NamespacedKey[] getBlockTypes() {
KList<NamespacedKey> keys = new KList<>();
for(String s : ItemsAdder.getNamespacedBlocksNamesInConfig())
keys.add(NamespacedKey.fromString(s));
return keys.toArray(new NamespacedKey[0]);
}
@Override
public boolean isValidProvider(NamespacedKey blockId) {
for(NamespacedKey k : getBlockTypes())
if(k.equals(blockId)) {
return true;
}
return false;
}
}

View File

@ -1,143 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KMap;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldType;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
public class MultiverseCoreLink {
private final KMap<String, String> worldNameTypes = new KMap<>();
public MultiverseCoreLink() {
}
public boolean addWorld(String worldName, IrisDimension dim, String seed) {
if(!isSupported()) {
return false;
}
try {
Plugin p = getMultiverse();
Object mvWorldManager = p.getClass().getDeclaredMethod("getMVWorldManager").invoke(p);
Method m = mvWorldManager.getClass().getDeclaredMethod("addWorld",
String.class, World.Environment.class, String.class, WorldType.class, Boolean.class, String.class, boolean.class);
boolean b = (boolean) m.invoke(mvWorldManager, worldName, dim.getEnvironment(), seed, WorldType.NORMAL, false, "Iris", false);
saveConfig();
return b;
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
return false;
}
@SuppressWarnings("unchecked")
public Map<String, ?> getList() {
try {
Plugin p = getMultiverse();
Object mvWorldManager = p.getClass().getDeclaredMethod("getMVWorldManager").invoke(p);
Field f = mvWorldManager.getClass().getDeclaredField("worldsFromTheConfig");
f.setAccessible(true);
return (Map<String, ?>) f.get(mvWorldManager);
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
return null;
}
public void removeFromConfig(World world) {
if(!isSupported()) {
return;
}
getList().remove(world.getName());
saveConfig();
}
public void removeFromConfig(String world) {
if(!isSupported()) {
return;
}
getList().remove(world);
saveConfig();
}
public void saveConfig() {
try {
Plugin p = getMultiverse();
Object mvWorldManager = p.getClass().getDeclaredMethod("getMVWorldManager").invoke(p);
mvWorldManager.getClass().getDeclaredMethod("saveWorldsConfig").invoke(mvWorldManager);
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
}
public void assignWorldType(String worldName, String type) {
worldNameTypes.put(worldName, type);
}
public String getWorldNameType(String worldName, String defaultType) {
try {
String t = worldNameTypes.get(worldName);
return t == null ? defaultType : t;
} catch(Throwable e) {
Iris.reportError(e);
return defaultType;
}
}
public boolean isSupported() {
return getMultiverse() != null;
}
public Plugin getMultiverse() {
return Bukkit.getPluginManager().getPlugin("Multiverse-Core");
}
public String envName(World.Environment environment) {
if(environment == null) {
return "normal";
}
return switch(environment) {
case NORMAL -> "normal";
case NETHER -> "nether";
case THE_END -> "end";
default -> environment.toString().toLowerCase();
};
}
}

View File

@ -1,115 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.link;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.plugin.Plugin;
import javax.annotation.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.BiFunction;
public class MythicMobsLink {
private Collection<String> mobs;
private BiFunction<String, Location, Entity> spawnMobFunction;
public MythicMobsLink() {
}
public boolean isEnabled() {
return getPlugin() != null;
}
public Plugin getPlugin() {
return Bukkit.getPluginManager().getPlugin("MythicMobs");
}
/**
* Spawn a mythic mob at this location
*
* @param mob
* The mob
* @param location
* The location
* @return The mob, or null if it can't be spawned
*/
public @Nullable
Entity spawnMob(String mob, Location location) {
if(!isEnabled()) return null;
if(spawnMobFunction != null) {
return spawnMobFunction.apply(mob, location);
}
try {
Class<?> mythicMobClass = Class.forName("io.lumine.mythic.bukkit.MythicBukkit");
Method getInst = mythicMobClass.getDeclaredMethod("inst");
Object inst = getInst.invoke(null);
Method getAPIHelper = mythicMobClass.getDeclaredMethod("getAPIHelper");
Object apiHelper = getAPIHelper.invoke(inst);
Method spawnMobMethod = apiHelper.getClass().getDeclaredMethod("spawnMythicMob", String.class, Location.class);
spawnMobFunction = (str, loc) -> {
try {
return (Entity) spawnMobMethod.invoke(apiHelper, str, loc);
} catch(InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
};
return spawnMobFunction.apply(mob, location);
} catch(Exception e) {
e.printStackTrace();
}
return null;
}
public Collection<String> getMythicMobTypes() {
if(mobs != null) {
return mobs;
}
if(isEnabled()) {
try {
Class<?> mythicMobClass = Class.forName("io.lumine.xikage.mythicmobs.MythicMobs");
Method getInst = mythicMobClass.getDeclaredMethod("inst");
Object inst = getInst.invoke(null);
Method getMobManager = mythicMobClass.getDeclaredMethod("getMobManager");
Object mobManager = getMobManager.invoke(inst);
Method getMobNames = mobManager.getClass().getDeclaredMethod("getMobNames");
mobs = (Collection<String>) getMobNames.invoke(mobManager);
return mobs;
} catch(ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
return new ArrayList<>();
}
}

View File

@ -1,112 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.link;
import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KList;
import io.th0rgal.oraxen.items.ItemBuilder;
import io.th0rgal.oraxen.items.OraxenItems;
import io.th0rgal.oraxen.mechanics.MechanicFactory;
import io.th0rgal.oraxen.mechanics.MechanicsManager;
import io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanic;
import io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanicFactory;
import io.th0rgal.oraxen.mechanics.provided.gameplay.noteblock.NoteBlockMechanicFactory;
import io.th0rgal.oraxen.utils.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Optional;
public class OraxenDataProvider extends ExternalDataProvider {
private static final String FIELD_FACTORIES_MAP = "FACTORIES_BY_MECHANIC_ID";
private Map<String, MechanicFactory> factories;
public OraxenDataProvider() { super("Oraxen"); }
@Override
public void init() {
try {
Field f = MechanicsManager.class.getDeclaredField(FIELD_FACTORIES_MAP);
f.setAccessible(true);
factories = (Map<String, MechanicFactory>) f.get(null);
} catch(NoSuchFieldException | IllegalAccessException e) {
Iris.error("Failed to set up Oraxen Link:");
Iris.error("\t" + e.getClass().getSimpleName());
}
}
@Override
public BlockData getBlockData(NamespacedKey blockId) throws MissingResourceException {
MechanicFactory f = getFactory(blockId);
if(f instanceof NoteBlockMechanicFactory)
return ((NoteBlockMechanicFactory)f).createNoteBlockData(blockId.getKey());
else if(f instanceof BlockMechanicFactory) {
MultipleFacing newBlockData = (MultipleFacing) Bukkit.createBlockData(Material.MUSHROOM_STEM);
Utils.setBlockFacing(newBlockData, ((BlockMechanic)f.getMechanic(blockId.getKey())).getCustomVariation());
return newBlockData;
} else
throw new MissingResourceException("Failed to find BlockData!", blockId.getNamespace(), blockId.getKey());
}
@Override
public ItemStack getItemStack(NamespacedKey itemId) throws MissingResourceException {
Optional<ItemBuilder> opt = OraxenItems.getOptionalItemById(itemId.getKey());
return opt.orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.getNamespace(), itemId.getKey())).build();
}
@Override
public NamespacedKey[] getBlockTypes() {
KList<NamespacedKey> names = new KList<>();
for(String name : OraxenItems.getItemNames()) {
try {
NamespacedKey key = new NamespacedKey("oraxen", name);
if(getBlockData(key) != null)
names.add(key);
} catch(MissingResourceException ignored) { }
}
return names.toArray(new NamespacedKey[0]);
}
@Override
public boolean isPresent() {
return super.isPresent() && factories != null;
}
@Override
public boolean isValidProvider(NamespacedKey key) {
return key.getNamespace().equalsIgnoreCase("oraxen");
}
private MechanicFactory getFactory(NamespacedKey key) throws MissingResourceException {
return factories.values().stream()
.filter(i -> i.getItems().contains(key.getKey()))
.findFirst()
.orElseThrow(() -> new MissingResourceException("Failed to find BlockData!", key.getNamespace(), key.getKey()));
}
}

View File

@ -1,37 +0,0 @@
package com.volmit.iris.core.link;
import com.volmit.iris.util.data.Cuboid;
import org.bukkit.World;
import org.bukkit.entity.Player;
public class WorldEditLink {
public static Cuboid getSelection(Player p)
{
try
{
Object instance = Class.forName("com.sk89q.worldedit.WorldEdit").getDeclaredMethod("getInstance").invoke(null);
Object sessionManager = instance.getClass().getDeclaredMethod("getSessionManager").invoke(instance);
Object player = Class.forName("com.sk89q.worldedit.bukkit.BukkitAdapter").getDeclaredMethod("adapt", Player.class).invoke(null, p);
Object localSession = sessionManager.getClass().getDeclaredMethod("getIfPresent", Class.forName("com.sk89q.worldedit.session.SessionOwner")).invoke(sessionManager, player);
Object world = Class.forName("com.sk89q.worldedit.bukkit.BukkitAdapter").getDeclaredMethod("adapt", World.class).invoke(null, p.getWorld());
Object region = localSession.getClass().getDeclaredMethod("getSelection", world.getClass()).invoke(localSession, world);
Object min = region.getClass().getDeclaredMethod("getMinimumPoint").invoke(region);
Object max = region.getClass().getDeclaredMethod("getMaximumPoint").invoke(region);
return new Cuboid(p.getWorld(),
(int)min.getClass().getDeclaredMethod("getX").invoke(min),
(int)min.getClass().getDeclaredMethod("getY").invoke(min),
(int)min.getClass().getDeclaredMethod("getZ").invoke(min),
(int)min.getClass().getDeclaredMethod("getX").invoke(max),
(int)min.getClass().getDeclaredMethod("getY").invoke(max),
(int)min.getClass().getDeclaredMethod("getZ").invoke(max)
);
}
catch(Throwable e)
{
}
return null;
}
}

View File

@ -1,149 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.loader;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.object.IrisImage;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
public class ImageResourceLoader extends ResourceLoader<IrisImage> {
public ImageResourceLoader(File root, IrisData idm, String folderName, String resourceTypeName) {
super(root, idm, folderName, resourceTypeName, IrisImage.class);
loadCache = new KCache<>(this::loadRaw, IrisSettings.get().getPerformance().getObjectLoaderCacheSize());
}
public boolean supportsSchemas() {
return false;
}
public long getSize() {
return loadCache.getSize();
}
public long getTotalStorage() {
return getSize();
}
protected IrisImage loadFile(File j, String name) {
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
BufferedImage bu = ImageIO.read(j);
IrisImage img = new IrisImage(bu);
img.setLoadFile(j);
img.setLoader(manager);
img.setLoadKey(name);
logLoad(j, img);
tlt.addAndGet(p.getMilliseconds());
return img;
} catch(Throwable e) {
Iris.reportError(e);
Iris.warn("Couldn't read " + resourceTypeName + " file: " + j.getPath() + ": " + e.getMessage());
return null;
}
}
public String[] getPossibleKeys() {
if(possibleKeys != null) {
return possibleKeys;
}
Iris.debug("Building " + resourceTypeName + " Possibility Lists");
KSet<String> m = new KSet<>();
for(File i : getFolders()) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".png")) {
m.add(j.getName().replaceAll("\\Q.png\\E", ""));
} else if(j.isDirectory()) {
for(File k : j.listFiles()) {
if(k.isFile() && k.getName().endsWith(".png")) {
m.add(j.getName() + "/" + k.getName().replaceAll("\\Q.png\\E", ""));
} else if(k.isDirectory()) {
for(File l : k.listFiles()) {
if(l.isFile() && l.getName().endsWith(".png")) {
m.add(j.getName() + "/" + k.getName() + "/" + l.getName().replaceAll("\\Q.png\\E", ""));
}
}
}
}
}
}
}
KList<String> v = new KList<>(m);
possibleKeys = v.toArray(new String[0]);
return possibleKeys;
}
public File findFile(String name) {
for(File i : getFolders(name)) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".png") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return j;
}
}
File file = new File(i, name + ".png");
if(file.exists()) {
return file;
}
}
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);
return null;
}
public IrisImage load(String name) {
return load(name, true);
}
private IrisImage loadRaw(String name) {
for(File i : getFolders(name)) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".png") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return loadFile(j, name);
}
}
File file = new File(i, name + ".png");
if(file.exists()) {
return loadFile(file, name);
}
}
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);
return null;
}
public IrisImage load(String name, boolean warn) {
return loadCache.get(name);
}
}

View File

@ -1,470 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.loader;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.engine.object.matter.IrisMatterObject;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import lombok.Data;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Objects;
import java.util.function.Function;
@Data
public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
private static final KMap<File, IrisData> dataLoaders = new KMap<>();
private final File dataFolder;
private final int id;
private boolean closed = false;
private ResourceLoader<IrisBiome> biomeLoader;
private ResourceLoader<IrisLootTable> lootLoader;
private ResourceLoader<IrisRegion> regionLoader;
private ResourceLoader<IrisDimension> dimensionLoader;
private ResourceLoader<IrisGenerator> generatorLoader;
private ResourceLoader<IrisJigsawPiece> jigsawPieceLoader;
private ResourceLoader<IrisJigsawPool> jigsawPoolLoader;
private ResourceLoader<IrisJigsawStructure> jigsawStructureLoader;
private ResourceLoader<IrisEntity> entityLoader;
private ResourceLoader<IrisMarker> markerLoader;
private ResourceLoader<IrisSpawner> spawnerLoader;
private ResourceLoader<IrisMod> modLoader;
private ResourceLoader<IrisBlockData> blockLoader;
private ResourceLoader<IrisExpression> expressionLoader;
private ResourceLoader<IrisObject> objectLoader;
private ResourceLoader<IrisMatterObject> matterLoader;
private ResourceLoader<IrisImage> imageLoader;
private ResourceLoader<IrisScript> scriptLoader;
private ResourceLoader<IrisCave> caveLoader;
private ResourceLoader<IrisRavine> ravineLoader;
private ResourceLoader<IrisMatterObject> matterObjectLoader;
private KMap<String, KList<String>> possibleSnippets;
private Gson gson;
private Gson snippetLoader;
private GsonBuilder builder;
private KMap<Class<? extends IrisRegistrant>, ResourceLoader<? extends IrisRegistrant>> loaders = new KMap<>();
private Engine engine;
private IrisData(File dataFolder) {
this.engine = null;
this.dataFolder = dataFolder;
this.id = RNG.r.imax();
hotloaded();
}
public static IrisData get(File dataFolder) {
return dataLoaders.computeIfAbsent(dataFolder, IrisData::new);
}
public static void dereference() {
dataLoaders.v().forEach(IrisData::cleanupEngine);
}
public static int cacheSize() {
int m = 0;
for(IrisData i : dataLoaders.values()) {
for(ResourceLoader<?> j : i.getLoaders().values()) {
m += j.getLoadCache().getSize();
}
}
return m;
}
private static void printData(ResourceLoader<?> rl) {
Iris.warn(" " + rl.getResourceTypeName() + " @ /" + rl.getFolderName() + ": Cache=" + rl.getLoadCache().getSize() + " Folders=" + rl.getFolders().size());
}
public static IrisObject loadAnyObject(String key) {
return loadAny(key, (dm) -> dm.getObjectLoader().load(key, false));
}
public static IrisMatterObject loadAnyMatter(String key) {
return loadAny(key, (dm) -> dm.getMatterLoader().load(key, false));
}
public static IrisBiome loadAnyBiome(String key) {
return loadAny(key, (dm) -> dm.getBiomeLoader().load(key, false));
}
public static IrisExpression loadAnyExpression(String key) {
return loadAny(key, (dm) -> dm.getExpressionLoader().load(key, false));
}
public static IrisMod loadAnyMod(String key) {
return loadAny(key, (dm) -> dm.getModLoader().load(key, false));
}
public static IrisJigsawPiece loadAnyJigsawPiece(String key) {
return loadAny(key, (dm) -> dm.getJigsawPieceLoader().load(key, false));
}
public static IrisJigsawPool loadAnyJigsawPool(String key) {
return loadAny(key, (dm) -> dm.getJigsawPoolLoader().load(key, false));
}
public static IrisEntity loadAnyEntity(String key) {
return loadAny(key, (dm) -> dm.getEntityLoader().load(key, false));
}
public static IrisLootTable loadAnyLootTable(String key) {
return loadAny(key, (dm) -> dm.getLootLoader().load(key, false));
}
public static IrisBlockData loadAnyBlock(String key) {
return loadAny(key, (dm) -> dm.getBlockLoader().load(key, false));
}
public static IrisSpawner loadAnySpaner(String key) {
return loadAny(key, (dm) -> dm.getSpawnerLoader().load(key, false));
}
public static IrisScript loadAnyScript(String key) {
return loadAny(key, (dm) -> dm.getScriptLoader().load(key, false));
}
public static IrisRavine loadAnyRavine(String key) {
return loadAny(key, (dm) -> dm.getRavineLoader().load(key, false));
}
public static IrisRegion loadAnyRegion(String key) {
return loadAny(key, (dm) -> dm.getRegionLoader().load(key, false));
}
public static IrisMarker loadAnyMarker(String key) {
return loadAny(key, (dm) -> dm.getMarkerLoader().load(key, false));
}
public static IrisCave loadAnyCave(String key) {
return loadAny(key, (dm) -> dm.getCaveLoader().load(key, false));
}
public static IrisImage loadAnyImage(String key) {
return loadAny(key, (dm) -> dm.getImageLoader().load(key, false));
}
public static IrisDimension loadAnyDimension(String key) {
return loadAny(key, (dm) -> dm.getDimensionLoader().load(key, false));
}
public static IrisJigsawStructure loadAnyJigsawStructure(String key) {
return loadAny(key, (dm) -> dm.getJigsawStructureLoader().load(key, false));
}
public static IrisGenerator loadAnyGenerator(String key) {
return loadAny(key, (dm) -> dm.getGeneratorLoader().load(key, false));
}
public static <T extends IrisRegistrant> T loadAny(String key, Function<IrisData, T> v) {
try {
for(File i : Objects.requireNonNull(Iris.instance.getDataFolder("packs").listFiles())) {
if(i.isDirectory()) {
IrisData dm = get(i);
T t = v.apply(dm);
if(t != null) {
return t;
}
}
}
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
return null;
}
public ResourceLoader<?> getTypedLoaderFor(File f) {
String[] k = f.getPath().split("\\Q" + File.separator + "\\E");
for(String i : k) {
for(ResourceLoader<?> j : loaders.values()) {
if(j.getFolderName().equals(i)) {
return j;
}
}
}
return null;
}
public void cleanupEngine() {
if(engine != null && engine.isClosed()) {
engine = null;
Iris.debug("Dereferenced Data<Engine> " + getId() + " " + getDataFolder());
}
}
public void preprocessObject(IrisRegistrant t) {
try {
IrisContext ctx = IrisContext.get();
Engine engine = this.engine;
if(engine == null && ctx != null && ctx.getEngine() != null) {
engine = ctx.getEngine();
}
if(engine == null && t.getPreprocessors().isNotEmpty()) {
Iris.error("Failed to preprocess object " + t.getLoadKey() + " because there is no engine context here. (See stack below)");
try {
throw new RuntimeException();
} catch(Throwable ex) {
ex.printStackTrace();
}
}
if(engine != null && t.getPreprocessors().isNotEmpty()) {
synchronized(this) {
engine.getExecution().getAPI().setPreprocessorObject(t);
for(String i : t.getPreprocessors()) {
engine.getExecution().execute(i);
Iris.debug("Loader<" + C.GREEN + t.getTypeName() + C.LIGHT_PURPLE + "> iprocess " + C.YELLOW + t.getLoadKey() + C.LIGHT_PURPLE + " in <rainbow>" + i);
}
}
}
} catch(Throwable e) {
Iris.error("Failed to preprocess object!");
e.printStackTrace();
}
}
public void close() {
closed = true;
dump();
}
public IrisData copy() {
return IrisData.get(dataFolder);
}
private <T extends IrisRegistrant> ResourceLoader<T> registerLoader(Class<T> registrant) {
try {
IrisRegistrant rr = registrant.getConstructor().newInstance();
ResourceLoader<T> r = null;
if(registrant.equals(IrisObject.class)) {
r = (ResourceLoader<T>) new ObjectResourceLoader(dataFolder, this, rr.getFolderName(),
rr.getTypeName());
} else if(registrant.equals(IrisMatterObject.class)) {
r = (ResourceLoader<T>) new MatterObjectResourceLoader(dataFolder, this, rr.getFolderName(),
rr.getTypeName());
} else if(registrant.equals(IrisScript.class)) {
r = (ResourceLoader<T>) new ScriptResourceLoader(dataFolder, this, rr.getFolderName(),
rr.getTypeName());
} else if(registrant.equals(IrisImage.class)) {
r = (ResourceLoader<T>) new ImageResourceLoader(dataFolder, this, rr.getFolderName(),
rr.getTypeName());
} else {
J.attempt(() -> registrant.getConstructor().newInstance().registerTypeAdapters(builder));
r = new ResourceLoader<>(dataFolder, this, rr.getFolderName(), rr.getTypeName(), registrant);
}
loaders.put(registrant, r);
return r;
} catch(Throwable e) {
e.printStackTrace();
Iris.error("Failed to create loader! " + registrant.getCanonicalName());
}
return null;
}
public synchronized void hotloaded() {
possibleSnippets = new KMap<>();
builder = new GsonBuilder()
.addDeserializationExclusionStrategy(this)
.addSerializationExclusionStrategy(this)
.setLenient()
.registerTypeAdapterFactory(this)
.setPrettyPrinting();
loaders.clear();
File packs = dataFolder;
packs.mkdirs();
this.lootLoader = registerLoader(IrisLootTable.class);
this.spawnerLoader = registerLoader(IrisSpawner.class);
this.entityLoader = registerLoader(IrisEntity.class);
this.regionLoader = registerLoader(IrisRegion.class);
this.biomeLoader = registerLoader(IrisBiome.class);
this.modLoader = registerLoader(IrisMod.class);
this.dimensionLoader = registerLoader(IrisDimension.class);
this.jigsawPoolLoader = registerLoader(IrisJigsawPool.class);
this.jigsawStructureLoader = registerLoader(IrisJigsawStructure.class);
this.jigsawPieceLoader = registerLoader(IrisJigsawPiece.class);
this.generatorLoader = registerLoader(IrisGenerator.class);
this.caveLoader = registerLoader(IrisCave.class);
this.markerLoader = registerLoader(IrisMarker.class);
this.ravineLoader = registerLoader(IrisRavine.class);
this.blockLoader = registerLoader(IrisBlockData.class);
this.expressionLoader = registerLoader(IrisExpression.class);
this.objectLoader = registerLoader(IrisObject.class);
this.imageLoader = registerLoader(IrisImage.class);
this.scriptLoader = registerLoader(IrisScript.class);
this.matterObjectLoader = registerLoader(IrisMatterObject.class);
gson = builder.create();
}
public void dump() {
for(ResourceLoader<?> i : loaders.values()) {
i.clearCache();
}
}
public void clearLists() {
for(ResourceLoader<?> i : loaders.values()) {
i.clearList();
}
}
public String toLoadKey(File f) {
if(f.getPath().startsWith(getDataFolder().getPath())) {
String[] full = f.getPath().split("\\Q" + File.separator + "\\E");
String[] df = getDataFolder().getPath().split("\\Q" + File.separator + "\\E");
StringBuilder g = new StringBuilder();
boolean m = true;
for(int i = 0; i < full.length; i++) {
if(i >= df.length) {
if(m) {
m = false;
continue;
}
g.append("/").append(full[i]);
}
}
String ff = g.substring(1).split("\\Q.\\E")[0];
return ff;
} else {
Iris.error("Forign file from loader " + f.getPath() + " (loader realm: " + getDataFolder().getPath() + ")");
}
Iris.error("Failed to load " + f.getPath() + " (loader realm: " + getDataFolder().getPath() + ")");
return null;
}
@Override
public boolean shouldSkipField(FieldAttributes f) {
return false;
}
@Override
public boolean shouldSkipClass(Class<?> c) {
if(c.equals(AtomicCache.class)) {
return true;
} else return c.equals(ChronoLatch.class);
}
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
if(!typeToken.getRawType().isAnnotationPresent(Snippet.class)) {
return null;
}
String snippetType = typeToken.getRawType().getDeclaredAnnotation(Snippet.class).value();
return new TypeAdapter<>() {
@Override
public void write(JsonWriter jsonWriter, T t) throws IOException {
gson.getDelegateAdapter(IrisData.this, typeToken).write(jsonWriter, t);
}
@Override
public T read(JsonReader reader) throws IOException {
TypeAdapter<T> adapter = gson.getDelegateAdapter(IrisData.this, typeToken);
if(reader.peek().equals(JsonToken.STRING)) {
String r = reader.nextString();
if(r.startsWith("snippet/" + snippetType + "/")) {
File f = new File(getDataFolder(), r + ".json");
if(f.exists()) {
try {
JsonReader snippetReader = new JsonReader(new FileReader(f));
return adapter.read(snippetReader);
} catch(Throwable e) {
Iris.error("Couldn't read snippet " + r + " in " + reader.getPath() + " (" + e.getMessage() + ")");
}
} else {
Iris.error("Couldn't find snippet " + r + " in " + reader.getPath());
}
}
return null;
}
try {
return adapter.read(reader);
} catch(Throwable e) {
Iris.error("Failed to read " + typeToken.getRawType().getCanonicalName() + "... faking objects a little to load the file at least.");
try {
return (T) typeToken.getRawType().getConstructor().newInstance();
} catch(Throwable ignored) {
}
}
return null;
}
};
}
public KList<String> getPossibleSnippets(String f) {
return possibleSnippets.computeIfAbsent(f, (k) -> {
KList<String> l = new KList<>();
File snippetFolder = new File(getDataFolder(), "snippet/" + f);
if(snippetFolder.exists() && snippetFolder.isDirectory()) {
for(File i : snippetFolder.listFiles()) {
l.add("snippet/" + f + "/" + i.getName().split("\\Q.\\E")[0]);
}
}
return l;
});
}
public boolean isClosed() {
return closed;
}
}

View File

@ -1,67 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.loader;
import com.google.gson.GsonBuilder;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.object.IrisScript;
import com.volmit.iris.engine.object.annotations.ArrayType;
import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.RegistryListResource;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.plugin.VolmitSender;
import lombok.Data;
import java.awt.Desktop;
import java.io.File;
@Data
public abstract class IrisRegistrant {
@Desc("Preprocess this object in-memory when it's loaded, run scripts using the variable 'Iris.getPreprocessorObject()' and modify properties about this object before it's used.")
@RegistryListResource(IrisScript.class)
@ArrayType(min = 1, type = String.class)
private KList<String> preprocessors = new KList<>();
private transient IrisData loader;
private transient String loadKey;
private transient File loadFile;
public abstract String getFolderName();
public abstract String getTypeName();
public void registerTypeAdapters(GsonBuilder builder) {
}
public File openInVSCode() {
try {
Desktop.getDesktop().open(getLoadFile());
} catch(Throwable e) {
Iris.reportError(e);
}
return getLoadFile();
}
public abstract void scanForErrors(JSONObject p, VolmitSender sender);
}

View File

@ -1,146 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.loader;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.object.matter.IrisMatterObject;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import java.io.File;
public class MatterObjectResourceLoader extends ResourceLoader<IrisMatterObject> {
public MatterObjectResourceLoader(File root, IrisData idm, String folderName, String resourceTypeName) {
super(root, idm, folderName, resourceTypeName, IrisMatterObject.class);
loadCache = new KCache<>(this::loadRaw, IrisSettings.get().getPerformance().getObjectLoaderCacheSize());
}
public boolean supportsSchemas() {
return false;
}
public long getSize() {
return loadCache.getSize();
}
public long getTotalStorage() {
return getSize();
}
protected IrisMatterObject loadFile(File j, String name) {
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
IrisMatterObject t = IrisMatterObject.from(j);
t.setLoadKey(name);
t.setLoader(manager);
t.setLoadFile(j);
logLoad(j, t);
tlt.addAndGet(p.getMilliseconds());
return t;
} catch(Throwable e) {
Iris.reportError(e);
Iris.warn("Couldn't read " + resourceTypeName + " file: " + j.getPath() + ": " + e.getMessage());
return null;
}
}
public String[] getPossibleKeys() {
if(possibleKeys != null) {
return possibleKeys;
}
Iris.debug("Building " + resourceTypeName + " Possibility Lists");
KSet<String> m = new KSet<>();
for(File i : getFolders()) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".mat")) {
m.add(j.getName().replaceAll("\\Q.mat\\E", ""));
} else if(j.isDirectory()) {
for(File k : j.listFiles()) {
if(k.isFile() && k.getName().endsWith(".mat")) {
m.add(j.getName() + "/" + k.getName().replaceAll("\\Q.mat\\E", ""));
} else if(k.isDirectory()) {
for(File l : k.listFiles()) {
if(l.isFile() && l.getName().endsWith(".mat")) {
m.add(j.getName() + "/" + k.getName() + "/" + l.getName().replaceAll("\\Q.mat\\E", ""));
}
}
}
}
}
}
}
KList<String> v = new KList<>(m);
possibleKeys = v.toArray(new String[0]);
return possibleKeys;
}
public File findFile(String name) {
for(File i : getFolders(name)) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".mat") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return j;
}
}
File file = new File(i, name + ".mat");
if(file.exists()) {
return file;
}
}
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);
return null;
}
public IrisMatterObject load(String name) {
return load(name, true);
}
private IrisMatterObject loadRaw(String name) {
for(File i : getFolders(name)) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".mat") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return loadFile(j, name);
}
}
File file = new File(i, name + ".mat");
if(file.exists()) {
return loadFile(file, name);
}
}
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);
return null;
}
public IrisMatterObject load(String name, boolean warn) {
return loadCache.get(name);
}
}

View File

@ -1,147 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.loader;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import java.io.File;
public class ObjectResourceLoader extends ResourceLoader<IrisObject> {
public ObjectResourceLoader(File root, IrisData idm, String folderName, String resourceTypeName) {
super(root, idm, folderName, resourceTypeName, IrisObject.class);
loadCache = new KCache<>(this::loadRaw, IrisSettings.get().getPerformance().getObjectLoaderCacheSize());
}
public boolean supportsSchemas() {
return false;
}
public long getSize() {
return loadCache.getSize();
}
public long getTotalStorage() {
return getSize();
}
protected IrisObject loadFile(File j, String name) {
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
IrisObject t = new IrisObject(0, 0, 0);
t.read(j);
t.setLoadKey(name);
t.setLoader(manager);
t.setLoadFile(j);
logLoad(j, t);
tlt.addAndGet(p.getMilliseconds());
return t;
} catch(Throwable e) {
Iris.reportError(e);
Iris.warn("Couldn't read " + resourceTypeName + " file: " + j.getPath() + ": " + e.getMessage());
return null;
}
}
public String[] getPossibleKeys() {
if(possibleKeys != null) {
return possibleKeys;
}
Iris.debug("Building " + resourceTypeName + " Possibility Lists");
KSet<String> m = new KSet<>();
for(File i : getFolders()) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".iob")) {
m.add(j.getName().replaceAll("\\Q.iob\\E", ""));
} else if(j.isDirectory()) {
for(File k : j.listFiles()) {
if(k.isFile() && k.getName().endsWith(".iob")) {
m.add(j.getName() + "/" + k.getName().replaceAll("\\Q.iob\\E", ""));
} else if(k.isDirectory()) {
for(File l : k.listFiles()) {
if(l.isFile() && l.getName().endsWith(".iob")) {
m.add(j.getName() + "/" + k.getName() + "/" + l.getName().replaceAll("\\Q.iob\\E", ""));
}
}
}
}
}
}
}
KList<String> v = new KList<>(m);
possibleKeys = v.toArray(new String[0]);
return possibleKeys;
}
public File findFile(String name) {
for(File i : getFolders(name)) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".iob") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return j;
}
}
File file = new File(i, name + ".iob");
if(file.exists()) {
return file;
}
}
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);
return null;
}
public IrisObject load(String name) {
return load(name, true);
}
private IrisObject loadRaw(String name) {
for(File i : getFolders(name)) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".iob") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return loadFile(j, name);
}
}
File file = new File(i, name + ".iob");
if(file.exists()) {
return loadFile(file, name);
}
}
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);
return null;
}
public IrisObject load(String name, boolean warn) {
return loadCache.get(name);
}
}

View File

@ -1,400 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.loader;
import com.google.common.util.concurrent.AtomicDouble;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.project.SchemaBuilder;
import com.volmit.iris.core.service.PreservationSVC;
import com.volmit.iris.engine.framework.MeteredCache;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Data;
import java.io.File;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
@Data
public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
public static final AtomicDouble tlt = new AtomicDouble(0);
private static final int CACHE_SIZE = 100000;
protected File root;
protected String folderName;
protected String resourceTypeName;
protected KCache<String, T> loadCache;
protected final AtomicReference<KList<File>> folderCache;
protected Class<? extends T> objectClass;
protected String cname;
protected String[] possibleKeys = null;
protected IrisData manager;
protected AtomicInteger loads;
protected ChronoLatch sec;
public ResourceLoader(File root, IrisData manager, String folderName, String resourceTypeName, Class<? extends T> objectClass) {
this.manager = manager;
folderCache = new AtomicReference<>();
sec = new ChronoLatch(5000);
loads = new AtomicInteger();
this.objectClass = objectClass;
cname = objectClass.getCanonicalName();
this.resourceTypeName = resourceTypeName;
this.root = root;
this.folderName = folderName;
loadCache = new KCache<>(this::loadRaw, IrisSettings.get().getPerformance().getResourceLoaderCacheSize());
Iris.debug("Loader<" + C.GREEN + resourceTypeName + C.LIGHT_PURPLE + "> created in " + C.RED + "IDM/" + manager.getId() + C.LIGHT_PURPLE + " on " + C.GRAY + manager.getDataFolder().getPath());
Iris.service(PreservationSVC.class).registerCache(this);
}
public JSONObject buildSchema() {
Iris.debug("Building Schema " + objectClass.getSimpleName() + " " + root.getPath());
JSONObject o = new JSONObject();
KList<String> fm = new KList<>();
for(int g = 1; g < 8; g++) {
fm.add("/" + folderName + Form.repeat("/*", g) + ".json");
}
o.put("fileMatch", new JSONArray(fm.toArray()));
o.put("url", "./.iris/schema/" + getFolderName() + "-schema.json");
File a = new File(getManager().getDataFolder(), ".iris/schema/" + getFolderName() + "-schema.json");
J.attemptAsync(() -> IO.writeAll(a, new SchemaBuilder(objectClass, manager).construct().toString(4)));
return o;
}
public File findFile(String name) {
for(File i : getFolders(name)) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".json") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return j;
}
}
File file = new File(i, name + ".json");
if(file.exists()) {
return file;
}
}
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);
return null;
}
public void logLoad(File path, T t) {
loads.getAndIncrement();
if(loads.get() == 1) {
sec.flip();
}
if(sec.flip()) {
J.a(() -> {
Iris.verbose("Loaded " + C.WHITE + loads.get() + " " + resourceTypeName + (loads.get() == 1 ? "" : "s") + C.GRAY + " (" + Form.f(getLoadCache().getSize()) + " " + resourceTypeName + (loadCache.getSize() == 1 ? "" : "s") + " Loaded)");
loads.set(0);
});
}
Iris.debug("Loader<" + C.GREEN + resourceTypeName + C.LIGHT_PURPLE + "> iload " + C.YELLOW + t.getLoadKey() + C.LIGHT_PURPLE + " in " + C.GRAY + t.getLoadFile().getPath() + C.LIGHT_PURPLE + " TLT: " + C.RED + Form.duration(tlt.get(), 2));
}
public void failLoad(File path, Throwable e) {
J.a(() -> Iris.warn("Couldn't Load " + resourceTypeName + " file: " + path.getPath() + ": " + e.getMessage()));
}
private KList<File> matchAllFiles(File root, Predicate<File> f) {
KList<File> fx = new KList<>();
matchFiles(root, fx, f);
return fx;
}
private void matchFiles(File at, KList<File> files, Predicate<File> f) {
if(at.isDirectory()) {
for(File i : at.listFiles()) {
matchFiles(i, files, f);
}
} else {
if(f.test(at)) {
files.add(at);
}
}
}
public String[] getPossibleKeys() {
if(possibleKeys != null) {
return possibleKeys;
}
KSet<String> m = new KSet<>();
KList<File> files = getFolders();
if(files == null) {
possibleKeys = new String[0];
return possibleKeys;
}
for(File i : files) {
for(File j : matchAllFiles(i, (f) -> f.getName().endsWith(".json"))) {
m.add(i.toURI().relativize(j.toURI()).getPath().replaceAll("\\Q.json\\E", ""));
}
}
KList<String> v = new KList<>(m);
possibleKeys = v.toArray(new String[0]);
return possibleKeys;
}
public long count() {
return loadCache.getSize();
}
protected T loadFile(File j, String name) {
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
T t = getManager().getGson()
.fromJson(preprocess(new JSONObject(IO.readAll(j))).toString(0), objectClass);
t.setLoadKey(name);
t.setLoadFile(j);
t.setLoader(manager);
getManager().preprocessObject(t);
logLoad(j, t);
tlt.addAndGet(p.getMilliseconds());
return t;
} catch(Throwable e) {
Iris.reportError(e);
failLoad(j, e);
return null;
}
}
protected JSONObject preprocess(JSONObject j) {
return j;
}
public Stream<T> streamAll(Stream<String> s) {
return s.map(this::load);
}
public KList<T> loadAll(KList<String> s) {
KList<T> m = new KList<>();
for(String i : s) {
T t = load(i);
if(t != null) {
m.add(t);
}
}
return m;
}
public KList<T> loadAll(KList<String> s, Consumer<T> postLoad) {
KList<T> m = new KList<>();
for(String i : s) {
T t = load(i);
if(t != null) {
m.add(t);
postLoad.accept(t);
}
}
return m;
}
public KList<T> loadAll(String[] s) {
KList<T> m = new KList<>();
for(String i : s) {
T t = load(i);
if(t != null) {
m.add(t);
}
}
return m;
}
public T load(String name) {
return load(name, true);
}
private T loadRaw(String name) {
for(File i : getFolders(name)) {
//noinspection ConstantConditions
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".json") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return loadFile(j, name);
}
}
File file = new File(i, name + ".json");
if(file.exists()) {
return loadFile(file, name);
}
}
return null;
}
public T load(String name, boolean warn) {
if(name == null) {
return null;
}
if(name.trim().isEmpty()) {
return null;
}
return loadCache.get(name);
}
public KList<File> getFolders() {
synchronized(folderCache) {
if(folderCache.get() == null) {
KList<File> fc = new KList<>();
for(File i : root.listFiles()) {
if(i.isDirectory()) {
if(i.getName().equals(folderName)) {
fc.add(i);
break;
}
}
}
folderCache.set(fc);
}
}
return folderCache.get();
}
public KList<File> getFolders(String rc) {
KList<File> folders = getFolders().copy();
if(rc.contains(":")) {
for(File i : folders.copy()) {
if(!rc.startsWith(i.getName() + ":")) {
folders.remove(i);
}
}
}
return folders;
}
public void clearCache() {
possibleKeys = null;
loadCache.invalidate();
folderCache.set(null);
}
public File fileFor(T b) {
for(File i : getFolders()) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".json") && j.getName().split("\\Q.\\E")[0].equals(b.getLoadKey())) {
return j;
}
}
File file = new File(i, b.getLoadKey() + ".json");
if(file.exists()) {
return file;
}
}
return null;
}
public boolean isLoaded(String next) {
return loadCache.contains(next);
}
public void clearList() {
folderCache.set(null);
possibleKeys = null;
}
public KList<String> getPossibleKeys(String arg) {
KList<String> f = new KList<>();
for(String i : getPossibleKeys()) {
if(i.equalsIgnoreCase(arg) || i.toLowerCase(Locale.ROOT).startsWith(arg.toLowerCase(Locale.ROOT)) || i.toLowerCase(Locale.ROOT).contains(arg.toLowerCase(Locale.ROOT)) || arg.toLowerCase(Locale.ROOT).contains(i.toLowerCase(Locale.ROOT))) {
f.add(i);
}
}
return f;
}
public boolean supportsSchemas() {
return true;
}
public void clean() {
}
public long getSize() {
return loadCache.getSize();
}
@Override
public KCache<?, ?> getRawCache() {
return loadCache;
}
@Override
public long getMaxSize() {
return loadCache.getMaxSize();
}
@Override
public boolean isClosed() {
return getManager().isClosed();
}
public long getTotalStorage() {
return getSize();
}
}

View File

@ -1,139 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.loader;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.object.IrisScript;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import java.io.File;
public class ScriptResourceLoader extends ResourceLoader<IrisScript> {
public ScriptResourceLoader(File root, IrisData idm, String folderName, String resourceTypeName) {
super(root, idm, folderName, resourceTypeName, IrisScript.class);
loadCache = new KCache<>(this::loadRaw, IrisSettings.get().getPerformance().getScriptLoaderCacheSize());
}
public boolean supportsSchemas() {
return false;
}
public long getSize() {
return loadCache.getSize();
}
protected IrisScript loadFile(File j, String name) {
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
IrisScript t = new IrisScript(IO.readAll(j));
t.setLoadKey(name);
t.setLoader(manager);
t.setLoadFile(j);
logLoad(j, t);
tlt.addAndGet(p.getMilliseconds());
return t;
} catch(Throwable e) {
Iris.reportError(e);
Iris.warn("Couldn't read " + resourceTypeName + " file: " + j.getPath() + ": " + e.getMessage());
return null;
}
}
public String[] getPossibleKeys() {
if(possibleKeys != null) {
return possibleKeys;
}
Iris.debug("Building " + resourceTypeName + " Possibility Lists");
KSet<String> m = new KSet<>();
for(File i : getFolders()) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".js")) {
m.add(j.getName().replaceAll("\\Q.js\\E", ""));
} else if(j.isDirectory()) {
for(File k : j.listFiles()) {
if(k.isFile() && k.getName().endsWith(".js")) {
m.add(j.getName() + "/" + k.getName().replaceAll("\\Q.js\\E", ""));
} else if(k.isDirectory()) {
for(File l : k.listFiles()) {
if(l.isFile() && l.getName().endsWith(".js")) {
m.add(j.getName() + "/" + k.getName() + "/" + l.getName().replaceAll("\\Q.js\\E", ""));
}
}
}
}
}
}
}
KList<String> v = new KList<>(m);
possibleKeys = v.toArray(new String[0]);
return possibleKeys;
}
public File findFile(String name) {
for(File i : getFolders(name)) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".js") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return j;
}
}
File file = new File(i, name + ".js");
if(file.exists()) {
return file;
}
}
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);
return null;
}
private IrisScript loadRaw(String name) {
for(File i : getFolders(name)) {
for(File j : i.listFiles()) {
if(j.isFile() && j.getName().endsWith(".js") && j.getName().split("\\Q.\\E")[0].equals(name)) {
return loadFile(j, name);
}
}
File file = new File(i, name + ".js");
if(file.exists()) {
return loadFile(file, name);
}
}
Iris.warn("Couldn't find " + resourceTypeName + ": " + name);
return null;
}
public IrisScript load(String name, boolean warn) {
return loadCache.get(name);
}
}

View File

@ -1,28 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.nms;
@FunctionalInterface
public interface BiomeBaseInjector {
default void setBiome(int x, int z, Object biomeBase) {
setBiome(x, 0, z, biomeBase);
}
void setBiome(int x, int y, int z, Object biomeBase);
}

View File

@ -1,77 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.nms;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.nms.v19_1.NMSBinding19_1;
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.util.collection.KMap;
import org.bukkit.Bukkit;
public class INMS {
//@builder
private static final KMap<String, Class<? extends INMSBinding>> bindings = new KMap<String, Class<? extends INMSBinding>>()
.qput("v1_19_R1", NMSBinding19_1.class);
//@done
private static final INMSBinding binding = bind();
public static INMSBinding get() {
return binding;
}
public static String getNMSTag() {
if(IrisSettings.get().getGeneral().isDisableNMS()) {
return "BUKKIT";
}
try {
return Bukkit.getServer().getClass().getCanonicalName().split("\\Q.\\E")[3];
} catch(Throwable e) {
Iris.reportError(e);
Iris.error("Failed to determine server nms version!");
e.printStackTrace();
}
return "BUKKIT";
}
private static INMSBinding bind() {
String code = getNMSTag();
Iris.info("Locating NMS Binding for " + code);
if(bindings.containsKey(code)) {
try {
INMSBinding b = bindings.get(code).getConstructor().newInstance();
Iris.info("Craftbukkit " + code + " <-> " + b.getClass().getSimpleName() + " Successfully Bound");
return b;
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
}
Iris.info("Craftbukkit " + code + " <-> " + NMSBinding1X.class.getSimpleName() + " Successfully Bound");
Iris.warn("Note: Some features of Iris may not work the same since you are on an unsupported version of Minecraft.");
Iris.warn("Note: If this is a new version, expect an update soon.");
return new NMSBinding1X();
}
}

View File

@ -1,86 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.nms;
import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer;
import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess;
import com.volmit.iris.util.nbt.tag.CompoundTag;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.block.Biome;
import org.bukkit.entity.Entity;
import org.bukkit.generator.ChunkGenerator;
public interface INMSBinding {
boolean hasTile(Location l);
CompoundTag serializeTile(Location location);
void deserializeTile(CompoundTag s, Location newPosition);
CompoundTag serializeEntity(Entity location);
Entity deserializeEntity(CompoundTag s, Location newPosition);
boolean supportsCustomHeight();
Object getBiomeBaseFromId(int id);
int getMinHeight(World world);
boolean supportsCustomBiomes();
int getTrueBiomeBaseId(Object biomeBase);
Object getTrueBiomeBase(Location location);
String getTrueBiomeBaseKey(Location location);
Object getCustomBiomeBaseFor(String mckey);
Object getCustomBiomeBaseHolderFor(String mckey);
String getKeyForBiomeBase(Object biomeBase);
Object getBiomeBase(World world, Biome biome);
Object getBiomeBase(Object registry, Biome biome);
boolean isBukkit();
int getBiomeId(Biome biome);
MCABiomeContainer newBiomeContainer(int min, int max, int[] data);
MCABiomeContainer newBiomeContainer(int min, int max);
default World createWorld(WorldCreator c) {
return c.createWorld();
}
int countCustomBiomes();
void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk);
default boolean supportsDataPacks() {
return false;
}
MCAPaletteAccess createPalette();
}

View File

@ -1,159 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.nms;
import com.volmit.iris.Iris;
import java.util.ArrayList;
import java.util.List;
public enum NMSVersion {
R1_19_1,
R1_18_2,
R1_18,
R1_17,
R1_16,
R1_15,
R1_14,
R1_13,
R1_13_1,
R1_12,
R1_11,
R1_10,
R1_9_4,
R1_9_2,
R1_8;
public static NMSVersion getMinimum() {
return values()[values().length - 1];
}
public static NMSVersion getMaximum() {
return values()[0];
}
public static NMSVersion current() {
if(tryVersion("1_8_R3")) {
return R1_8;
}
if(tryVersion("1_9_R1")) {
return R1_9_2;
}
if(tryVersion("1_9_R2")) {
return R1_9_4;
}
if(tryVersion("1_10_R1")) {
return R1_10;
}
if(tryVersion("1_11_R1")) {
return R1_11;
}
if(tryVersion("1_12_R1")) {
return R1_12;
}
if(tryVersion("1_13_R1")) {
return R1_13;
}
if(tryVersion("1_13_R2")) {
return R1_13_1;
}
if(tryVersion("1_14_R1")) {
return R1_14;
}
if(tryVersion("1_15_R1")) {
return R1_15;
}
if(tryVersion("1_16_R1")) {
return R1_16;
}
if(tryVersion("1_17_R1")) {
return R1_17;
}
if(tryVersion("1_18_R1")) {
return R1_18;
}
if(tryVersion("1_18_R2")) {
return R1_18_2;
}
if(tryVersion("1_19_R1")) {
return R1_19_1;
}
return null;
}
private static boolean tryVersion(String v) {
try {
Class.forName("org.bukkit.craftbukkit.v" + v + ".CraftWorld");
return true;
} catch(Throwable e) {
Iris.reportError(e);
}
return false;
}
public List<NMSVersion> getAboveInclusive() {
List<NMSVersion> n = new ArrayList<>();
for(NMSVersion i : values()) {
if(i.ordinal() >= ordinal()) {
n.add(i);
}
}
return n;
}
public List<NMSVersion> betweenInclusive(NMSVersion other) {
List<NMSVersion> n = new ArrayList<>();
for(NMSVersion i : values()) {
if(i.ordinal() <= Math.max(other.ordinal(), ordinal()) && i.ordinal() >= Math.min(ordinal(), other.ordinal())) {
n.add(i);
}
}
return n;
}
public List<NMSVersion> getBelowInclusive() {
List<NMSVersion> n = new ArrayList<>();
for(NMSVersion i : values()) {
if(i.ordinal() <= ordinal()) {
n.add(i);
}
}
return n;
}
}

View File

@ -1,480 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.nms.v19_1;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMSBinding;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.nbt.io.NBTUtil;
import com.volmit.iris.util.nbt.mca.NBTWorld;
import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer;
import com.volmit.iris.util.nbt.mca.palette.MCAChunkBiomeContainer;
import com.volmit.iris.util.nbt.mca.palette.MCAGlobalPalette;
import com.volmit.iris.util.nbt.mca.palette.MCAIdMap;
import com.volmit.iris.util.nbt.mca.palette.MCAIdMapper;
import com.volmit.iris.util.nbt.mca.palette.MCAPalette;
import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess;
import com.volmit.iris.util.nbt.mca.palette.MCAPalettedContainer;
import com.volmit.iris.util.nbt.mca.palette.MCAWrappedPalettedContainer;
import com.volmit.iris.util.nbt.tag.CompoundTag;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.core.*;
import net.minecraft.nbt.NbtIo;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.BitStorage;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.Palette;
import net.minecraft.world.level.chunk.PalettedContainer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_19_R1.CraftServer;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData;
import org.bukkit.entity.Entity;
import org.bukkit.generator.ChunkGenerator;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class NMSBinding19_1 implements INMSBinding {
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
private final BlockData AIR = Material.AIR.createBlockData();
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
private Field biomeStorageCache = null;
@Override
public boolean hasTile(Location l) {
return ((CraftWorld) l.getWorld()).getHandle().getBlockEntity(new BlockPos(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null;
}
@Override
public CompoundTag serializeTile(Location location) {
BlockEntity e = ((CraftWorld) location.getWorld()).getHandle().getBlockEntity(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true);
if(e == null) {
return null;
}
net.minecraft.nbt.CompoundTag tag = e.saveWithFullMetadata();
return convert(tag);
}
private CompoundTag convert(net.minecraft.nbt.CompoundTag tag) {
try {
ByteArrayOutputStream boas = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(boas);
tag.write(dos);
dos.close();
return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag();
} catch(Throwable ex) {
ex.printStackTrace();
}
return null;
}
private net.minecraft.nbt.CompoundTag convert(CompoundTag tag) {
try {
ByteArrayOutputStream boas = new ByteArrayOutputStream();
NBTUtil.write(tag, boas, false);
DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray()));
net.minecraft.nbt.CompoundTag c = NbtIo.read(din);
din.close();
return c;
} catch(Throwable e) {
e.printStackTrace();
}
return null;
}
@Override
public void deserializeTile(CompoundTag c, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c));
}
@Override
public CompoundTag serializeEntity(Entity location) {
return null;// TODO:
}
@Override
public Entity deserializeEntity(CompoundTag s, Location newPosition) {
return null;// TODO:
}
@Override
public boolean supportsCustomHeight() {
return true;
}
private RegistryAccess registry() {
return registryAccess.aquire(() -> (RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer()));
}
private Registry<net.minecraft.world.level.biome.Biome> getCustomBiomeRegistry() {
return registry().registry(Registry.BIOME_REGISTRY).orElse(null);
}
private Registry<Block> getBlockRegistry() {
return registry().registry(Registry.BLOCK_REGISTRY).orElse(null);
}
@Override
public Object getBiomeBaseFromId(int id) {
try {
return byIdRef.aquire(() -> {
for(Method i : IdMap.class.getDeclaredMethods()) {
if(i.getParameterCount() == 1 && i.getParameterTypes()[0].equals(int.class)) {
Iris.info("[NMS] Found byId method in " + IdMap.class.getSimpleName() + "." + i.getName() + "(int) => " + Biome.class.getSimpleName());
return i;
}
}
Iris.error("Cannot find byId method!");
return null;
}).invoke(getCustomBiomeRegistry(), id);
} catch(IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
@Override
public int getMinHeight(World world) {
return world.getMinHeight();
}
@Override
public boolean supportsCustomBiomes() {
return true;
}
@Override
public int getTrueBiomeBaseId(Object biomeBase) {
return getCustomBiomeRegistry().getId((net.minecraft.world.level.biome.Biome) biomeBase);
}
@Override
public Object getTrueBiomeBase(Location location) {
return ((CraftWorld) location.getWorld()).getHandle().getBiome(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()));
}
@Override
public String getTrueBiomeBaseKey(Location location) {
return getKeyForBiomeBase(getTrueBiomeBase(location));
}
@Override
public Object getCustomBiomeBaseFor(String mckey) {
return getCustomBiomeRegistry().get(new ResourceLocation(mckey));
}
@Override
public Object getCustomBiomeBaseHolderFor(String mckey) {
return getCustomBiomeRegistry().getHolder(getTrueBiomeBaseId(getCustomBiomeRegistry().get(new ResourceLocation(mckey)))).get();
}
@Override
public String getKeyForBiomeBase(Object biomeBase) {
return getCustomBiomeRegistry().getKey((net.minecraft.world.level.biome.Biome) biomeBase).getPath(); // something, not something:something
}
@Override
public Object getBiomeBase(World world, Biome biome) {
return getBiomeBase(((CraftWorld) world).getHandle().registryAccess().registry(Registry.BIOME_REGISTRY).orElse(null), biome);
}
@Override
public Object getBiomeBase(Object registry, Biome biome) {
Object v = baseBiomeCache.get(biome);
if(v != null) {
return v;
}
//noinspection unchecked
v = org.bukkit.craftbukkit.v1_19_R1.block.CraftBlock.biomeToBiomeBase((Registry<net.minecraft.world.level.biome.Biome>) registry, biome);
if(v == null) {
// Ok so there is this new biome name called "CUSTOM" in Paper's new releases.
// But, this does NOT exist within CraftBukkit which makes it return an error.
// So, we will just return the ID that the plains biome returns instead.
//noinspection unchecked
return org.bukkit.craftbukkit.v1_19_R1.block.CraftBlock.biomeToBiomeBase((Registry<net.minecraft.world.level.biome.Biome>) registry, Biome.PLAINS);
}
baseBiomeCache.put(biome, v);
return v;
}
@Override
public boolean isBukkit() {
return true;
}
@Override
public int getBiomeId(Biome biome) {
for(World i : Bukkit.getWorlds()) {
if(i.getEnvironment().equals(World.Environment.NORMAL)) {
Registry<net.minecraft.world.level.biome.Biome> registry = ((CraftWorld) i).getHandle().registryAccess().registry(Registry.BIOME_REGISTRY).orElse(null);
return registry.getId((net.minecraft.world.level.biome.Biome) getBiomeBase(registry, biome));
}
}
return biome.ordinal();
}
private MCAIdMap<net.minecraft.world.level.biome.Biome> getBiomeMapping() {
return biomeMapCache.aquire(() -> new MCAIdMap<>() {
@NotNull
@Override
public Iterator<net.minecraft.world.level.biome.Biome> iterator() {
return getCustomBiomeRegistry().iterator();
}
@Override
public int getId(net.minecraft.world.level.biome.Biome paramT) {
return getCustomBiomeRegistry().getId(paramT);
}
@Override
public net.minecraft.world.level.biome.Biome byId(int paramInt) {
return (net.minecraft.world.level.biome.Biome) getBiomeBaseFromId(paramInt);
}
});
}
@NotNull
private MCABiomeContainer getBiomeContainerInterface(MCAIdMap<net.minecraft.world.level.biome.Biome> biomeMapping, MCAChunkBiomeContainer<net.minecraft.world.level.biome.Biome> base) {
return new MCABiomeContainer() {
@Override
public int[] getData() {
return base.writeBiomes();
}
@Override
public void setBiome(int x, int y, int z, int id) {
base.setBiome(x, y, z, biomeMapping.byId(id));
}
@Override
public int getBiome(int x, int y, int z) {
return biomeMapping.getId(base.getBiome(x, y, z));
}
};
}
@Override
public MCABiomeContainer newBiomeContainer(int min, int max) {
MCAChunkBiomeContainer<net.minecraft.world.level.biome.Biome> base = new MCAChunkBiomeContainer<>(getBiomeMapping(), min, max);
return getBiomeContainerInterface(getBiomeMapping(), base);
}
@Override
public MCABiomeContainer newBiomeContainer(int min, int max, int[] data) {
MCAChunkBiomeContainer<net.minecraft.world.level.biome.Biome> base = new MCAChunkBiomeContainer<>(getBiomeMapping(), min, max, data);
return getBiomeContainerInterface(getBiomeMapping(), base);
}
@Override
public int countCustomBiomes() {
AtomicInteger a = new AtomicInteger(0);
getCustomBiomeRegistry().keySet().forEach((i) -> {
if(i.getNamespace().equals("minecraft")) {
return;
}
a.incrementAndGet();
Iris.debug("Custom Biome: " + i);
});
return a.get();
}
public boolean supportsDataPacks() {
return true;
}
@Override
public void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk) {
try {
ChunkAccess s = (ChunkAccess) getFieldForBiomeStorage(chunk).get(chunk);
Holder<net.minecraft.world.level.biome.Biome> biome = (Holder<net.minecraft.world.level.biome.Biome>) somethingVeryDirty;
s.setBiome(x, y, z, biome);
/*int l = QuartPos.fromBlock(s.getMinBuildHeight());
int i1 = l + QuartPos.fromBlock(s.getHeight()) - 1;
PalettedContainer<Holder<net.minecraft.world.level.biome.Biome>> palette = getPalette(s, s.getSectionIndex(QuartPos.toBlock(Mth.clamp(y, l, i1))));
int index = getPaletteIndex(x, y, z, s, palette);
int data = getPaletteDataId(palette, biome);
setPaletteData(palette, index, data);*/
} catch(IllegalAccessException e) {
Iris.reportError(e);
e.printStackTrace();
}
}
private PalettedContainer<Holder<net.minecraft.world.level.biome.Biome>> getPalette(ChunkAccess ca, int index) {
LevelChunkSection[] sections = fieldForClass(LevelChunkSection[].class, ChunkAccess.class, ca);
return fieldForClass(PalettedContainer.class, LevelChunkSection.class, sections[index]);
}
private int getPaletteIndex(int x, int y, int z, ChunkAccess s, PalettedContainer<?> palette) {
int l = QuartPos.fromBlock(s.getMinBuildHeight());
int i1 = l + QuartPos.fromBlock(s.getHeight()) - 1;
int j1 = Mth.clamp(y, l, i1);
return fieldForClass(PalettedContainer.Strategy.class, PalettedContainer.class, palette).getIndex(x & 3, j1 & 3, z & 3);
}
private <T extends Holder<?>> int getPaletteDataId(PalettedContainer<T> palette, T data) throws ClassNotFoundException {
Class<?> dataType = getClassType(PalettedContainer.class, 1);
Object paletteData = fieldFor(dataType, palette);
Palette<T> fuckinFinally = fieldForClass(Palette.class,dataType, paletteData);
return fuckinFinally.idFor(data);
}
private void setPaletteData(PalettedContainer<?> palette, int index, int data) throws ClassNotFoundException {
Class<?> dataType = getClassType(PalettedContainer.class, 1);
Object paletteData = fieldFor(dataType, palette);
BitStorage storage = fieldForClass(BitStorage.class, dataType, paletteData);
storage.set(index, data);
}
private Field getFieldForBiomeStorage(Object storage) {
Field f = biomeStorageCache;
if(f != null) {
return f;
}
try {
f = storage.getClass().getDeclaredField("biome");
f.setAccessible(true);
return f;
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
Iris.error(storage.getClass().getCanonicalName());
}
biomeStorageCache = f;
return null;
}
@Override
public MCAPaletteAccess createPalette() {
MCAIdMapper<BlockState> registry = registryCache.aquireNasty(() -> {
Field cf = net.minecraft.core.IdMapper.class.getDeclaredField("tToId");
Field df = net.minecraft.core.IdMapper.class.getDeclaredField("idToT");
Field bf = net.minecraft.core.IdMapper.class.getDeclaredField("nextId");
cf.setAccessible(true);
df.setAccessible(true);
bf.setAccessible(true);
net.minecraft.core.IdMapper<BlockState> blockData = Block.BLOCK_STATE_REGISTRY;
int b = bf.getInt(blockData);
Object2IntMap<BlockState> c = (Object2IntMap<BlockState>) cf.get(blockData);
List<BlockState> d = (List<BlockState>) df.get(blockData);
return new MCAIdMapper<BlockState>(c, d, b);
});
MCAPalette<BlockState> global = globalCache.aquireNasty(() -> new MCAGlobalPalette<>(registry, ((CraftBlockData) AIR).getState()));
MCAPalettedContainer<BlockState> container = new MCAPalettedContainer<>(global, registry,
i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState(),
i -> NBTWorld.getCompound(CraftBlockData.fromData(i)),
((CraftBlockData) AIR).getState());
return new MCAWrappedPalettedContainer<>(container,
i -> NBTWorld.getCompound(CraftBlockData.fromData(i)),
i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState());
}
private static Object getFor(Class<?> type, Object source) {
Object o = fieldFor(type, source);
if(o != null) {
return o;
}
return invokeFor(type, source);
}
private static Object invokeFor(Class<?> returns, Object in) {
for(Method i : in.getClass().getMethods()) {
if(i.getReturnType().equals(returns)) {
i.setAccessible(true);
try {
Iris.debug("[NMS] Found " + returns.getSimpleName() + " in " + in.getClass().getSimpleName() + "." + i.getName() + "()");
return i.invoke(in);
} catch(Throwable e) {
e.printStackTrace();
}
}
}
return null;
}
private static Object fieldFor(Class<?> returns, Object in) {
return fieldForClass(returns, in.getClass(), in);
}
@SuppressWarnings("unchecked")
private static <T> T fieldForClass(Class<T> returnType, Class<?> sourceType, Object in) {
for(Field i : sourceType.getDeclaredFields()) {
if(i.getType().equals(returnType)) {
i.setAccessible(true);
try {
Iris.debug("[NMS] Found " + returnType.getSimpleName() + " in " + sourceType.getSimpleName() + "." + i.getName());
return (T) i.get(in);
} catch(IllegalAccessException e) {
e.printStackTrace();
}
}
}
return null;
}
private static Class<?> getClassType(Class<?> type, int ordinal) {
return type.getDeclaredClasses()[ordinal];
}
}

View File

@ -1,173 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.nms.v1X;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMSBinding;
import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer;
import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess;
import com.volmit.iris.util.nbt.tag.CompoundTag;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.entity.Entity;
import org.bukkit.generator.ChunkGenerator;
public class NMSBinding1X implements INMSBinding {
private static final boolean supportsCustomHeight = testCustomHeight();
@SuppressWarnings("ConstantConditions")
private static boolean testCustomHeight() {
try {
if(World.class.getDeclaredMethod("getMaxHeight") != null && World.class.getDeclaredMethod("getMinHeight") != null)
;
{
return true;
}
} catch(Throwable ignored) {
}
return false;
}
@Override
public boolean hasTile(Location l) {
return false;
}
@Override
public CompoundTag serializeTile(Location location) {
return null;
}
@Override
public void deserializeTile(CompoundTag s, Location newPosition) {
}
@Override
public CompoundTag serializeEntity(Entity location) {
return null;
}
@Override
public Entity deserializeEntity(CompoundTag s, Location newPosition) {
return null;
}
@Override
public boolean supportsCustomHeight() {
return supportsCustomHeight;
}
@Override
public Object getBiomeBaseFromId(int id) {
return null;
}
@Override
public int getMinHeight(World world) {
return supportsCustomHeight ? world.getMinHeight() : 0;
}
@Override
public boolean supportsCustomBiomes() {
return false;
}
@Override
public int getTrueBiomeBaseId(Object biomeBase) {
return 0;
}
@Override
public Object getTrueBiomeBase(Location location) {
return null;
}
@Override
public String getTrueBiomeBaseKey(Location location) {
return null;
}
@Override
public Object getCustomBiomeBaseFor(String mckey) {
return null;
}
@Override
public Object getCustomBiomeBaseHolderFor(String mckey) {
return null;
}
@Override
public String getKeyForBiomeBase(Object biomeBase) {
return null;
}
public Object getBiomeBase(World world, Biome biome) {
return null;
}
@Override
public Object getBiomeBase(Object registry, Biome biome) {
return null;
}
@Override
public boolean isBukkit() {
return true;
}
@Override
public int getBiomeId(Biome biome) {
return biome.ordinal();
}
@Override
public MCABiomeContainer newBiomeContainer(int min, int max) {
Iris.error("Cannot use the custom biome data! Iris is incapable of using MCA generation on this version of minecraft!");
return null;
}
@Override
public MCABiomeContainer newBiomeContainer(int min, int max, int[] v) {
Iris.error("Cannot use the custom biome data! Iris is incapable of using MCA generation on this version of minecraft!");
return null;
}
@Override
public int countCustomBiomes() {
return 0;
}
@Override
public void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk) {
}
@Override
public MCAPaletteAccess createPalette() {
Iris.error("Cannot use the global data palette! Iris is incapable of using MCA generation on this version of minecraft!");
return null;
}
}

View File

@ -1,400 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pack;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisWorld;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.exceptions.IrisException;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Data;
import org.bukkit.World;
import org.zeroturnaround.zip.commons.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
/**
* Represents an Iris pack that exists
*/
@Data
public class IrisPack {
private final File folder;
private final IrisData data;
/**
* Create an iris pack backed by a data folder
* the data folder is assumed to be in the Iris/packs/NAME folder
*
* @param name
* the name
*/
public IrisPack(String name) {
this(packsPack(name));
}
/**
* Create an iris pack backed by a data folder
*
* @param folder
* the folder of the pack. Must be a directory
*/
public IrisPack(File folder) {
this.folder = folder;
if(!folder.exists()) {
throw new RuntimeException("Cannot open Pack " + folder.getPath() + " (directory doesnt exist)");
}
if(!folder.isDirectory()) {
throw new RuntimeException("Cannot open Pack " + folder.getPath() + " (not a directory)");
}
this.data = IrisData.get(folder);
}
/**
* Create a new pack from the input url
*
* @param sender
* the sender
* @param url
* the url, or name, or really anything see IrisPackRepository.from(String)
* @return the iris pack
* @throws IrisException
* fails
*/
public static Future<IrisPack> from(VolmitSender sender, String url) throws IrisException {
IrisPackRepository repo = IrisPackRepository.from(url);
if(repo == null) {
throw new IrisException("Null Repo");
}
try {
return from(sender, repo);
} catch(MalformedURLException e) {
throw new IrisException("Malformed URL " + e.getMessage());
}
}
/**
* Create a pack from a repo
*
* @param sender
* the sender
* @param repo
* the repo
* @return the pack
* @throws MalformedURLException
* shit happens
*/
public static Future<IrisPack> from(VolmitSender sender, IrisPackRepository repo) throws MalformedURLException {
CompletableFuture<IrisPack> pack = new CompletableFuture<>();
repo.install(sender, () -> {
pack.complete(new IrisPack(repo.getRepo()));
});
return pack;
}
/**
* Create a blank pack with a given name
*
* @param name
* the name of the pack
* @return the pack
* @throws IrisException
* if the pack already exists or another error
*/
public static IrisPack blank(String name) throws IrisException {
File f = packsPack(name);
if(f.exists()) {
throw new IrisException("Already exists");
}
File fd = new File(f, "dimensions/" + name + ".json");
fd.getParentFile().mkdirs();
try {
IO.writeAll(fd, "{\n" +
" \"name\": \"" + Form.capitalize(name) + "\",\n" +
" \"version\": 1\n" +
"}\n");
} catch(IOException e) {
throw new IrisException(e.getMessage(), e);
}
IrisPack pack = new IrisPack(f);
pack.updateWorkspace();
return pack;
}
/**
* Get a packs pack folder for a name. Such that overworld would resolve as Iris/packs/overworld
*
* @param name
* the name
* @return the file path
*/
public static File packsPack(String name) {
return Iris.instance.getDataFolderNoCreate(StudioSVC.WORKSPACE_NAME, name);
}
private static KList<File> collectFiles(File f, String fileExtension) {
KList<File> l = new KList<>();
if(f.isDirectory()) {
for(File i : f.listFiles()) {
l.addAll(collectFiles(i, fileExtension));
}
} else if(f.getName().endsWith("." + fileExtension)) {
l.add(f);
}
return l;
}
/**
* Delete this pack. This invalidates this pack and you should
* probably no longer use this instance after deleting this pack
*/
public void delete() {
IO.delete(folder);
folder.delete();
}
/**
* Get the name of this pack
*
* @return the pack name
*/
public String getName() {
return folder.getName();
}
/**
* Get the file path of the workspace file
*
* @return the workspace file path
*/
public File getWorkspaceFile() {
return new File(getFolder(), getName() + ".code-workspace");
}
/**
* Update the workspace file
*
* @return true if it was updated
*/
public boolean updateWorkspace() {
getFolder().mkdirs();
File ws = getWorkspaceFile();
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
Iris.debug("Building Workspace: " + ws.getPath());
JSONObject j = generateWorkspaceConfig();
IO.writeAll(ws, j.toString(4));
p.end();
Iris.debug("Building Workspace: " + ws.getPath() + " took " + Form.duration(p.getMilliseconds(), 2));
return true;
} catch(Throwable e) {
Iris.reportError(e);
Iris.warn("Pack invalid: " + ws.getAbsolutePath() + " Re-creating. You may loose some vs-code workspace settings! But not your actual project!");
ws.delete();
try {
IO.writeAll(ws, generateWorkspaceConfig());
} catch(IOException e1) {
Iris.reportError(e1);
e1.printStackTrace();
}
}
return false;
}
/**
* Install this pack into a world
*
* @param world
* the world to install into (world/iris/pack)
* @return the installed pack
*/
public IrisPack install(World world) throws IrisException {
return install(new File(world.getWorldFolder(), "iris/pack"));
}
/**
* Install this pack into a world
*
* @param world
* the world to install into (world/iris/pack)
* @return the installed pack
*/
public IrisPack install(IrisWorld world) throws IrisException {
return install(new File(world.worldFolder(), "iris/pack"));
}
/**
* Install this pack into a world
*
* @param folder
* the folder to install this pack into
* @return the installed pack
*/
public IrisPack install(File folder) throws IrisException {
if(folder.exists()) {
throw new IrisException("Cannot install new pack because the folder " + folder.getName() + " already exists!");
}
folder.mkdirs();
try {
FileUtils.copyDirectory(getFolder(), folder);
} catch(IOException e) {
Iris.reportError(e);
}
return new IrisPack(folder);
}
/**
* Create a new pack using this pack as a template. The new pack will be renamed & have a renamed dimension
* to match it.
*
* @param newName
* the new pack name
* @return the new IrisPack
*/
public IrisPack install(String newName) throws IrisException {
File newPack = packsPack(newName);
if(newPack.exists()) {
throw new IrisException("Cannot install new pack because the folder " + newName + " already exists!");
}
try {
FileUtils.copyDirectory(getFolder(), newPack);
} catch(IOException e) {
Iris.reportError(e);
}
IrisData data = IrisData.get(newPack);
IrisDimension dim = data.getDimensionLoader().load(getDimensionKey());
data.dump();
File from = dim.getLoadFile();
File to = new File(from.getParentFile(), newName + ".json");
try {
FileUtils.moveFile(from, to);
new File(newPack, getWorkspaceFile().getName()).delete();
} catch(Throwable e) {
throw new IrisException(e);
}
IrisPack pack = new IrisPack(newPack);
pack.updateWorkspace();
return pack;
}
/**
* The dimension's assumed loadkey
*
* @return getName()
*/
public String getDimensionKey() {
return getName();
}
/**
* Get the main dimension object
*
* @return the dimension (folder name as dim key)
*/
public IrisDimension getDimension() {
return getData().getDimensionLoader().load(getDimensionKey());
}
/**
* Find all files in this pack with the given extension
*
* @param fileExtension
* the extension
* @return the list of files
*/
public KList<File> collectFiles(String fileExtension) {
return collectFiles(getFolder(), fileExtension);
}
private JSONObject generateWorkspaceConfig() {
JSONObject ws = new JSONObject();
JSONArray folders = new JSONArray();
JSONObject folder = new JSONObject();
folder.put("path", ".");
folders.put(folder);
ws.put("folders", folders);
JSONObject settings = new JSONObject();
settings.put("workbench.colorTheme", "Monokai");
settings.put("workbench.preferredDarkColorTheme", "Solarized Dark");
settings.put("workbench.tips.enabled", false);
settings.put("workbench.tree.indent", 24);
settings.put("files.autoSave", "onFocusChange");
JSONObject jc = new JSONObject();
jc.put("editor.autoIndent", "brackets");
jc.put("editor.acceptSuggestionOnEnter", "smart");
jc.put("editor.cursorSmoothCaretAnimation", true);
jc.put("editor.dragAndDrop", false);
jc.put("files.trimTrailingWhitespace", true);
jc.put("diffEditor.ignoreTrimWhitespace", true);
jc.put("files.trimFinalNewlines", true);
jc.put("editor.suggest.showKeywords", false);
jc.put("editor.suggest.showSnippets", false);
jc.put("editor.suggest.showWords", false);
JSONObject st = new JSONObject();
st.put("strings", true);
jc.put("editor.quickSuggestions", st);
jc.put("editor.suggest.insertMode", "replace");
settings.put("[json]", jc);
settings.put("json.maxItemsComputed", 30000);
JSONArray schemas = new JSONArray();
IrisData dm = IrisData.get(getFolder());
for(ResourceLoader<?> r : dm.getLoaders().v()) {
if(r.supportsSchemas()) {
schemas.put(r.buildSchema());
}
}
settings.put("json.schemas", schemas);
ws.put("settings", settings);
return ws;
}
}

View File

@ -1,132 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pack;
import com.volmit.iris.Iris;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.jobs.DownloadJob;
import com.volmit.iris.util.scheduling.jobs.JobCollection;
import com.volmit.iris.util.scheduling.jobs.SingleJob;
import lombok.Builder;
import lombok.Data;
import org.zeroturnaround.zip.ZipUtil;
import org.zeroturnaround.zip.commons.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.UUID;
@Data
@Builder
public class IrisPackRepository {
@Builder.Default
private String user = "IrisDimensions";
@Builder.Default
private String repo = "overworld";
@Builder.Default
private String branch = "master";
@Builder.Default
private String tag = "";
/**
*
*/
public static IrisPackRepository from(String g) {
// https://github.com/IrisDimensions/overworld
if(g.startsWith("https://github.com/")) {
String sub = g.split("\\Qgithub.com/\\E")[1];
IrisPackRepository r = IrisPackRepository.builder()
.user(sub.split("\\Q/\\E")[0])
.repo(sub.split("\\Q/\\E")[1]).build();
if(g.contains("/tree/")) {
r.setBranch(g.split("/tree/")[1]);
}
return r;
} else if(g.contains("/")) {
String[] f = g.split("\\Q/\\E");
if(f.length == 1) {
return from(g);
} else if(f.length == 2) {
return IrisPackRepository.builder()
.user(f[0])
.repo(f[1])
.build();
} else if(f.length >= 3) {
IrisPackRepository r = IrisPackRepository.builder()
.user(f[0])
.repo(f[1])
.build();
if(f[2].startsWith("#")) {
r.setTag(f[2].substring(1));
} else {
r.setBranch(f[2]);
}
return r;
}
} else {
return IrisPackRepository.builder()
.user("IrisDimensions")
.repo(g)
.branch(g.equals("overworld") ? "stable" : "master")
.build();
}
return null;
}
public String toURL() {
if(!tag.trim().isEmpty()) {
return "https://codeload.github.com/" + user + "/" + repo + "/zip/refs/tags/" + tag;
}
return "https://codeload.github.com/" + user + "/" + repo + "/zip/refs/heads/" + branch;
}
public void install(VolmitSender sender, Runnable whenComplete) throws MalformedURLException {
File pack = Iris.instance.getDataFolderNoCreate(StudioSVC.WORKSPACE_NAME, getRepo());
if(!pack.exists()) {
File dl = new File(Iris.getTemp(), "dltk-" + UUID.randomUUID() + ".zip");
File work = new File(Iris.getTemp(), "extk-" + UUID.randomUUID());
new JobCollection(Form.capitalize(getRepo()),
new DownloadJob(toURL(), pack),
new SingleJob("Extracting", () -> ZipUtil.unpack(dl, work)),
new SingleJob("Installing", () -> {
try {
FileUtils.copyDirectory(work.listFiles()[0], pack);
} catch(IOException e) {
e.printStackTrace();
}
})).execute(sender, whenComplete);
} else {
sender.sendMessage("Pack already exists!");
}
}
}

View File

@ -1,285 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator;
import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Looper;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
public class IrisPregenerator {
private final PregenTask task;
private final PregeneratorMethod generator;
private final PregenListener listener;
private final Looper ticker;
private final AtomicBoolean paused;
private final AtomicBoolean shutdown;
private final RollingSequence chunksPerSecond;
private final RollingSequence chunksPerMinute;
private final RollingSequence regionsPerMinute;
private final AtomicInteger generated;
private final AtomicInteger generatedLast;
private final AtomicInteger generatedLastMinute;
private final AtomicInteger totalChunks;
private final AtomicLong startTime;
private final ChronoLatch minuteLatch;
private final AtomicReference<String> currentGeneratorMethod;
private final KSet<Position2> generatedRegions;
private final KSet<Position2> retry;
private final KSet<Position2> net;
private final ChronoLatch cl;
public IrisPregenerator(PregenTask task, PregeneratorMethod generator, PregenListener listener) {
this.listener = listenify(listener);
cl = new ChronoLatch(5000);
generatedRegions = new KSet<>();
this.shutdown = new AtomicBoolean(false);
this.paused = new AtomicBoolean(false);
this.task = task;
this.generator = generator;
retry = new KSet<>();
net = new KSet<>();
currentGeneratorMethod = new AtomicReference<>("Void");
minuteLatch = new ChronoLatch(60000, false);
chunksPerSecond = new RollingSequence(10);
chunksPerMinute = new RollingSequence(10);
regionsPerMinute = new RollingSequence(10);
generated = new AtomicInteger(0);
generatedLast = new AtomicInteger(0);
generatedLastMinute = new AtomicInteger(0);
totalChunks = new AtomicInteger(0);
task.iterateRegions((_a, _b) -> totalChunks.addAndGet(1024));
startTime = new AtomicLong(M.ms());
ticker = new Looper() {
@Override
protected long loop() {
long eta = computeETA();
int secondGenerated = generated.get() - generatedLast.get();
generatedLast.set(generated.get());
chunksPerSecond.put(secondGenerated);
if(minuteLatch.flip()) {
int minuteGenerated = generated.get() - generatedLastMinute.get();
generatedLastMinute.set(generated.get());
chunksPerMinute.put(minuteGenerated);
regionsPerMinute.put((double) minuteGenerated / 1024D);
}
listener.onTick(chunksPerSecond.getAverage(), chunksPerMinute.getAverage(),
regionsPerMinute.getAverage(),
(double) generated.get() / (double) totalChunks.get(),
generated.get(), totalChunks.get(),
totalChunks.get() - generated.get(),
eta, M.ms() - startTime.get(), currentGeneratorMethod.get());
if(cl.flip()) {
Iris.info("Pregen: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (" + Form.pc((double) generated.get() / (double) totalChunks.get(), 0) + ") " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration((double) eta, 2));
}
return 1000;
}
};
}
private long computeETA() {
return (long) ((totalChunks.get() - generated.get()) *
((double) (M.ms() - startTime.get()) / (double) generated.get()));
}
public void close() {
shutdown.set(true);
}
public void start() {
init();
ticker.start();
checkRegions();
task.iterateRegions((x, z) -> visitRegion(x, z, true));
task.iterateRegions((x, z) -> visitRegion(x, z, false));
shutdown();
}
private void checkRegions() {
task.iterateRegions(this::checkRegion);
}
private void init() {
generator.init();
generator.save();
}
private void shutdown() {
listener.onSaving();
generator.close();
ticker.interrupt();
listener.onClose();
}
private void visitRegion(int x, int z, boolean regions) {
while(paused.get() && !shutdown.get()) {
J.sleep(50);
}
if(shutdown.get()) {
listener.onRegionSkipped(x, z);
return;
}
Position2 pos = new Position2(x, z);
if(generatedRegions.contains(pos)) {
return;
}
currentGeneratorMethod.set(generator.getMethod(x, z));
boolean hit = false;
if(generator.supportsRegions(x, z, listener) && regions) {
hit = true;
listener.onRegionGenerating(x, z);
generator.generateRegion(x, z, listener);
} else if(!regions) {
hit = true;
listener.onRegionGenerating(x, z);
PregenTask.iterateRegion(x, z, (xx, zz) -> generator.generateChunk(xx, zz, listener));
}
if(hit) {
listener.onRegionGenerated(x, z);
listener.onSaving();
generator.save();
generatedRegions.add(pos);
checkRegions();
}
}
private void checkRegion(int x, int z) {
if(generatedRegions.contains(new Position2(x, z))) {
return;
}
generator.supportsRegions(x, z, listener);
}
public void pause() {
paused.set(true);
}
public void resume() {
paused.set(false);
}
private PregenListener listenify(PregenListener listener) {
return new PregenListener() {
@Override
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method) {
listener.onTick(chunksPerSecond, chunksPerMinute, regionsPerMinute, percent, generated, totalChunks, chunksRemaining, eta, elapsed, method);
}
@Override
public void onChunkGenerating(int x, int z) {
listener.onChunkGenerating(x, z);
}
@Override
public void onChunkGenerated(int x, int z) {
listener.onChunkGenerated(x, z);
generated.addAndGet(1);
}
@Override
public void onRegionGenerated(int x, int z) {
listener.onRegionGenerated(x, z);
}
@Override
public void onRegionGenerating(int x, int z) {
listener.onRegionGenerating(x, z);
}
@Override
public void onChunkCleaned(int x, int z) {
listener.onChunkCleaned(x, z);
}
@Override
public void onRegionSkipped(int x, int z) {
listener.onRegionSkipped(x, z);
}
@Override
public void onNetworkStarted(int x, int z) {
net.add(new Position2(x, z));
}
@Override
public void onNetworkFailed(int x, int z) {
retry.add(new Position2(x, z));
}
@Override
public void onNetworkReclaim(int revert) {
generated.addAndGet(-revert);
}
@Override
public void onNetworkGeneratedChunk(int x, int z) {
generated.addAndGet(1);
}
@Override
public void onNetworkDownloaded(int x, int z) {
net.remove(new Position2(x, z));
}
@Override
public void onClose() {
listener.onClose();
}
@Override
public void onSaving() {
listener.onSaving();
}
@Override
public void onChunkExistsInRegionGen(int x, int z) {
listener.onChunkExistsInRegionGen(x, z);
}
};
}
public boolean paused() {
return paused.get();
}
public Mantle getMantle() {
return generator.getMantle();
}
}

View File

@ -1,51 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator;
public interface PregenListener {
void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method);
void onChunkGenerating(int x, int z);
void onChunkGenerated(int x, int z);
void onRegionGenerated(int x, int z);
void onRegionGenerating(int x, int z);
void onChunkCleaned(int x, int z);
void onRegionSkipped(int x, int z);
void onNetworkStarted(int x, int z);
void onNetworkFailed(int x, int z);
void onNetworkReclaim(int revert);
void onNetworkGeneratedChunk(int x, int z);
void onNetworkDownloaded(int x, int z);
void onClose();
void onSaving();
void onChunkExistsInRegionGen(int x, int z);
}

View File

@ -1,96 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.Spiraled;
import com.volmit.iris.util.math.Spiraler;
import lombok.Builder;
import lombok.Data;
import java.util.Comparator;
@Builder
@Data
public class PregenTask {
private static final Position2 ZERO = new Position2(0, 0);
private static final KList<Position2> ORDER_CENTER = computeChunkOrder();
private static final KMap<Position2, KList<Position2>> ORDERS = new KMap<>();
@Builder.Default
private Position2 center = new Position2(0, 0);
@Builder.Default
private int width = 1;
@Builder.Default
private int height = 1;
public static void iterateRegion(int xr, int zr, Spiraled s, Position2 pull) {
for(Position2 i : ORDERS.computeIfAbsent(pull, PregenTask::computeOrder)) {
s.on(i.getX() + (xr << 5), i.getZ() + (zr << 5));
}
}
public static void iterateRegion(int xr, int zr, Spiraled s) {
iterateRegion(xr, zr, s, new Position2(0, 0));
}
private static KList<Position2> computeOrder(Position2 pull) {
KList<Position2> p = new KList<>();
new Spiraler(33, 33, (x, z) -> {
int xx = (x + 15);
int zz = (z + 15);
if(xx < 0 || xx > 31 || zz < 0 || zz > 31) {
return;
}
p.add(new Position2(xx, zz));
}).drain();
p.sort(Comparator.comparing((i) -> i.distance(pull)));
return p;
}
private static KList<Position2> computeChunkOrder() {
Position2 center = new Position2(15, 15);
KList<Position2> p = new KList<>();
new Spiraler(33, 33, (x, z) -> {
int xx = x + 15;
int zz = z + 15;
if(xx < 0 || xx > 31 || zz < 0 || zz > 31) {
return;
}
p.add(new Position2(xx, zz));
}).drain();
p.sort(Comparator.comparing((i) -> i.distance(center)));
return p;
}
public void iterateRegions(Spiraled s) {
new Spiraler(getWidth() * 2, getHeight() * 2, s)
.setOffset(center.getX(), center.getZ()).drain();
}
public void iterateAllChunks(Spiraled s) {
new Spiraler(getWidth() * 2, getHeight() * 2, (x, z) -> iterateRegion(x, z, s))
.setOffset(center.getX(), center.getZ()).drain();
}
}

View File

@ -1,89 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator;
import com.volmit.iris.util.mantle.Mantle;
/**
* Represents something that is capable of generating in chunks or regions, or both
*/
public interface PregeneratorMethod {
/**
* This is called before any generate methods are called. Setup your generator here
*/
void init();
/**
* This is called after the pregenerator is done. Save your work and stop threads
*/
void close();
/**
* This is called every X amount of chunks or regions. Save work,
* but no need to save all of it. At the end, close() will still be called.
*/
void save();
/**
* Return true if regions can be generated
*
* @param x
* the x region
* @param z
* the z region
* @return true if they can be
*/
boolean supportsRegions(int x, int z, PregenListener listener);
/**
* Return the name of the method being used
*
* @param x
* the x region
* @param z
* the z region
* @return the name
*/
String getMethod(int x, int z);
/**
* Called to generate a region. Execute sync, if multicore internally, wait
* for the task to complete
*
* @param x
* the x
* @param z
* the z
* @param listener
* signal chunks generating & generated. Parallel capable.
*/
void generateRegion(int x, int z, PregenListener listener);
/**
* Called to generate a chunk. You can go async so long as save will wait on the threads to finish
*
* @param x
* the x
* @param z
* the z
*/
void generateChunk(int x, int z, PregenListener listener);
Mantle getMantle();
}

View File

@ -1,73 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.util.mantle.Mantle;
import io.papermc.lib.PaperLib;
import org.bukkit.World;
public class AsyncOrMedievalPregenMethod implements PregeneratorMethod {
private final PregeneratorMethod method;
public AsyncOrMedievalPregenMethod(World world, int threads) {
method = PaperLib.isPaper() ? new AsyncPregenMethod(world, threads) : new MedievalPregenMethod(world);
}
@Override
public void init() {
method.init();
}
@Override
public void close() {
method.close();
}
@Override
public void save() {
method.save();
}
@Override
public String getMethod(int x, int z) {
return method.getMethod(x, z);
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
method.generateChunk(x, z, listener);
}
@Override
public Mantle getMantle() {
return method.getMantle();
}
}

View File

@ -1,142 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.J;
import io.papermc.lib.PaperLib;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.util.concurrent.Future;
public class AsyncPregenMethod implements PregeneratorMethod {
private final World world;
private final MultiBurst burst;
private final KList<Future<?>> future;
public AsyncPregenMethod(World world, int threads) {
if(!PaperLib.isPaper()) {
throw new UnsupportedOperationException("Cannot use PaperAsync on non paper!");
}
this.world = world;
burst = MultiBurst.burst;
future = new KList<>(1024);
}
private void unloadAndSaveAllChunks() {
try {
J.sfut(() -> {
if(world == null) {
Iris.warn("World was null somehow...");
return;
}
for(Chunk i : world.getLoadedChunks()) {
i.unload(true);
}
world.save();
}).get();
} catch(Throwable e) {
e.printStackTrace();
}
}
private void completeChunk(int x, int z, PregenListener listener) {
try {
PaperLib.getChunkAtAsync(world, x, z, true).get();
listener.onChunkGenerated(x, z);
listener.onChunkCleaned(x, z);
} catch(Throwable e) {
e.printStackTrace();
J.sleep(5);
future.add(burst.complete(() -> completeChunk(x, z, listener)));
}
}
private void waitForChunks() {
for(Future<?> i : future.copy()) {
try {
i.get();
future.remove(i);
} catch(Throwable e) {
e.printStackTrace();
}
}
}
@Override
public void init() {
unloadAndSaveAllChunks();
}
@Override
public String getMethod(int x, int z) {
return "Async";
}
@Override
public void close() {
waitForChunks();
unloadAndSaveAllChunks();
}
@Override
public void save() {
waitForChunks();
unloadAndSaveAllChunks();
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
if(future.size() > IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())) { // TODO: FIX
waitForChunks();
}
listener.onChunkGenerating(x, z);
future.add(burst.complete(() -> completeChunk(x, z, listener)));
}
@Override
public Mantle getMantle() {
if(IrisToolbelt.isIrisWorld(world)) {
return IrisToolbelt.access(world).getEngine().getMantle().getMantle();
}
return null;
}
}

View File

@ -1,65 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.util.mantle.Mantle;
public class DummyPregenMethod implements PregeneratorMethod {
@Override
public void init() {
}
@Override
public void close() {
}
@Override
public String getMethod(int x, int z) {
return "Dummy";
}
@Override
public void save() {
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
}
@Override
public Mantle getMantle() {
return null;
}
}

View File

@ -1,80 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.math.Position2;
import org.bukkit.World;
import java.io.File;
public class HybridPregenMethod implements PregeneratorMethod {
private final PregeneratorMethod inWorld;
private final World world;
public HybridPregenMethod(World world, int threads) {
this.world = world;
inWorld = new AsyncOrMedievalPregenMethod(world, threads);
}
@Override
public String getMethod(int x, int z) {
return "Hybrid<" + inWorld.getMethod(x, z) + ">";
}
@Override
public void init() {
inWorld.init();
}
@Override
public void close() {
inWorld.close();
}
@Override
public void save() {
inWorld.save();
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return inWorld.supportsRegions(x, z, listener);
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
inWorld.generateRegion(x, z, listener);
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
inWorld.generateChunk(x, z, listener);
}
@Override
public Mantle getMantle() {
return inWorld.getMantle();
}
}

View File

@ -1,120 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.util.concurrent.CompletableFuture;
public class MedievalPregenMethod implements PregeneratorMethod {
private final World world;
private final KList<CompletableFuture<?>> futures;
public MedievalPregenMethod(World world) {
this.world = world;
futures = new KList<>();
}
private void waitForChunks() {
for(CompletableFuture<?> i : futures) {
try {
i.get();
} catch(Throwable e) {
e.printStackTrace();
}
}
futures.clear();
}
private void unloadAndSaveAllChunks() {
waitForChunks();
try {
J.sfut(() -> {
for(Chunk i : world.getLoadedChunks()) {
i.unload(true);
}
world.save();
}).get();
} catch(Throwable e) {
e.printStackTrace();
}
}
@Override
public void init() {
unloadAndSaveAllChunks();
}
@Override
public void close() {
unloadAndSaveAllChunks();
}
@Override
public void save() {
unloadAndSaveAllChunks();
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {
throw new UnsupportedOperationException();
}
@Override
public String getMethod(int x, int z) {
return "Medieval";
}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
if(futures.size() > IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())) {
waitForChunks();
}
listener.onChunkGenerating(x, z);
futures.add(J.sfut(() -> {
world.getChunkAt(x, z);
listener.onChunkGenerated(x, z);
listener.onChunkCleaned(x, z);
}));
}
@Override
public Mantle getMantle() {
if(IrisToolbelt.isIrisWorld(world)) {
return IrisToolbelt.access(world).getEngine().getMantle().getMantle();
}
return null;
}
}

View File

@ -1,666 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.project;
import com.google.gson.Gson;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBlockData;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisEntity;
import com.volmit.iris.engine.object.IrisGenerator;
import com.volmit.iris.engine.object.IrisLootTable;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisObjectPlacement;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.engine.object.IrisSpawner;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.exceptions.IrisException;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.O;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.scheduling.jobs.Job;
import com.volmit.iris.util.scheduling.jobs.JobCollection;
import com.volmit.iris.util.scheduling.jobs.ParallelQueueJob;
import lombok.Data;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.World;
import org.zeroturnaround.zip.ZipUtil;
import java.awt.Desktop;
import java.awt.GraphicsEnvironment;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Consumer;
@SuppressWarnings("ALL")
@Data
public class IrisProject {
private File path;
private String name;
private PlatformChunkGenerator activeProvider;
public IrisProject(File path) {
this.path = path;
this.name = path.getName();
}
public static int clean(VolmitSender s, File clean) {
int c = 0;
if(clean.isDirectory()) {
for(File i : clean.listFiles()) {
c += clean(s, i);
}
} else if(clean.getName().endsWith(".json")) {
try {
clean(clean);
} catch(Throwable e) {
Iris.reportError(e);
Iris.error("Failed to beautify " + clean.getAbsolutePath() + " You may have errors in your json!");
}
c++;
}
return c;
}
public static void clean(File clean) throws IOException {
JSONObject obj = new JSONObject(IO.readAll(clean));
fixBlocks(obj, clean);
IO.writeAll(clean, obj.toString(4));
}
public static void fixBlocks(JSONObject obj, File f) {
for(String i : obj.keySet()) {
Object o = obj.get(i);
if(i.equals("block") && o instanceof String && !o.toString().trim().isEmpty() && !o.toString().contains(":")) {
obj.put(i, "minecraft:" + o);
Iris.debug("Updated Block Key: " + o + " to " + obj.getString(i) + " in " + f.getPath());
}
if(o instanceof JSONObject) {
fixBlocks((JSONObject) o, f);
} else if(o instanceof JSONArray) {
fixBlocks((JSONArray) o, f);
}
}
}
public static void fixBlocks(JSONArray obj, File f) {
for(int i = 0; i < obj.length(); i++) {
Object o = obj.get(i);
if(o instanceof JSONObject) {
fixBlocks((JSONObject) o, f);
} else if(o instanceof JSONArray) {
fixBlocks((JSONArray) o, f);
}
}
}
public boolean isOpen() {
return activeProvider != null;
}
public KList<File> collectFiles(File f, String fileExtension) {
KList<File> l = new KList<>();
if(f.isDirectory()) {
for(File i : f.listFiles()) {
l.addAll(collectFiles(i, fileExtension));
}
} else if(f.getName().endsWith("." + fileExtension)) {
l.add(f);
}
return l;
}
public KList<File> collectFiles(String json) {
return collectFiles(path, json);
}
public void open(VolmitSender sender) throws IrisException {
open(sender, 1337, (w) ->
{
});
}
public void openVSCode(VolmitSender sender) {
IrisDimension d = IrisData.loadAnyDimension(getName());
J.attemptAsync(() ->
{
try {
if(d.getLoader() == null) {
sender.sendMessage("Could not get dimension loader");
return;
}
File f = d.getLoader().getDataFolder();
if(!doOpenVSCode(f)) {
File ff = new File(d.getLoader().getDataFolder(), d.getLoadKey() + ".code-workspace");
Iris.warn("Project missing code-workspace: " + ff.getAbsolutePath() + " Re-creating code workspace.");
try {
IO.writeAll(ff, createCodeWorkspaceConfig());
} catch(IOException e1) {
Iris.reportError(e1);
e1.printStackTrace();
}
updateWorkspace();
if(!doOpenVSCode(f)) {
Iris.warn("Tried creating code workspace but failed a second time. Your project is likely corrupt.");
}
}
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
});
}
private boolean doOpenVSCode(File f) throws IOException {
boolean foundWork = false;
for(File i : Objects.requireNonNull(f.listFiles())) {
if(i.getName().endsWith(".code-workspace")) {
foundWork = true;
J.a(() ->
{
updateWorkspace();
});
if(IrisSettings.get().getStudio().isOpenVSCode()) {
if(!GraphicsEnvironment.isHeadless()) {
Iris.msg("Opening VSCode. You may see the output from VSCode.");
Iris.msg("VSCode output always starts with: '(node:#####) electron'");
Desktop.getDesktop().open(i);
}
}
break;
}
}
return foundWork;
}
public void open(VolmitSender sender, long seed, Consumer<World> onDone) throws IrisException {
if(isOpen()) {
close();
}
boolean hasError = false;
if(hasError) {
return;
}
IrisDimension d = IrisData.loadAnyDimension(getName());
if(d == null) {
sender.sendMessage("Can't find dimension: " + getName());
return;
} else if(sender.isPlayer()) {
sender.player().setGameMode(GameMode.SPECTATOR);
}
openVSCode(sender);
J.a(() -> {
try {
activeProvider = (PlatformChunkGenerator) IrisToolbelt.createWorld()
.seed(seed)
.sender(sender)
.studio(true)
.name("iris/" + UUID.randomUUID())
.dimension(d.getLoadKey())
.create().getGenerator();
onDone.accept(activeProvider.getTarget().getWorld().realWorld());
} catch(IrisException e) {
e.printStackTrace();
}
});
}
public void close() {
Iris.debug("Closing Active Provider");
IrisToolbelt.evacuate(activeProvider.getTarget().getWorld().realWorld());
activeProvider.close();
File folder = activeProvider.getTarget().getWorld().worldFolder();
Iris.linkMultiverseCore.removeFromConfig(activeProvider.getTarget().getWorld().name());
Bukkit.unloadWorld(activeProvider.getTarget().getWorld().name(), false);
J.attemptAsync(() -> IO.delete(folder));
Iris.debug("Closed Active Provider " + activeProvider.getTarget().getWorld().name());
activeProvider = null;
}
public File getCodeWorkspaceFile() {
return new File(path, getName() + ".code-workspace");
}
public boolean updateWorkspace() {
getPath().mkdirs();
File ws = getCodeWorkspaceFile();
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
JSONObject j = createCodeWorkspaceConfig();
IO.writeAll(ws, j.toString(4));
p.end();
return true;
} catch(Throwable e) {
Iris.reportError(e);
Iris.warn("Project invalid: " + ws.getAbsolutePath() + " Re-creating. You may loose some vs-code workspace settings! But not your actual project!");
ws.delete();
try {
IO.writeAll(ws, createCodeWorkspaceConfig());
} catch(IOException e1) {
Iris.reportError(e1);
e1.printStackTrace();
}
}
return false;
}
public JSONObject createCodeWorkspaceConfig() {
JSONObject ws = new JSONObject();
JSONArray folders = new JSONArray();
JSONObject folder = new JSONObject();
folder.put("path", ".");
folders.put(folder);
ws.put("folders", folders);
JSONObject settings = new JSONObject();
settings.put("workbench.colorTheme", "Monokai");
settings.put("workbench.preferredDarkColorTheme", "Solarized Dark");
settings.put("workbench.tips.enabled", false);
settings.put("workbench.tree.indent", 24);
settings.put("files.autoSave", "onFocusChange");
JSONObject jc = new JSONObject();
jc.put("editor.autoIndent", "brackets");
jc.put("editor.acceptSuggestionOnEnter", "smart");
jc.put("editor.cursorSmoothCaretAnimation", true);
jc.put("editor.dragAndDrop", false);
jc.put("files.trimTrailingWhitespace", true);
jc.put("diffEditor.ignoreTrimWhitespace", true);
jc.put("files.trimFinalNewlines", true);
jc.put("editor.suggest.showKeywords", false);
jc.put("editor.suggest.showSnippets", false);
jc.put("editor.suggest.showWords", false);
JSONObject st = new JSONObject();
st.put("strings", true);
jc.put("editor.quickSuggestions", st);
jc.put("editor.suggest.insertMode", "replace");
settings.put("[json]", jc);
settings.put("json.maxItemsComputed", 30000);
JSONArray schemas = new JSONArray();
IrisData dm = IrisData.get(getPath());
for(ResourceLoader<?> r : dm.getLoaders().v()) {
if(r.supportsSchemas()) {
schemas.put(r.buildSchema());
}
}
for(Class<?> i : Iris.getClasses("com.volmit.iris.engine.object.", Snippet.class)) {
try {
String snipType = i.getDeclaredAnnotation(Snippet.class).value();
JSONObject o = new JSONObject();
KList<String> fm = new KList<>();
for(int g = 1; g < 8; g++) {
fm.add("/snippet/" + snipType + Form.repeat("/*", g) + ".json");
}
o.put("fileMatch", new JSONArray(fm.toArray()));
o.put("url", "./.iris/schema/snippet/" + snipType + "-schema.json");
schemas.put(o);
File a = new File(dm.getDataFolder(), ".iris/schema/snippet/" + snipType + "-schema.json");
J.attemptAsync(() -> {
try {
IO.writeAll(a, new SchemaBuilder(i, dm).construct().toString(4));
} catch(Throwable e) {
e.printStackTrace();
}
});
} catch(Throwable e) {
e.printStackTrace();
}
}
settings.put("json.schemas", schemas);
ws.put("settings", settings);
return ws;
}
public File compilePackage(VolmitSender sender, boolean obfuscate, boolean minify) {
String dimm = getName();
IrisData dm = IrisData.get(path);
IrisDimension dimension = dm.getDimensionLoader().load(dimm);
File folder = new File(Iris.instance.getDataFolder(), "exports/" + dimension.getLoadKey());
folder.mkdirs();
Iris.info("Packaging Dimension " + dimension.getName() + " " + (obfuscate ? "(Obfuscated)" : ""));
KSet<IrisRegion> regions = new KSet<>();
KSet<IrisBiome> biomes = new KSet<>();
KSet<IrisEntity> entities = new KSet<>();
KSet<IrisSpawner> spawners = new KSet<>();
KSet<IrisGenerator> generators = new KSet<>();
KSet<IrisLootTable> loot = new KSet<>();
KSet<IrisBlockData> blocks = new KSet<>();
for(String i : dm.getDimensionLoader().getPossibleKeys()) {
blocks.add(dm.getBlockLoader().load(i));
}
dimension.getRegions().forEach((i) -> regions.add(dm.getRegionLoader().load(i)));
dimension.getLoot().getTables().forEach((i) -> loot.add(dm.getLootLoader().load(i)));
regions.forEach((i) -> biomes.addAll(i.getAllBiomes(null)));
regions.forEach((r) -> r.getLoot().getTables().forEach((i) -> loot.add(dm.getLootLoader().load(i))));
regions.forEach((r) -> r.getEntitySpawners().forEach((sp) -> spawners.add(dm.getSpawnerLoader().load(sp))));
dimension.getEntitySpawners().forEach((sp) -> spawners.add(dm.getSpawnerLoader().load(sp)));
biomes.forEach((i) -> i.getGenerators().forEach((j) -> generators.add(j.getCachedGenerator(null))));
biomes.forEach((r) -> r.getLoot().getTables().forEach((i) -> loot.add(dm.getLootLoader().load(i))));
biomes.forEach((r) -> r.getEntitySpawners().forEach((sp) -> spawners.add(dm.getSpawnerLoader().load(sp))));
spawners.forEach((i) -> i.getSpawns().forEach((j) -> entities.add(dm.getEntityLoader().load(j.getEntity()))));
KMap<String, String> renameObjects = new KMap<>();
String a;
StringBuilder b = new StringBuilder();
StringBuilder c = new StringBuilder();
sender.sendMessage("Serializing Objects");
for(IrisBiome i : biomes) {
for(IrisObjectPlacement j : i.getObjects()) {
b.append(j.hashCode());
KList<String> newNames = new KList<>();
for(String k : j.getPlace()) {
if(renameObjects.containsKey(k)) {
newNames.add(renameObjects.get(k));
continue;
}
String name = !obfuscate ? k : UUID.randomUUID().toString().replaceAll("-", "");
b.append(name);
newNames.add(name);
renameObjects.put(k, name);
}
j.setPlace(newNames);
}
}
KMap<String, KList<String>> lookupObjects = renameObjects.flip();
StringBuilder gb = new StringBuilder();
ChronoLatch cl = new ChronoLatch(1000);
O<Integer> ggg = new O<>();
ggg.set(0);
biomes.forEach((i) -> i.getObjects().forEach((j) -> j.getPlace().forEach((k) ->
{
try {
File f = dm.getObjectLoader().findFile(lookupObjects.get(k).get(0));
IO.copyFile(f, new File(folder, "objects/" + k + ".iob"));
gb.append(IO.hash(f));
ggg.set(ggg.get() + 1);
if(cl.flip()) {
int g = ggg.get();
ggg.set(0);
sender.sendMessage("Wrote another " + g + " Objects");
}
} catch(Throwable e) {
Iris.reportError(e);
}
})));
b.append(IO.hash(gb.toString()));
c.append(IO.hash(b.toString()));
b = new StringBuilder();
Iris.info("Writing Dimensional Scaffold");
try {
a = new JSONObject(new Gson().toJson(dimension)).toString(minify ? 0 : 4);
IO.writeAll(new File(folder, "dimensions/" + dimension.getLoadKey() + ".json"), a);
b.append(IO.hash(a));
for(IrisGenerator i : generators) {
a = new JSONObject(new Gson().toJson(i)).toString(minify ? 0 : 4);
IO.writeAll(new File(folder, "generators/" + i.getLoadKey() + ".json"), a);
b.append(IO.hash(a));
}
c.append(IO.hash(b.toString()));
b = new StringBuilder();
for(IrisRegion i : regions) {
a = new JSONObject(new Gson().toJson(i)).toString(minify ? 0 : 4);
IO.writeAll(new File(folder, "regions/" + i.getLoadKey() + ".json"), a);
b.append(IO.hash(a));
}
for(IrisBlockData i : blocks) {
a = new JSONObject(new Gson().toJson(i)).toString(minify ? 0 : 4);
IO.writeAll(new File(folder, "blocks/" + i.getLoadKey() + ".json"), a);
b.append(IO.hash(a));
}
for(IrisBiome i : biomes) {
a = new JSONObject(new Gson().toJson(i)).toString(minify ? 0 : 4);
IO.writeAll(new File(folder, "biomes/" + i.getLoadKey() + ".json"), a);
b.append(IO.hash(a));
}
for(IrisEntity i : entities) {
a = new JSONObject(new Gson().toJson(i)).toString(minify ? 0 : 4);
IO.writeAll(new File(folder, "entities/" + i.getLoadKey() + ".json"), a);
b.append(IO.hash(a));
}
for(IrisLootTable i : loot) {
a = new JSONObject(new Gson().toJson(i)).toString(minify ? 0 : 4);
IO.writeAll(new File(folder, "loot/" + i.getLoadKey() + ".json"), a);
b.append(IO.hash(a));
}
c.append(IO.hash(b.toString()));
String finalHash = IO.hash(c.toString());
JSONObject meta = new JSONObject();
meta.put("hash", finalHash);
meta.put("time", M.ms());
meta.put("version", dimension.getVersion());
IO.writeAll(new File(folder, "package.json"), meta.toString(minify ? 0 : 4));
File p = new File(Iris.instance.getDataFolder(), "exports/" + dimension.getLoadKey() + ".iris");
Iris.info("Compressing Package");
ZipUtil.pack(folder, p, 9);
IO.delete(folder);
sender.sendMessage("Package Compiled!");
return p;
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
sender.sendMessage("Failed!");
return null;
}
public void compile(VolmitSender sender) {
IrisData data = IrisData.get(getPath());
KList<Job> jobs = new KList<>();
KList<File> files = new KList<>();
KList<File> objects = new KList<>();
files(getPath(), files);
filesObjects(getPath(), objects);
jobs.add(new ParallelQueueJob<File>() {
@Override
public void execute(File f) {
try {
IrisObject o = new IrisObject(0, 0, 0);
o.read(f);
if(o.getBlocks().isEmpty()) {
sender.sendMessageRaw("<hover:show_text:'Error:\n" +
"<yellow>" + f.getPath() +
"'><red>- IOB " + f.getName() + " has 0 blocks!");
}
if(o.getW() == 0 || o.getH() == 0 || o.getD() == 0) {
sender.sendMessageRaw("<hover:show_text:'Error:\n" +
"<yellow>" + f.getPath() + "\n<red>The width height or depth has a zero in it (bad format)" +
"'><red>- IOB " + f.getName() + " is not 3D!");
}
} catch(IOException e) {
e.printStackTrace();
}
}
@Override
public String getName() {
return "IOB";
}
}.queue(objects));
jobs.add(new ParallelQueueJob<File>() {
@Override
public void execute(File f) {
try {
JSONObject p = new JSONObject(IO.readAll(f));
fixBlocks(p);
scanForErrors(data, f, p, sender);
IO.writeAll(f, p.toString(4));
} catch(Throwable e) {
sender.sendMessageRaw("<hover:show_text:'Error:\n" +
"<yellow>" + f.getPath() +
"\n<red>" + e.getMessage() +
"'><red>- JSON Error " + f.getName());
}
}
@Override
public String getName() {
return "JSON";
}
}.queue(files));
new JobCollection("Compile", jobs).execute(sender);
}
private void scanForErrors(IrisData data, File f, JSONObject p, VolmitSender sender) {
String key = data.toLoadKey(f);
ResourceLoader<?> loader = data.getTypedLoaderFor(f);
if(loader == null) {
sender.sendMessageBasic("Can't find loader for " + f.getPath());
return;
}
IrisRegistrant load = loader.load(key);
compare(load.getClass(), p, sender, new KList<>());
load.scanForErrors(p, sender);
}
public void compare(Class<?> c, JSONObject j, VolmitSender sender, KList<String> path) {
try {
Object o = c.getClass().getConstructor().newInstance();
} catch(Throwable e) {
}
}
public void files(File clean, KList<File> files) {
if(clean.isDirectory()) {
for(File i : clean.listFiles()) {
files(i, files);
}
} else if(clean.getName().endsWith(".json")) {
try {
files.add(clean);
} catch(Throwable e) {
Iris.reportError(e);
}
}
}
public void filesObjects(File clean, KList<File> files) {
if(clean.isDirectory()) {
for(File i : clean.listFiles()) {
filesObjects(i, files);
}
} else if(clean.getName().endsWith(".iob")) {
try {
files.add(clean);
} catch(Throwable e) {
Iris.reportError(e);
}
}
}
private void fixBlocks(JSONObject obj) {
for(String i : obj.keySet()) {
Object o = obj.get(i);
if(i.equals("block") && o instanceof String && !o.toString().trim().isEmpty() && !o.toString().contains(":")) {
obj.put(i, "minecraft:" + o);
}
if(o instanceof JSONObject) {
fixBlocks((JSONObject) o);
} else if(o instanceof JSONArray) {
fixBlocks((JSONArray) o);
}
}
}
private void fixBlocks(JSONArray obj) {
for(int i = 0; i < obj.length(); i++) {
Object o = obj.get(i);
if(o instanceof JSONObject) {
fixBlocks((JSONObject) o);
} else if(o instanceof JSONArray) {
fixBlocks((JSONArray) o);
}
}
}
}

View File

@ -1,682 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.project;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.loader.ResourceLoader;
import com.volmit.iris.engine.object.annotations.ArrayType;
import com.volmit.iris.engine.object.annotations.Desc;
import com.volmit.iris.engine.object.annotations.MaxNumber;
import com.volmit.iris.engine.object.annotations.MinNumber;
import com.volmit.iris.engine.object.annotations.RegistryListBlockType;
import com.volmit.iris.engine.object.annotations.RegistryListFont;
import com.volmit.iris.engine.object.annotations.RegistryListItemType;
import com.volmit.iris.engine.object.annotations.RegistryListResource;
import com.volmit.iris.engine.object.annotations.RegistryListSpecialEntity;
import com.volmit.iris.engine.object.annotations.Required;
import com.volmit.iris.engine.object.annotations.Snippet;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.potion.PotionEffectType;
import java.awt.GraphicsEnvironment;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class SchemaBuilder {
private static final String SYMBOL_LIMIT__N = "*";
private static final String SYMBOL_TYPE__N = "";
private static final JSONArray POTION_TYPES = getPotionTypes();
private static final JSONArray ENCHANT_TYPES = getEnchantmentTypes();
private static final JSONArray ITEM_TYPES = new JSONArray(B.getItemTypes());
private static final JSONArray FONT_TYPES = new JSONArray(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames());
private final KMap<String, JSONObject> definitions;
private final Class<?> root;
private final KList<String> warnings;
private final IrisData data;
public SchemaBuilder(Class<?> root, IrisData data) {
this.data = data;
warnings = new KList<>();
this.definitions = new KMap<>();
this.root = root;
}
private static JSONArray getEnchantmentTypes() {
JSONArray a = new JSONArray();
for(Field gg : Enchantment.class.getDeclaredFields()) {
a.put(gg.getName());
}
return a;
}
private static JSONArray getPotionTypes() {
JSONArray a = new JSONArray();
for(PotionEffectType gg : PotionEffectType.values()) {
a.put(gg.getName().toUpperCase().replaceAll("\\Q \\E", "_"));
}
return a;
}
public JSONObject construct() {
JSONObject schema = new JSONObject();
schema.put("$schema", "http://json-schema.org/draft-07/schema#");
schema.put("$id", "https://volmit.com/iris-schema/" + root.getSimpleName().toLowerCase() + ".json");
JSONObject props = buildProperties(root);
for(String i : props.keySet()) {
if(!schema.has(i)) {
schema.put(i, props.get(i));
}
}
JSONObject defs = new JSONObject();
for(Map.Entry<String, JSONObject> entry : definitions.entrySet()) {
defs.put(entry.getKey(), entry.getValue());
}
schema.put("definitions", defs);
for(String i : warnings) {
Iris.warn(root.getSimpleName() + ": " + i);
}
return schema;
}
private JSONObject buildProperties(Class<?> c) {
JSONObject o = new JSONObject();
JSONObject properties = new JSONObject();
o.put("description", getDescription(c));
o.put("type", getType(c));
JSONArray required = new JSONArray();
if(c.isAssignableFrom(IrisRegistrant.class) || IrisRegistrant.class.isAssignableFrom(c)) {
for(Field k : IrisRegistrant.class.getDeclaredFields()) {
k.setAccessible(true);
if(Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
continue;
}
JSONObject property = buildProperty(k, c);
if(property.getBoolean("!required")) {
required.put(k.getName());
}
property.remove("!required");
properties.put(k.getName(), property);
}
}
for(Field k : c.getDeclaredFields()) {
k.setAccessible(true);
if(Modifier.isStatic(k.getModifiers()) || Modifier.isFinal(k.getModifiers()) || Modifier.isTransient(k.getModifiers())) {
continue;
}
JSONObject property = buildProperty(k, c);
property.remove("!required");
properties.put(k.getName(), property);
}
if(required.length() > 0) {
o.put("required", required);
}
o.put("properties", properties);
if(c.isAnnotationPresent(Snippet.class)) {
JSONObject anyOf = new JSONObject();
JSONArray arr = new JSONArray();
JSONObject str = new JSONObject();
str.put("type", "string");
arr.put(o);
arr.put(str);
anyOf.put("anyOf", arr);
return anyOf;
}
return o;
}
private JSONObject buildProperty(Field k, Class<?> cl) {
JSONObject prop = new JSONObject();
String type = getType(k.getType());
KList<String> description = new KList<>();
prop.put("!required", k.isAnnotationPresent(Required.class));
prop.put("type", type);
String fancyType = "Unknown Type";
switch(type) {
case "boolean" -> fancyType = "Boolean";
case "integer" -> {
fancyType = "Integer";
if(k.isAnnotationPresent(MinNumber.class)) {
int min = (int) k.getDeclaredAnnotation(MinNumber.class).value();
prop.put("minimum", min);
description.add(SYMBOL_LIMIT__N + " Minimum allowed is " + min);
}
if(k.isAnnotationPresent(MaxNumber.class)) {
int max = (int) k.getDeclaredAnnotation(MaxNumber.class).value();
prop.put("maximum", max);
description.add(SYMBOL_LIMIT__N + " Maximum allowed is " + max);
}
}
case "number" -> {
fancyType = "Number";
if(k.isAnnotationPresent(MinNumber.class)) {
double min = k.getDeclaredAnnotation(MinNumber.class).value();
prop.put("minimum", min);
description.add(SYMBOL_LIMIT__N + " Minimum allowed is " + min);
}
if(k.isAnnotationPresent(MaxNumber.class)) {
double max = k.getDeclaredAnnotation(MaxNumber.class).value();
prop.put("maximum", max);
description.add(SYMBOL_LIMIT__N + " Maximum allowed is " + max);
}
}
case "string" -> {
fancyType = "Text";
if(k.isAnnotationPresent(MinNumber.class)) {
int min = (int) k.getDeclaredAnnotation(MinNumber.class).value();
prop.put("minLength", min);
description.add(SYMBOL_LIMIT__N + " Minimum Length allowed is " + min);
}
if(k.isAnnotationPresent(MaxNumber.class)) {
int max = (int) k.getDeclaredAnnotation(MaxNumber.class).value();
prop.put("maxLength", max);
description.add(SYMBOL_LIMIT__N + " Maximum Length allowed is " + max);
}
if(k.isAnnotationPresent(RegistryListResource.class)) {
RegistryListResource rr = k.getDeclaredAnnotation(RegistryListResource.class);
ResourceLoader<?> loader = data.getLoaders().get(rr.value());
if(loader != null) {
String key = "erz" + loader.getFolderName();
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", new JSONArray(loader.getPossibleKeys()));
definitions.put(key, j);
}
fancyType = "Iris " + loader.getResourceTypeName();
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid " + loader.getFolderName() + " (use ctrl+space for auto complete!)");
} else {
Iris.error("Cannot find Registry Loader for type " + rr.value() + " used in " + k.getDeclaringClass().getCanonicalName() + " in field " + k.getName());
}
} else if(k.isAnnotationPresent(RegistryListBlockType.class)) {
String key = "enum-block-type";
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
JSONArray ja = new JSONArray();
for(String i : data.getBlockLoader().getPossibleKeys()) {
ja.put(i);
}
for(String i : B.getBlockTypes()) {
ja.put(i);
}
j.put("enum", ja);
definitions.put(key, j);
}
fancyType = "Block Type";
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Block Type (use ctrl+space for auto complete!)");
} else if(k.isAnnotationPresent(RegistryListItemType.class)) {
String key = "enum-item-type";
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", ITEM_TYPES);
definitions.put(key, j);
}
fancyType = "Item Type";
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Item Type (use ctrl+space for auto complete!)");
} else if(k.isAnnotationPresent(RegistryListSpecialEntity.class)) {
String key = "enum-reg-specialentity";
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
KList<String> list = new KList<>();
list.addAll(Iris.linkMythicMobs.getMythicMobTypes().stream().map(s -> "MythicMobs:" + s).collect(Collectors.toList()));
//TODO add Citizens stuff here too
j.put("enum", list.toJSONStringArray());
definitions.put(key, j);
}
fancyType = "Mythic Mob Type";
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Mythic Mob Type (use ctrl+space for auto complete!) Define mythic mobs with the mythic mobs plugin configuration files.");
} else if(k.isAnnotationPresent(RegistryListFont.class)) {
String key = "enum-font";
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", FONT_TYPES);
definitions.put(key, j);
}
fancyType = "Font Family";
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Font Family (use ctrl+space for auto complete!)");
} else if(k.getType().equals(Enchantment.class)) {
String key = "enum-enchantment";
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", ENCHANT_TYPES);
definitions.put(key, j);
}
fancyType = "Enchantment Type";
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Enchantment Type (use ctrl+space for auto complete!)");
} else if(k.getType().equals(PotionEffectType.class)) {
String key = "enum-potion-effect-type";
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", POTION_TYPES);
definitions.put(key, j);
}
fancyType = "Potion Effect Type";
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)");
} else if(k.getType().isEnum()) {
fancyType = k.getType().getSimpleName().replaceAll("\\QIris\\E", "");
JSONArray a = new JSONArray();
boolean advanced = k.getType().isAnnotationPresent(Desc.class);
for(Object gg : k.getType().getEnumConstants()) {
if(advanced) {
try {
JSONObject j = new JSONObject();
String name = ((Enum<?>) gg).name();
j.put("const", name);
Desc dd = k.getType().getField(name).getAnnotation(Desc.class);
j.put("description", dd == null ? ("No Description for " + name) : dd.value());
a.put(j);
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
} else {
a.put(((Enum<?>) gg).name());
}
}
String key = (advanced ? "oneof-" : "") + "enum-" + k.getType().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put(advanced ? "oneOf" : "enum", a);
definitions.put(key, j);
}
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid " + k.getType().getSimpleName().replaceAll("\\QIris\\E", "") + " (use ctrl+space for auto complete!)");
}
}
case "object" -> {
fancyType = k.getType().getSimpleName().replaceAll("\\QIris\\E", "") + " (Object)";
String key = "obj-" + k.getType().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
if(!definitions.containsKey(key)) {
definitions.put(key, new JSONObject());
definitions.put(key, buildProperties(k.getType()));
}
prop.put("$ref", "#/definitions/" + key);
}
case "array" -> {
fancyType = "List of Something...?";
ArrayType t = k.getDeclaredAnnotation(ArrayType.class);
if(t != null) {
if(t.min() > 0) {
prop.put("minItems", t.min());
if(t.min() == 1) {
description.add(SYMBOL_LIMIT__N + " At least one entry must be defined, or just remove this list.");
} else {
description.add(SYMBOL_LIMIT__N + " Requires at least " + t.min() + " entries.");
}
}
String arrayType = getType(t.type());
switch(arrayType) {
case "integer" -> fancyType = "List of Integers";
case "number" -> fancyType = "List of Numbers";
case "object" -> {
fancyType = "List of " + t.type().getSimpleName().replaceAll("\\QIris\\E", "") + "s (Objects)";
String key = "obj-" + t.type().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
if(!definitions.containsKey(key)) {
definitions.put(key, new JSONObject());
definitions.put(key, buildProperties(t.type()));
}
JSONObject items = new JSONObject();
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
}
case "string" -> {
fancyType = "List of Text";
if(k.isAnnotationPresent(RegistryListResource.class)) {
RegistryListResource rr = k.getDeclaredAnnotation(RegistryListResource.class);
ResourceLoader<?> loader = data.getLoaders().get(rr.value());
if(loader != null) {
fancyType = "List<" + loader.getResourceTypeName() + ">";
String key = "erz" + loader.getFolderName();
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", new JSONArray(loader.getPossibleKeys()));
definitions.put(key, j);
}
JSONObject items = new JSONObject();
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid " + loader.getResourceTypeName() + " (use ctrl+space for auto complete!)");
} else {
Iris.error("Cannot find Registry Loader for type (list schema) " + rr.value() + " used in " + k.getDeclaringClass().getCanonicalName() + " in field " + k.getName());
}
} else if(k.isAnnotationPresent(RegistryListBlockType.class)) {
fancyType = "List of Block Types";
String key = "enum-block-type";
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
JSONArray ja = new JSONArray();
for(String i : data.getBlockLoader().getPossibleKeys()) {
ja.put(i);
}
for(String i : B.getBlockTypes()) {
ja.put(i);
}
j.put("enum", ja);
definitions.put(key, j);
}
JSONObject items = new JSONObject();
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid Block Type (use ctrl+space for auto complete!)");
} else if(k.isAnnotationPresent(RegistryListItemType.class)) {
fancyType = "List of Item Types";
String key = "enum-item-type";
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", ITEM_TYPES);
definitions.put(key, j);
}
JSONObject items = new JSONObject();
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid Item Type (use ctrl+space for auto complete!)");
} else if(k.isAnnotationPresent(RegistryListFont.class)) {
String key = "enum-font";
fancyType = "List of Font Families";
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", FONT_TYPES);
definitions.put(key, j);
}
JSONObject items = new JSONObject();
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid Font Family (use ctrl+space for auto complete!)");
} else if(t.type().equals(Enchantment.class)) {
fancyType = "List of Enchantment Types";
String key = "enum-enchantment";
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", ENCHANT_TYPES);
definitions.put(key, j);
}
JSONObject items = new JSONObject();
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid Enchantment Type (use ctrl+space for auto complete!)");
} else if(t.type().equals(PotionEffectType.class)) {
fancyType = "List of Potion Effect Types";
String key = "enum-potion-effect-type";
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put("enum", POTION_TYPES);
definitions.put(key, j);
}
JSONObject items = new JSONObject();
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid Potion Effect Type (use ctrl+space for auto complete!)");
} else if(t.type().isEnum()) {
fancyType = "List of " + t.type().getSimpleName().replaceAll("\\QIris\\E", "") + "s";
JSONArray a = new JSONArray();
boolean advanced = t.type().isAnnotationPresent(Desc.class);
for(Object gg : t.type().getEnumConstants()) {
if(advanced) {
try {
JSONObject j = new JSONObject();
String name = ((Enum<?>) gg).name();
j.put("const", name);
Desc dd = t.type().getField(name).getAnnotation(Desc.class);
j.put("description", dd == null ? ("No Description for " + name) : dd.value());
a.put(j);
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
} else {
a.put(((Enum<?>) gg).name());
}
}
String key = (advanced ? "oneof-" : "") + "enum-" + t.type().getCanonicalName().replaceAll("\\Q.\\E", "-").toLowerCase();
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
j.put(advanced ? "oneOf" : "enum", a);
definitions.put(key, j);
}
JSONObject items = new JSONObject();
items.put("$ref", "#/definitions/" + key);
prop.put("items", items);
description.add(SYMBOL_TYPE__N + " Must be a valid " + t.type().getSimpleName().replaceAll("\\QIris\\E", "") + " (use ctrl+space for auto complete!)");
}
}
}
} else {
warnings.add("Undefined array type for field " + k.getName() + " (" + k.getType().getSimpleName() + ") in class " + cl.getSimpleName());
}
}
default -> warnings.add("Unexpected Schema Type: " + type + " for field " + k.getName() + " (" + k.getType().getSimpleName() + ") in class " + cl.getSimpleName());
}
KList<String> d = new KList<>();
d.add(k.getName());
d.add(getFieldDescription(k));
d.add(" ");
d.add(fancyType);
d.add(getDescription(k.getType()));
if(k.getType().isAnnotationPresent(Snippet.class)) {
String sm = k.getType().getDeclaredAnnotation(Snippet.class).value();
d.add(" ");
d.add("You can instead specify \"snippet/" + sm + "/some-name.json\" to use a snippet file instead of specifying it here.");
}
try {
k.setAccessible(true);
Object value = k.get(cl.newInstance());
if(value != null) {
if(value instanceof List) {
d.add(" ");
d.add("* Default Value is an empty list");
} else if(!cl.isPrimitive() && !(value instanceof Number) && !(value instanceof String) && !(cl.isEnum())) {
d.add(" ");
d.add("* Default Value is a default object (create this object to see default properties)");
} else {
d.add(" ");
d.add("* Default Value is " + value);
}
}
} catch(Throwable ignored) {
}
description.forEach((g) -> d.add(g.trim()));
prop.put("type", type);
prop.put("description", d.toString("\n"));
if(k.getType().isAnnotationPresent(Snippet.class)) {
JSONObject anyOf = new JSONObject();
JSONArray arr = new JSONArray();
JSONObject str = new JSONObject();
str.put("type", "string");
String key = "enum-snippet-" + k.getType().getDeclaredAnnotation(Snippet.class).value();
str.put("$ref", "#/definitions/" + key);
if(!definitions.containsKey(key)) {
JSONObject j = new JSONObject();
JSONArray snl = new JSONArray();
data.getPossibleSnippets(k.getType().getDeclaredAnnotation(Snippet.class).value()).forEach(snl::put);
j.put("enum", snl);
definitions.put(key, j);
}
arr.put(prop);
arr.put(str);
prop.put("description", d.toString("\n"));
str.put("description", d.toString("\n"));
anyOf.put("anyOf", arr);
anyOf.put("description", d.toString("\n"));
anyOf.put("!required", k.isAnnotationPresent(Required.class));
return anyOf;
}
return prop;
}
private String getType(Class<?> c) {
if(c.equals(int.class) || c.equals(Integer.class) || c.equals(long.class) || c.equals(Long.class)) {
return "integer";
}
if(c.equals(float.class) || c.equals(double.class) || c.equals(Float.class) || c.equals(Double.class)) {
return "number";
}
if(c.equals(boolean.class) || c.equals(Boolean.class)) {
return "boolean";
}
if(c.equals(String.class) || c.isEnum() || c.equals(Enchantment.class) || c.equals(PotionEffectType.class)) {
return "string";
}
if(c.equals(KList.class)) {
return "array";
}
if(c.equals(KMap.class)) {
return "object";
}
if(!c.isAnnotationPresent(Desc.class) && c.getCanonicalName().startsWith("com.volmit.iris.")) {
warnings.addIfMissing("Unsupported Type: " + c.getCanonicalName() + " Did you forget @Desc?");
}
return "object";
}
private String getFieldDescription(Field r) {
if(r.isAnnotationPresent(Desc.class)) {
return r.getDeclaredAnnotation(Desc.class).value();
}
// suppress warnings on bukkit classes
if(r.getDeclaringClass().getName().startsWith("org.bukkit.")) {
return "Bukkit package classes and enums have no descriptions";
}
warnings.addIfMissing("Missing @Desc on field " + r.getName() + " (" + r.getType() + ") in " + r.getDeclaringClass().getCanonicalName());
return "No Field Description";
}
private String getDescription(Class<?> r) {
if(r.isAnnotationPresent(Desc.class)) {
return r.getDeclaredAnnotation(Desc.class).value();
}
if(!r.isPrimitive() && !r.equals(KList.class) && !r.equals(KMap.class) && r.getCanonicalName().startsWith("com.volmit.")) {
warnings.addIfMissing("Missing @Desc on " + r.getSimpleName() + " in " + (r.getDeclaringClass() != null ? r.getDeclaringClass().getCanonicalName() : " NOSRC"));
}
return "";
}
}

View File

@ -1,39 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.report;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Report {
@Builder.Default
private final ReportType type = ReportType.NOTICE;
@Builder.Default
private final String title = "Problem...";
@Builder.Default
private final String message = "No Message";
@Builder.Default
private final String suggestion = "No Suggestion";
public String toString() {
return type + ": " + title + ": " + message + ": Suggestion: " + suggestion;
}
}

View File

@ -1,26 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.report;
public enum ReportType {
ERROR,
SEVERE_WARNING,
WARNING,
NOTICE,
}

View File

@ -1,141 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.board.BoardManager;
import com.volmit.iris.util.board.BoardProvider;
import com.volmit.iris.util.board.BoardSettings;
import com.volmit.iris.util.board.ScoreDirection;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.J;
import lombok.Data;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import java.util.List;
public class BoardSVC implements IrisService, BoardProvider {
private final KMap<Player, PlayerBoard> boards = new KMap<>();
private com.volmit.iris.util.board.BoardManager manager;
@Override
public void onEnable() {
J.ar(this::tick, 20);
manager = new BoardManager(Iris.instance, BoardSettings.builder()
.boardProvider(this)
.scoreDirection(ScoreDirection.DOWN)
.build());
}
@Override
public void onDisable() {
manager.onDisable();
boards.clear();
}
@EventHandler
public void on(PlayerChangedWorldEvent e) {
J.s(() -> updatePlayer(e.getPlayer()));
}
@EventHandler
public void on(PlayerJoinEvent e) {
J.s(() -> updatePlayer(e.getPlayer()));
}
public void updatePlayer(Player p) {
if(IrisToolbelt.isIrisStudioWorld(p.getWorld())) {
manager.remove(p);
manager.setup(p);
} else {
manager.remove(p);
boards.remove(p);
}
}
@Override
public String getTitle(Player player) {
return C.GREEN + "Iris";
}
public void tick() {
if(!Iris.service(StudioSVC.class).isProjectOpen()) {
return;
}
boards.forEach((k, v) -> v.update());
}
@Override
public List<String> getLines(Player player) {
PlayerBoard pb = boards.computeIfAbsent(player, PlayerBoard::new);
synchronized(pb.lines) {
return pb.lines;
}
}
@Data
public static class PlayerBoard {
private final Player player;
private final KList<String> lines;
public PlayerBoard(Player player) {
this.player = player;
this.lines = new KList<>();
update();
}
public void update() {
synchronized(lines) {
lines.clear();
if(!IrisToolbelt.isIrisStudioWorld(player.getWorld())) {
return;
}
Engine engine = IrisToolbelt.access(player.getWorld()).getEngine();
int x = player.getLocation().getBlockX();
int y = player.getLocation().getBlockY() - player.getWorld().getMinHeight();
int z = player.getLocation().getBlockZ();
lines.add("&7&m ");
lines.add(C.GREEN + "Speed" + C.GRAY + ": " + Form.f(engine.getGeneratedPerSecond(), 0) + "/s " + Form.duration(1000D / engine.getGeneratedPerSecond(), 0));
lines.add(C.AQUA + "Cache" + C.GRAY + ": " + Form.f(IrisData.cacheSize()));
lines.add(C.AQUA + "Mantle" + C.GRAY + ": " + engine.getMantle().getLoadedRegionCount());
lines.add("&7&m ");
lines.add(C.AQUA + "Region" + C.GRAY + ": " + engine.getRegion(x, z).getName());
lines.add(C.AQUA + "Biome" + C.GRAY + ": " + engine.getBiomeOrMantle(x, y, z).getName());
lines.add(C.AQUA + "Height" + C.GRAY + ": " + Math.round(engine.getHeight(x, z) + player.getWorld().getMinHeight()));
lines.add(C.AQUA + "Slope" + C.GRAY + ": " + Form.f(engine.getComplex().getSlopeStream().get(x, z), 2));
lines.add(C.AQUA + "BUD/s" + C.GRAY + ": " + Form.f(engine.getBlockUpdatesPerSecond()));
lines.add("&7&m ");
}
}
}
}

View File

@ -1,99 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.commands.CommandIris;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeSystem;
import com.volmit.iris.util.decree.virtual.VirtualDecreeCommand;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.server.ServerCommandEvent;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
public class CommandSVC implements IrisService, DecreeSystem {
private final KMap<String, CompletableFuture<String>> futures = new KMap<>();
private CompletableFuture<String> consoleFuture = null;
private final transient AtomicCache<VirtualDecreeCommand> commandCache = new AtomicCache<>();
@Override
public void onEnable() {
Iris.instance.getCommand("iris").setExecutor(this);
J.a(() -> getRoot().cacheAll());
}
@Override
public void onDisable() {
}
@EventHandler
public void on(PlayerCommandPreprocessEvent e) {
String msg = e.getMessage().startsWith("/") ? e.getMessage().substring(1) : e.getMessage();
if(msg.startsWith("irisdecree ")) {
String[] args = msg.split("\\Q \\E");
CompletableFuture<String> future = futures.get(args[1]);
if(future != null) {
future.complete(args[2]);
e.setCancelled(true);
return;
}
}
if((msg.startsWith("locate ") || msg.startsWith("locatebiome ")) && IrisToolbelt.isIrisWorld(e.getPlayer().getWorld())) {
new VolmitSender(e.getPlayer()).sendMessage(C.RED + "Locating biomes & objects is disabled in Iris Worlds. Use /iris studio goto <biome>");
e.setCancelled(true);
}
}
@EventHandler
public void on(ServerCommandEvent e) {
if(consoleFuture != null && !consoleFuture.isCancelled() && !consoleFuture.isDone()) {
if(!e.getCommand().contains(" ")) {
String pick = e.getCommand().trim().toLowerCase(Locale.ROOT);
consoleFuture.complete(pick);
e.setCancelled(true);
}
}
}
@Override
public VirtualDecreeCommand getRoot() {
return commandCache.aquireNastyPrint(() -> VirtualDecreeCommand.createRoot(new CommandIris()));
}
public void post(String password, CompletableFuture<String> future) {
futures.put(password, future);
}
public void postConsole(CompletableFuture<String> future) {
consoleFuture = future;
}
}

View File

@ -1,246 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.google.gson.Gson;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.object.IrisDirection;
import com.volmit.iris.engine.object.IrisJigsawPiece;
import com.volmit.iris.engine.object.IrisJigsawPieceConnector;
import com.volmit.iris.engine.object.IrisJigsawPool;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisPosition;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.function.Consumer2;
import com.volmit.iris.util.io.Converter;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.nbt.io.NBTUtil;
import com.volmit.iris.util.nbt.io.NamedTag;
import com.volmit.iris.util.nbt.mca.NBTWorld;
import com.volmit.iris.util.nbt.tag.CompoundTag;
import com.volmit.iris.util.nbt.tag.IntTag;
import com.volmit.iris.util.nbt.tag.ListTag;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Jigsaw;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
public class ConversionSVC implements IrisService {
private KList<Converter> converters;
private File folder;
@Override
public void onEnable() {
folder = Iris.instance.getDataFolder("convert");
converters = new KList<>();
J.s(() ->
J.attemptAsync(() ->
{
}), 5);
}
@Override
public void onDisable() {
}
private String toPoolName(String poolReference) {
return poolReference.split("\\Q:\\E")[1];
}
public void convertStructures(File in, File out, VolmitSender s) {
KMap<String, IrisJigsawPool> pools = new KMap<>();
KList<File> roots = new KList<>();
AtomicInteger total = new AtomicInteger(0);
AtomicInteger at = new AtomicInteger(0);
File destPools = new File(out.getAbsolutePath() + "/jigsaw-pools");
destPools.mkdirs();
findAllNBT(in, (folder, file) -> {
total.getAndIncrement();
if(roots.addIfMissing(folder)) {
String b = in.toURI().relativize(folder.toURI()).getPath();
if(b.startsWith("/")) {
b = b.substring(1);
}
if(b.endsWith("/")) {
b = b.substring(0, b.length() - 1);
}
pools.put(b, new IrisJigsawPool());
}
});
findAllNBT(in, (folder, file) -> {
at.getAndIncrement();
String b = in.toURI().relativize(folder.toURI()).getPath();
if(b.startsWith("/")) {
b = b.substring(1);
}
if(b.endsWith("/")) {
b = b.substring(0, b.length() - 1);
}
IrisJigsawPool jpool = pools.get(b);
File destObjects = new File(out.getAbsolutePath() + "/objects/" + in.toURI().relativize(folder.toURI()).getPath());
File destPieces = new File(out.getAbsolutePath() + "/jigsaw-pieces/" + in.toURI().relativize(folder.toURI()).getPath());
destObjects.mkdirs();
destPieces.mkdirs();
try {
NamedTag tag = NBTUtil.read(file);
CompoundTag compound = (CompoundTag) tag.getTag();
if(compound.containsKey("blocks") && compound.containsKey("palette") && compound.containsKey("size")) {
String id = in.toURI().relativize(folder.toURI()).getPath() + file.getName().split("\\Q.\\E")[0];
@SuppressWarnings("unchecked") ListTag<IntTag> size = (ListTag<IntTag>) compound.getListTag("size");
int w = size.get(0).asInt();
int h = size.get(1).asInt();
int d = size.get(2).asInt();
KList<BlockData> palette = new KList<>();
@SuppressWarnings("unchecked") ListTag<CompoundTag> paletteList = (ListTag<CompoundTag>) compound.getListTag("palette");
for(int i = 0; i < paletteList.size(); i++) {
CompoundTag cp = paletteList.get(i);
palette.add(NBTWorld.getBlockData(cp));
}
IrisJigsawPiece piece = new IrisJigsawPiece();
IrisObject object = new IrisObject(w, h, d);
@SuppressWarnings("unchecked") ListTag<CompoundTag> blockList = (ListTag<CompoundTag>) compound.getListTag("blocks");
for(int i = 0; i < blockList.size(); i++) {
CompoundTag cp = blockList.get(i);
@SuppressWarnings("unchecked") ListTag<IntTag> pos = (ListTag<IntTag>) cp.getListTag("pos");
int x = pos.get(0).asInt();
int y = pos.get(1).asInt();
int z = pos.get(2).asInt();
BlockData bd = palette.get(cp.getInt("state")).clone();
if(bd.getMaterial().equals(Material.JIGSAW) && cp.containsKey("nbt")) {
piece.setObject(in.toURI().relativize(folder.toURI()).getPath() + file.getName().split("\\Q.\\E")[0]);
IrisPosition spos = new IrisPosition(object.getSigned(x, y, z));
CompoundTag nbt = cp.getCompoundTag("nbt");
CompoundTag finalState = new CompoundTag();
finalState.putString("Name", nbt.getString("final_state"));
BlockData jd = bd.clone();
bd = NBTWorld.getBlockData(finalState);
String joint = nbt.getString("joint");
String pool = nbt.getString("pool");
String poolId = toPoolName(pool);
String name = nbt.getString("name");
String target = nbt.getString("target");
pools.computeIfAbsent(poolId, (k) -> new IrisJigsawPool());
IrisJigsawPieceConnector connector = new IrisJigsawPieceConnector();
connector.setName(name);
connector.setTargetName(target);
connector.setRotateConnector(false);
connector.setPosition(spos);
connector.getPools().add(poolId);
connector.setDirection(IrisDirection.getDirection(((Jigsaw) jd).getOrientation()));
if(target.equals("minecraft:building_entrance")) {
connector.setInnerConnector(true);
}
piece.getConnectors().add(connector);
}
if(!bd.getMaterial().equals(Material.STRUCTURE_VOID) && !bd.getMaterial().equals(Material.AIR)) {
object.setUnsigned(x, y, z, bd);
}
}
jpool.getPieces().addIfMissing(id);
object.write(new File(destObjects, file.getName().split("\\Q.\\E")[0] + ".iob"));
IO.writeAll(new File(destPieces, file.getName().split("\\Q.\\E")[0] + ".json"), new JSONObject(new Gson().toJson(piece)).toString(4));
Iris.info("[Jigsaw]: (" + Form.pc((double) at.get() / (double) total.get(), 0) + ") Exported Piece: " + id);
}
} catch(Throwable e) {
e.printStackTrace();
Iris.reportError(e);
}
});
for(String i : pools.k()) {
try {
IO.writeAll(new File(destPools, i + ".json"), new JSONObject(new Gson().toJson(pools.get(i))).toString(4));
} catch(IOException e) {
e.printStackTrace();
Iris.reportError(e);
}
}
Iris.info("Done! Exported " + Form.f((total.get() * 2) + pools.size()) + " Files!");
}
public void findAllNBT(File path, Consumer2<File, File> inFile) {
if(path == null) {
return;
}
if(path.isFile() && path.getName().endsWith(".nbt")) {
inFile.accept(path.getParentFile(), path);
return;
}
for(File i : path.listFiles()) {
if(i.isDirectory()) {
findAllNBT(i, inFile);
} else if(i.isFile() && i.getName().endsWith(".nbt")) {
inFile.accept(path, i);
}
}
}
public void check(VolmitSender s) {
int m = 0;
Iris.instance.getDataFolder("convert");
for(File i : folder.listFiles()) {
for(Converter j : converters) {
if(i.getName().endsWith("." + j.getInExtension())) {
File out = new File(folder, i.getName().replaceAll("\\Q." + j.getInExtension() + "\\E", "." + j.getOutExtension()));
m++;
j.convert(i, out);
s.sendMessage("Converted " + i.getName() + " -> " + out.getName());
}
}
if(i.isDirectory() && i.getName().equals("structures")) {
File f = new File(folder, "jigsaw");
if(!f.exists()) {
s.sendMessage("Converting NBT Structures into Iris Jigsaw Structures...");
f.mkdirs();
J.a(() -> convertStructures(i, f, s));
}
}
}
s.sendMessage("Converted " + m + " File" + (m == 1 ? "" : "s"));
}
}

View File

@ -1,54 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.plugin.IrisService;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerInteractEntityEvent;
public class DolphinSVC implements IrisService {
@Override
public void onEnable() {
}
@Override
public void onDisable() {
}
/**
* Prevents dolphins from being fed, to locate a treasure map.
* Note: This results in odd dolphin behaviour, but it's the best we can do.
*/
@EventHandler
public void on(PlayerInteractEntityEvent event) {
if(!IrisToolbelt.isIrisWorld(event.getPlayer().getWorld())) {
return;
}
Material hand = event.getPlayer().getInventory().getItem(event.getHand()).getType();
if(event.getRightClicked().getType().equals(EntityType.DOLPHIN) && (hand.equals(Material.TROPICAL_FISH) || hand.equals(Material.PUFFERFISH) || hand.equals(Material.COD) || hand.equals(Material.SALMON))) {
event.setCancelled(true);
}
}
}

View File

@ -1,104 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.edit.BlockEditor;
import com.volmit.iris.core.edit.BukkitBlockEditor;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.plugin.IrisService;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.event.EventHandler;
import org.bukkit.event.world.WorldUnloadEvent;
public class EditSVC implements IrisService {
private KMap<World, BlockEditor> editors;
@Override
public void onEnable() {
this.editors = new KMap<>();
Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::update, 1000, 1000);
}
@Override
public void onDisable() {
flushNow();
}
public BlockData get(World world, int x, int y, int z) {
return open(world).get(x, y, z);
}
public void set(World world, int x, int y, int z, BlockData d) {
open(world).set(x, y, z, d);
}
public void setBiome(World world, int x, int y, int z, Biome d) {
open(world).setBiome(x, y, z, d);
}
public void setBiome(World world, int x, int z, Biome d) {
open(world).setBiome(x, z, d);
}
public Biome getBiome(World world, int x, int y, int z) {
return open(world).getBiome(x, y, z);
}
public Biome getBiome(World world, int x, int z) {
return open(world).getBiome(x, z);
}
@EventHandler
public void on(WorldUnloadEvent e) {
if(editors.containsKey(e.getWorld())) {
editors.remove(e.getWorld()).close();
}
}
public void update() {
for(World i : editors.k()) {
if(M.ms() - editors.get(i).last() > 1000) {
editors.remove(i).close();
}
}
}
public void flushNow() {
for(World i : editors.k()) {
editors.remove(i).close();
}
}
public BlockEditor open(World world) {
if(editors.containsKey(world)) {
return editors.get(world);
}
BlockEditor e = new BukkitBlockEditor(world);
editors.put(world, e);
return e;
}
}

View File

@ -1,86 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.link.ExternalDataProvider;
import com.volmit.iris.core.link.ItemAdderDataProvider;
import com.volmit.iris.core.link.OraxenDataProvider;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.plugin.IrisService;
import lombok.Data;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import org.bukkit.inventory.ItemStack;
import java.util.MissingResourceException;
import java.util.Optional;
@Data
public class ExternalDataSVC implements IrisService {
private KList<ExternalDataProvider> providers = new KList<>();
@Override
public void onEnable() {
addProvider(new OraxenDataProvider(), new ItemAdderDataProvider());
}
@Override
public void onDisable() { }
public void addProvider(ExternalDataProvider... provider) {
for(ExternalDataProvider p : provider) {
if(p.getPlugin() != null) {
providers.add(p);
p.init();
}
}
}
public Optional<BlockData> getBlockData(NamespacedKey key) {
Optional<ExternalDataProvider> provider = providers.stream().filter(p -> p.isPresent() && p.isValidProvider(key)).findFirst();
if(provider.isEmpty())
return Optional.empty();
try {
return Optional.of(provider.get().getBlockData(key));
} catch(MissingResourceException e) {
Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]");
return Optional.empty();
}
}
public Optional<ItemStack> getItemStack(NamespacedKey key) {
Optional<ExternalDataProvider> provider = providers.stream().filter(p -> p.isPresent() && p.isValidProvider(key)).findFirst();
if(provider.isEmpty())
return Optional.empty();
try {
return Optional.of(provider.get().getItemStack(key));
} catch(MissingResourceException e) {
Iris.error(e.getMessage() + " - [" + e.getClassName() + ":" + e.getKey() + "]");
return Optional.empty();
}
}
public NamespacedKey[] getAllIdentifiers() {
KList<NamespacedKey> names = new KList<>();
providers.stream().filter(ExternalDataProvider::isPresent).forEach(p -> names.add(p.getBlockTypes()));
return names.toArray(new NamespacedKey[0]);
}
}

View File

@ -1,61 +0,0 @@
package com.volmit.iris.core.service;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.plugin.IrisService;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.message.Message;
public class LogFilterSVC implements IrisService, Filter {
private static final String HEIGHTMAP_MISMATCH = "Ignoring heightmap data for chunk";
private static final String RAID_PERSISTENCE = "Could not save data net.minecraft.world.entity.raid.PersistentRaid";
private static final String DUPLICATE_ENTITY_UUID = "UUID of added entity already exists";
private static final KList<String> FILTERS = new KList<>();
public void onEnable() {
FILTERS.add(HEIGHTMAP_MISMATCH, RAID_PERSISTENCE, DUPLICATE_ENTITY_UUID);
((Logger)LogManager.getRootLogger()).addFilter(this);
}
public void initialize() { }
public void start() { }
public void stop() { }
public void onDisable() { }
public boolean isStarted() { return true; }
public boolean isStopped() { return false; }
public State getState() {
try { return State.STARTED; }
catch (Exception var2) { return null; }
}
public Filter.Result getOnMatch() { return Result.NEUTRAL; }
public Filter.Result getOnMismatch() { return Result.NEUTRAL; }
public Result filter(LogEvent event) { return check(event.getMessage().getFormattedMessage()); }
public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) { return check(msg.toString()); }
public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) { return check(msg.getFormattedMessage()); }
public Result filter(Logger logger, Level level, Marker marker, String message, Object... params) { return check(message); }
public Result filter(Logger logger, Level level, Marker marker, String message, Object p0) { return check(message); }
public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1) { return check(message); }
public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2) { return check(message); }
public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3) { return check(message); }
public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4) { return check(message); }
public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5) { return check(message); }
public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6) { return check(message); }
public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7) { return check(message); }
public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8) { return check(message); }
public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8, Object p9) { return check(message); }
private Result check(String string) {
if(FILTERS.stream().anyMatch(string::contains))
return Result.DENY;
return Result.NEUTRAL;
}
}

View File

@ -1,87 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.J;
import lombok.Getter;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import java.util.Map;
public class ObjectSVC implements IrisService {
@Getter
private final Deque<Map<Block, BlockData>> undos = new ArrayDeque<>();
@Override
public void onEnable() {
}
@Override
public void onDisable() {
}
public void addChanges(Map<Block, BlockData> oldBlocks) {
undos.add(oldBlocks);
}
public void revertChanges(int amount) {
loopChange(amount);
}
private void loopChange(int amount) {
if(undos.size() > 0) {
revert(undos.pollLast());
if(amount > 1) {
J.s(() -> loopChange(amount - 1), 2);
}
}
}
/**
* Reverts all the block changes provided, 200 blocks per tick
*
* @param blocks
* The blocks to remove
*/
private void revert(Map<Block, BlockData> blocks) {
int amount = 0;
Iterator<Map.Entry<Block, BlockData>> it = blocks.entrySet().iterator();
while(it.hasNext()) {
Map.Entry<Block, BlockData> entry = it.next();
BlockData data = entry.getValue();
entry.getKey().setBlockData(data, false);
it.remove();
amount++;
if(amount > 200) {
J.s(() -> revert(blocks), 1);
}
}
}
}

View File

@ -1,136 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.framework.MeteredCache;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.KCache;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.Looper;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
public class PreservationSVC implements IrisService {
private final List<Thread> threads = new CopyOnWriteArrayList<>();
private final List<ExecutorService> services = new CopyOnWriteArrayList<>();
private Looper dereferencer;
private final List<MeteredCache> caches = new CopyOnWriteArrayList<>();
public void register(Thread t) {
threads.add(t);
}
public void register(MultiBurst burst) {
}
public void register(ExecutorService service) {
services.add(service);
}
public void printCaches() {
long s = caches.stream().filter(i -> !i.isClosed()).mapToLong(MeteredCache::getSize).sum();
long m = caches.stream().filter(i -> !i.isClosed()).mapToLong(MeteredCache::getMaxSize).sum();
double p = 0;
double mf = 0;
for(MeteredCache i : caches) {
if(i.isClosed()) {
continue;
}
mf++;
p += i.getUsage();
}
mf = mf == 0 ? 1 : mf;
Iris.info("Cached " + Form.f(s) + " / " + Form.f(m) + " (" + Form.pc(p / mf) + ") from " + caches.size() + " Caches");
}
public void dereference() {
IrisContext.dereference();
IrisData.dereference();
threads.removeIf((i) -> !i.isAlive());
services.removeIf(ExecutorService::isShutdown);
updateCaches();
}
@Override
public void onEnable() {
/*
* Dereferences copies of Engine instances that are closed to prevent memory from
* hanging around and keeping copies of complex, caches and other dead objects.
*/
dereferencer = new Looper() {
@Override
protected long loop() {
dereference();
return 60000;
}
};
}
@Override
public void onDisable() {
dereferencer.interrupt();
dereference();
postShutdown(() -> {
for(Thread i : threads) {
if(i.isAlive()) {
try {
i.interrupt();
Iris.info("Shutdown Thread " + i.getName());
} catch(Throwable e) {
Iris.reportError(e);
}
}
}
for(ExecutorService i : services) {
try {
i.shutdownNow();
Iris.info("Shutdown Executor Service " + i);
} catch(Throwable e) {
Iris.reportError(e);
}
}
});
}
public void updateCaches() {
caches.removeIf(MeteredCache::isClosed);
}
public void registerCache(MeteredCache cache) {
caches.add(cache);
}
public List<KCache<?, ?>> caches() {
return caches.stream().map(MeteredCache::getRawCache).collect(Collectors.toList());
}
}

View File

@ -1,463 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.pack.IrisPack;
import com.volmit.iris.core.project.IrisProject;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.exceptions.IrisException;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONException;
import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.zeroturnaround.zip.ZipUtil;
import org.zeroturnaround.zip.commons.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import java.util.function.Consumer;
public class StudioSVC implements IrisService {
public static final String LISTING = "https://raw.githubusercontent.com/IrisDimensions/_listing/main/listing-v2.json";
public static final String WORKSPACE_NAME = "packs";
private static final AtomicCache<Integer> counter = new AtomicCache<>();
private final KMap<String, String> cacheListing = null;
private IrisProject activeProject;
@Override
public void onEnable() {
J.a(() -> {
String pack = IrisSettings.get().getGenerator().getDefaultWorldType();
File f = IrisPack.packsPack(pack);
if(!f.exists()) {
Iris.info("Downloading Default Pack " + pack);
downloadSearch(Iris.getSender(), pack, false);
}
});
}
@Override
public void onDisable() {
Iris.debug("Studio Mode Active: Closing Projects");
for(World i : Bukkit.getWorlds()) {
if(IrisToolbelt.isIrisWorld(i)) {
if(IrisToolbelt.isStudio(i)) {
IrisToolbelt.evacuate(i);
IrisToolbelt.access(i).close();
}
}
}
}
public IrisDimension installIntoWorld(VolmitSender sender, String type, File folder) {
sender.sendMessage("Looking for Package: " + type);
File iris = new File(folder, "iris");
File irispack = new File(folder, "iris/pack");
IrisDimension dim = IrisData.loadAnyDimension(type);
if(dim == null) {
for(File i : getWorkspaceFolder().listFiles()) {
if(i.isFile() && i.getName().equals(type + ".iris")) {
sender.sendMessage("Found " + type + ".iris in " + WORKSPACE_NAME + " folder");
ZipUtil.unpack(i, irispack);
break;
}
}
} else {
sender.sendMessage("Found " + type + " dimension in " + WORKSPACE_NAME + " folder. Repackaging");
File f = new IrisProject(new File(getWorkspaceFolder(), type)).getPath();
try {
FileUtils.copyDirectory(f, irispack);
} catch(IOException e) {
Iris.reportError(e);
}
}
File dimf = new File(irispack, "dimensions/" + type + ".json");
if(!dimf.exists() || !dimf.isFile()) {
downloadSearch(sender, type, false);
File downloaded = getWorkspaceFolder(type);
for(File i : downloaded.listFiles()) {
if(i.isFile()) {
try {
FileUtils.copyFile(i, new File(irispack, i.getName()));
} catch(IOException e) {
e.printStackTrace();
Iris.reportError(e);
}
} else {
try {
FileUtils.copyDirectory(i, new File(irispack, i.getName()));
} catch(IOException e) {
e.printStackTrace();
Iris.reportError(e);
}
}
}
IO.delete(downloaded);
}
if(!dimf.exists() || !dimf.isFile()) {
sender.sendMessage("Can't find the " + dimf.getName() + " in the dimensions folder of this pack! Failed!");
return null;
}
IrisData dm = IrisData.get(irispack);
dim = dm.getDimensionLoader().load(type);
if(dim == null) {
sender.sendMessage("Can't load the dimension! Failed!");
return null;
}
sender.sendMessage(folder.getName() + " type installed. ");
return dim;
}
public void downloadSearch(VolmitSender sender, String key, boolean trim) {
downloadSearch(sender, key, trim, false);
}
public void downloadSearch(VolmitSender sender, String key, boolean trim, boolean forceOverwrite) {
String url = "?";
try {
url = getListing(false).get(key);
if(url == null) {
Iris.warn("ITS ULL for " + key);
}
url = url == null ? key : url;
Iris.info("Assuming URL " + url);
String branch = "master";
String[] nodes = url.split("\\Q/\\E");
String repo = nodes.length == 1 ? "IrisDimensions/" + nodes[0] : nodes[0] + "/" + nodes[1];
branch = nodes.length > 2 ? nodes[2] : branch;
download(sender, repo, branch, trim, forceOverwrite);
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
sender.sendMessage("Failed to download '" + key + "' from " + url + ".");
}
}
public void download(VolmitSender sender, String repo, String branch, boolean trim) throws JsonSyntaxException, IOException {
download(sender, repo, branch, trim, false);
}
public void download(VolmitSender sender, String repo, String branch, boolean trim, boolean forceOverwrite) throws JsonSyntaxException, IOException {
String url = "https://codeload.github.com/" + repo + "/zip/refs/heads/" + branch;
sender.sendMessage("Downloading " + url + " "); //The extra space stops a bug in adventure API from repeating the last letter of the URL
File zip = Iris.getNonCachedFile("pack-" + trim + "-" + repo, url);
File temp = Iris.getTemp();
File work = new File(temp, "dl-" + UUID.randomUUID());
File packs = getWorkspaceFolder();
if(zip == null || !zip.exists()) {
sender.sendMessage("Failed to find pack at " + url);
sender.sendMessage("Make sure you specified the correct repo and branch!");
sender.sendMessage("For example: /iris download IrisDimensions/overworld branch=master");
return;
}
sender.sendMessage("Unpacking " + repo);
try {
ZipUtil.unpack(zip, work);
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
sender.sendMessage(
"""
Issue when unpacking. Please check/do the following:
1. Do you have a functioning internet connection?
2. Did the download corrupt?
3. Try deleting the */plugins/iris/packs folder and re-download.
4. Download the pack from the GitHub repo: https://github.com/IrisDimensions/overworld
5. Contact support (if all other options do not help)"""
);
}
File dir = null;
File[] zipFiles = work.listFiles();
if(zipFiles == null) {
sender.sendMessage("No files were extracted from the zip file.");
return;
}
try {
dir = zipFiles.length == 1 && zipFiles[0].isDirectory() ? zipFiles[0] : null;
} catch(NullPointerException e) {
Iris.reportError(e);
sender.sendMessage("Error when finding home directory. Are there any non-text characters in the file name?");
return;
}
if(dir == null) {
sender.sendMessage("Invalid Format. Missing root folder or too many folders!");
return;
}
File dimensions = new File(dir, "dimensions");
if(!(dimensions.exists() && dimensions.isDirectory())) {
sender.sendMessage("Invalid Format. Missing dimensions folder");
return;
}
if(dimensions.listFiles() == null) {
sender.sendMessage("No dimension file found in the extracted zip file.");
sender.sendMessage("Check it is there on GitHub and report this to staff!");
} else if(dimensions.listFiles().length != 1) {
sender.sendMessage("Dimensions folder must have 1 file in it");
return;
}
File dim = dimensions.listFiles()[0];
if(!dim.isFile()) {
sender.sendMessage("Invalid dimension (folder) in dimensions folder");
return;
}
String key = dim.getName().split("\\Q.\\E")[0];
IrisDimension d = new Gson().fromJson(IO.readAll(dim), IrisDimension.class);
sender.sendMessage("Importing " + d.getName() + " (" + key + ")");
File packEntry = new File(packs, key);
if(forceOverwrite) {
IO.delete(packEntry);
}
if(IrisData.loadAnyDimension(key) != null) {
sender.sendMessage("Another dimension in the packs folder is already using the key " + key + " IMPORT FAILED!");
return;
}
if(packEntry.exists() && packEntry.listFiles().length > 0) {
sender.sendMessage("Another pack is using the key " + key + ". IMPORT FAILED!");
return;
}
FileUtils.copyDirectory(dir, packEntry);
if(trim) {
sender.sendMessage("Trimming " + key);
File cp = compilePackage(sender, key, false, false);
IO.delete(packEntry);
packEntry.mkdirs();
ZipUtil.unpack(cp, packEntry);
}
sender.sendMessage("Successfully Aquired " + d.getName());
ServerConfigurator.installDataPacks(true);
}
public KMap<String, String> getListing(boolean cached) {
JSONObject a;
if(cached) {
a = new JSONObject(Iris.getCached("cachedlisting", LISTING));
} else {
a = new JSONObject(Iris.getNonCached(true + "listing", LISTING));
}
KMap<String, String> l = new KMap<>();
for(String i : a.keySet()) {
if(a.get(i) instanceof String)
l.put(i, a.getString(i));
}
// TEMP FIX
l.put("IrisDimensions/overworld/master", "IrisDimensions/overworld/stable");
l.put("overworld", "IrisDimensions/overworld/stable");
return l;
}
public boolean isProjectOpen() {
return activeProject != null && activeProject.isOpen();
}
public void open(VolmitSender sender, String dimm) {
open(sender, 1337, dimm);
}
public void open(VolmitSender sender, long seed, String dimm) {
try {
open(sender, seed, dimm, (w) -> {
});
} catch(Exception e) {
Iris.reportError(e);
sender.sendMessage("Error when creating studio world:");
e.printStackTrace();
}
}
public void open(VolmitSender sender, long seed, String dimm, Consumer<World> onDone) throws IrisException {
if(isProjectOpen()) {
close();
}
IrisProject project = new IrisProject(new File(getWorkspaceFolder(), dimm));
activeProject = project;
project.open(sender, seed, onDone);
}
public void openVSCode(VolmitSender sender, String dim) {
new IrisProject(new File(getWorkspaceFolder(), dim)).openVSCode(sender);
}
public File getWorkspaceFolder(String... sub) {
return Iris.instance.getDataFolderList(WORKSPACE_NAME, sub);
}
public File getWorkspaceFile(String... sub) {
return Iris.instance.getDataFileList(WORKSPACE_NAME, sub);
}
public void close() {
if(isProjectOpen()) {
Iris.debug("Closing Active Project");
activeProject.close();
activeProject = null;
}
}
public File compilePackage(VolmitSender sender, String d, boolean obfuscate, boolean minify) {
return new IrisProject(new File(getWorkspaceFolder(), d)).compilePackage(sender, obfuscate, minify);
}
public void createFrom(String existingPack, String newName) {
File importPack = getWorkspaceFolder(existingPack);
File newPack = getWorkspaceFolder(newName);
if(importPack.listFiles().length == 0) {
Iris.warn("Couldn't find the pack to create a new dimension from.");
return;
}
try {
FileUtils.copyDirectory(importPack, newPack, pathname -> !pathname.getAbsolutePath().contains(".git"), false);
} catch(IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
new File(importPack, existingPack + ".code-workspace").delete();
File dimFile = new File(importPack, "dimensions/" + existingPack + ".json");
File newDimFile = new File(newPack, "dimensions/" + newName + ".json");
try {
FileUtils.copyFile(dimFile, newDimFile);
} catch(IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
new File(newPack, "dimensions/" + existingPack + ".json").delete();
try {
JSONObject json = new JSONObject(IO.readAll(newDimFile));
if(json.has("name")) {
json.put("name", Form.capitalizeWords(newName.replaceAll("\\Q-\\E", " ")));
IO.writeAll(newDimFile, json.toString(4));
}
} catch(JSONException | IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
try {
IrisProject p = new IrisProject(getWorkspaceFolder(newName));
JSONObject ws = p.createCodeWorkspaceConfig();
IO.writeAll(getWorkspaceFile(newName, newName + ".code-workspace"), ws.toString(0));
} catch(JSONException | IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
}
public void create(VolmitSender sender, String s, String downloadable) {
boolean shouldDelete = false;
File importPack = getWorkspaceFolder(downloadable);
if(importPack.listFiles().length == 0) {
downloadSearch(sender, downloadable, false);
if(importPack.listFiles().length > 0) {
shouldDelete = true;
}
}
if(importPack.listFiles().length == 0) {
sender.sendMessage("Couldn't find the pack to create a new dimension from.");
return;
}
File importDimensionFile = new File(importPack, "dimensions/" + downloadable + ".json");
if(!importDimensionFile.exists()) {
sender.sendMessage("Missing Imported Dimension File");
return;
}
sender.sendMessage("Importing " + downloadable + " into new Project " + s);
createFrom(downloadable, s);
if(shouldDelete) {
importPack.delete();
}
open(sender, s);
}
public void create(VolmitSender sender, String s) {
create(sender, s, "example");
}
public IrisProject getActiveProject() {
return activeProject;
}
public void updateWorkspace() {
if(isProjectOpen()) {
activeProject.updateWorkspace();
}
}
}

View File

@ -1,377 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IObjectPlacer;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisObjectPlacement;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.engine.object.IrisTreeModes;
import com.volmit.iris.engine.object.IrisTreeSize;
import com.volmit.iris.engine.object.TileData;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.Cuboid;
import com.volmit.iris.util.math.BlockPosition;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Bukkit;
import org.bukkit.HeightMap;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.TreeType;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Sapling;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.world.StructureGrowEvent;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
public class TreeSVC implements IrisService {
private boolean block = false;
@Override
public void onEnable() {
}
@Override
public void onDisable() {
}
/**
* This function does the following
* <br>1. Is the sapling growing in an Iris world? No -> exit</br>
* <br>2. Is the Iris world accessible? No -> exit</br>
* <br>3. Is the sapling overwriting setting on in that dimension? No -> exit</br>
* <br>4. Check biome, region and dimension for overrides for that sapling type -> Found -> use</br>
* <br>5. Exit if none are found, cancel event if one or more are.</br>
*
* @param event
* Checks the given event for sapling overrides
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void on(StructureGrowEvent event) {
if(block || event.isCancelled()) {
return;
}
Iris.debug(this.getClass().getName() + " received a structure grow event");
if(!IrisToolbelt.isIrisWorld(event.getWorld())) {
Iris.debug(this.getClass().getName() + " passed grow event off to vanilla since not an Iris world");
return;
}
PlatformChunkGenerator worldAccess = IrisToolbelt.access(event.getWorld());
if(worldAccess == null) {
Iris.debug(this.getClass().getName() + " passed it off to vanilla because could not get IrisAccess for this world");
Iris.reportError(new NullPointerException(event.getWorld().getName() + " could not be accessed despite being an Iris world"));
return;
}
Engine engine = worldAccess.getEngine();
if(engine == null) {
Iris.debug(this.getClass().getName() + " passed it off to vanilla because could not get Engine for this world");
Iris.reportError(new NullPointerException(event.getWorld().getName() + " could not be accessed despite being an Iris world"));
return;
}
IrisDimension dimension = engine.getDimension();
if(dimension == null) {
Iris.debug(this.getClass().getName() + " passed it off to vanilla because could not get Dimension for this world");
Iris.reportError(new NullPointerException(event.getWorld().getName() + " could not be accessed despite being an Iris world"));
return;
}
if(!dimension.getTreeSettings().isEnabled()) {
Iris.debug(this.getClass().getName() + " cancelled because tree overrides are disabled");
return;
}
BlockData first = event.getLocation().getBlock().getBlockData().clone();
Cuboid saplingPlane = getSaplings(event.getLocation(), blockData -> blockData instanceof Sapling && blockData.getMaterial().equals(first.getMaterial()), event.getWorld());
Iris.debug("Sapling grew @ " + event.getLocation() + " for " + event.getSpecies().name() + " usedBoneMeal is " + event.isFromBonemeal());
Iris.debug("Sapling plane is: " + saplingPlane.getSizeX() + " by " + saplingPlane.getSizeZ());
IrisObjectPlacement placement = getObjectPlacement(worldAccess, event.getLocation(), event.getSpecies(), new IrisTreeSize(1, 1));
if(placement == null) {
Iris.debug(this.getClass().getName() + " had options but did not manage to find objectPlacements for them");
return;
}
saplingPlane.forEach(block -> block.setType(Material.AIR));
IrisObject object = worldAccess.getData().getObjectLoader().load(placement.getPlace().getRandom(RNG.r));
List<BlockState> blockStateList = new KList<>();
KMap<Location, BlockData> dataCache = new KMap<>();
// TODO: REAL CLASSES!!!!
IObjectPlacer placer = new IObjectPlacer() {
@Override
public int getHighest(int x, int z, IrisData data) {
return event.getWorld().getHighestBlockYAt(x, z);
}
@Override
public int getHighest(int x, int z, IrisData data, boolean ignoreFluid) {
return event.getWorld().getHighestBlockYAt(x, z, ignoreFluid ? HeightMap.OCEAN_FLOOR : HeightMap.WORLD_SURFACE);
}
@Override
public void set(int x, int y, int z, BlockData d) {
Block b = event.getWorld().getBlockAt(x, y, z);
BlockState state = b.getState();
state.setBlockData(d);
blockStateList.add(b.getState());
dataCache.put(new Location(event.getWorld(), x, y, z), d);
}
@Override
public BlockData get(int x, int y, int z) {
return event.getWorld().getBlockAt(x, y, z).getBlockData();
}
@Override
public boolean isPreventingDecay() {
return true;
}
@Override
public boolean isCarved(int x, int y, int z) {
return false;
}
@Override
public boolean isSolid(int x, int y, int z) {
return get(x, y, z).getMaterial().isSolid();
}
@Override
public boolean isUnderwater(int x, int z) {
return false;
}
@Override
public int getFluidHeight() {
return worldAccess.getEngine().getDimension().getFluidHeight();
}
@Override
public boolean isDebugSmartBore() {
return false;
}
@Override
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) {
}
@Override
public Engine getEngine() {
return engine;
}
};
object.place(
saplingPlane.getCenter().getBlockX(),
(saplingPlane.getCenter().getBlockY() + object.getH() / 2),
saplingPlane.getCenter().getBlockZ(),
placer,
placement,
RNG.r,
Objects.requireNonNull(worldAccess).getData()
);
event.setCancelled(true);
J.s(() -> {
StructureGrowEvent iGrow = new StructureGrowEvent(event.getLocation(), event.getSpecies(), event.isFromBonemeal(), event.getPlayer(), blockStateList);
block = true;
Bukkit.getServer().getPluginManager().callEvent(iGrow);
block = false;
if(!iGrow.isCancelled()) {
for(BlockState block : iGrow.getBlocks()) {
Location l = block.getLocation();
if(dataCache.containsKey(l)) {
l.getBlock().setBlockData(dataCache.get(l), false);
}
}
}
});
}
/**
* Finds a single object placement (which may contain more than one object) for the requirements species, location &
* size
*
* @param worldAccess
* The world to access (check for biome, region, dimension, etc)
* @param location
* The location of the growth event (For biome/region finding)
* @param type
* The bukkit TreeType to match
* @param size
* The size of the sapling area
* @return An object placement which contains the matched tree, or null if none were found / it's disabled.
*/
private IrisObjectPlacement getObjectPlacement(PlatformChunkGenerator worldAccess, Location location, TreeType type, IrisTreeSize size) {
KList<IrisObjectPlacement> placements = new KList<>();
boolean isUseAll = worldAccess.getEngine().getDimension().getTreeSettings().getMode().equals(IrisTreeModes.ALL);
// Retrieve objectPlacements of type `species` from biome
IrisBiome biome = worldAccess.getEngine().getBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ());
placements.addAll(matchObjectPlacements(biome.getObjects(), size, type));
// Add more or find any in the region
if(isUseAll || placements.isEmpty()) {
IrisRegion region = worldAccess.getEngine().getRegion(location.getBlockX(), location.getBlockZ());
placements.addAll(matchObjectPlacements(region.getObjects(), size, type));
}
// Check if no matches were found, return a random one if they are
return placements.isNotEmpty() ? placements.getRandom() : null;
}
/**
* Filters out mismatches and returns matches
*
* @param objects
* The object placements to check
* @param size
* The size of the sapling area to filter with
* @param type
* The type of the tree to filter with
* @return A list of objectPlacements that matched. May be empty.
*/
private KList<IrisObjectPlacement> matchObjectPlacements(KList<IrisObjectPlacement> objects, IrisTreeSize size, TreeType type) {
KList<IrisObjectPlacement> p = new KList<>();
for(IrisObjectPlacement i : objects) {
if(i.matches(size, type)) {
p.add(i);
}
}
return p;
}
/**
* Get the Cuboid of sapling sizes at a location & blockData predicate
*
* @param at
* this location
* @param valid
* with this blockData predicate
* @param world
* the world to check in
* @return A cuboid containing only saplings
*/
public Cuboid getSaplings(Location at, Predicate<BlockData> valid, World world) {
KList<BlockPosition> blockPositions = new KList<>();
grow(at.getWorld(), new BlockPosition(at.getBlockX(), at.getBlockY(), at.getBlockZ()), valid, blockPositions);
BlockPosition a = new BlockPosition(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
BlockPosition b = new BlockPosition(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
// Maximise the block position in x and z to get max cuboid bounds
for(BlockPosition blockPosition : blockPositions) {
a.max(blockPosition);
b.min(blockPosition);
}
Iris.debug("Blocks: " + blockPositions.size());
Iris.debug("Min: " + a + " Max: " + b);
// Create a cuboid with the size calculated before
Cuboid cuboid = new Cuboid(a.toBlock(world).getLocation(), b.toBlock(world).getLocation());
boolean cuboidIsValid = true;
// Loop while the cuboid is larger than 2
while(Math.min(cuboid.getSizeX(), cuboid.getSizeZ()) > 0) {
checking:
for(int i = cuboid.getLowerX(); i < cuboid.getUpperX(); i++) {
for(int j = cuboid.getLowerY(); j < cuboid.getUpperY(); j++) {
for(int k = cuboid.getLowerZ(); k < cuboid.getUpperZ(); k++) {
if(!blockPositions.contains(new BlockPosition(i, j, k))) {
cuboidIsValid = false;
break checking;
}
}
}
}
// Return this cuboid if it's valid
if(cuboidIsValid) {
return cuboid;
}
// Inset the cuboid and try again (revalidate)
cuboid = cuboid.inset(Cuboid.CuboidDirection.Horizontal, 1);
cuboidIsValid = true;
}
return new Cuboid(at, at);
}
/**
* Grows the blockPosition list by means of checking neighbours in
*
* @param world
* the world to check in
* @param center
* the location of this position
* @param valid
* validation on blockData to check block with
* @param l
* list of block positions to add new neighbors too
*/
private void grow(World world, BlockPosition center, Predicate<BlockData> valid, KList<BlockPosition> l) {
// Make sure size is less than 50, the block to check isn't already in, and make sure the blockData still matches
if(l.size() <= 50 && !l.contains(center) && valid.test(center.toBlock(world).getBlockData())) {
l.add(center);
grow(world, center.add(1, 0, 0), valid, l);
grow(world, center.add(-1, 0, 0), valid, l);
grow(world, center.add(0, 0, 1), valid, l);
grow(world, center.add(0, 0, -1), valid, l);
}
}
}

View File

@ -1,130 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisVillagerOverride;
import com.volmit.iris.engine.object.IrisVillagerTrade;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.entity.Villager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.VillagerAcquireTradeEvent;
import org.bukkit.event.entity.VillagerCareerChangeEvent;
import java.util.List;
public class VillageSVC implements IrisService {
@Override
public void onEnable() {
}
@Override
public void onDisable() {
}
@EventHandler
public void on(VillagerCareerChangeEvent event) {
if (!IrisToolbelt.isIrisWorld(event.getEntity().getWorld())) {
return;
}
IrisDimension dim = IrisToolbelt.access(event.getEntity().getWorld())
.getEngine().getDimension();
if (!dim.isRemoveCartographersDueToCrash()) {
return;
}
if (event.getProfession().equals(Villager.Profession.CARTOGRAPHER)) {
event.setCancelled(true);
Location eventLocation = event.getEntity().getLocation();
int radius = dim.getNotifyPlayersOfCartographerCancelledRadius();
if (radius == -1) {
return;
}
List<Player> playersInWorld = event.getEntity().getWorld().getPlayers();
String message = C.GOLD + "Iris does not allow cartographers in its world due to crashes.";
Iris.info("Cancelled Cartographer Villager to prevent server crash at " + eventLocation + "!");
if (radius == -2) {
playersInWorld.stream().map(VolmitSender::new).forEach(v -> v.sendMessage(message));
} else {
playersInWorld.forEach(p -> {
if (p.getLocation().distance(eventLocation) < radius) {
new VolmitSender(p).sendMessage(message);
}
});
}
}
}
/*
* Replace or disable villager trade add event to prevent explorer map
*/
/* Removed due to MC breaking stuff again. This event is now called after the cartographer maps are made,
so it can fuck right off.
@EventHandler
public void on(VillagerAcquireTradeEvent event) {
if(!IrisToolbelt.isIrisWorld((event.getEntity().getWorld()))) {
return;
}
// Iris.info("Trade event: type " + event.getRecipe().getResult().getType() + " / meta " + event.getRecipe().getResult().getItemMeta() + " / data " + event.getRecipe().getResult().getData());
if(!event.getRecipe().getResult().getType().equals(Material.FILLED_MAP)) {
return;
}
IrisVillagerOverride override = IrisToolbelt.access(event.getEntity().getWorld()).getEngine()
.getDimension().getPatchCartographers();
if(override.isDisableTrade()) {
event.setCancelled(true);
Iris.debug("Cancelled cartographer trade @ " + event.getEntity().getLocation());
return;
}
if(override.getValidItems() == null) {
event.setCancelled(true);
Iris.debug("Cancelled cartographer trade because no override items are valid @ " + event.getEntity().getLocation());
return;
}
IrisVillagerTrade trade = override.getValidItems().getRandom();
event.setRecipe(trade.convert());
Iris.debug("Overrode cartographer trade with: " + trade + " to prevent allowing cartography map trades");
}
*/
}

View File

@ -1,475 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.service;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.edit.DustRevealer;
import com.volmit.iris.core.link.WorldEditLink;
import com.volmit.iris.core.wand.WandSelection;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.Cuboid;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.matter.Matter;
import com.volmit.iris.util.matter.WorldMatter;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.util.BlockVector;
import org.bukkit.util.Vector;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Objects;
public class WandSVC implements IrisService {
private static ItemStack dust;
public static void pasteSchematic(IrisObject s, Location at) {
s.place(at);
}
/**
* Creates an Iris Object from the 2 coordinates selected with a wand
*
* @param p
* The wand player
* @return The new object
*/
public static IrisObject createSchematic(Player p) {
if(!isHoldingWand(p)) {
return null;
}
try {
Location[] f = getCuboid(p);
Cuboid c = new Cuboid(f[0], f[1]);
IrisObject s = new IrisObject(c.getSizeX(), c.getSizeY(), c.getSizeZ());
for(Block b : c) {
if(b.getType().equals(Material.AIR)) {
continue;
}
BlockVector bv = b.getLocation().subtract(c.getLowerNE().toVector()).toVector().toBlockVector();
s.setUnsigned(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), b);
}
return s;
} catch(Throwable e) {
e.printStackTrace();
Iris.reportError(e);
}
return null;
}
/**
* Creates an Iris Object from the 2 coordinates selected with a wand
*
* @return The new object
*/
public static Matter createMatterSchem(Player p) {
if(!isHoldingWand(p)) {
return null;
}
try {
Location[] f = getCuboid(p);
return WorldMatter.createMatter(p.getName(), f[0], f[1]);
} catch(Throwable e) {
e.printStackTrace();
Iris.reportError(e);
}
return null;
}
/**
* Converts a user friendly location string to an actual Location
*
* @param s
* The string
* @return The location
*/
public static Location stringToLocation(String s) {
try {
String[] f = s.split("\\Q in \\E");
String[] g = f[0].split("\\Q,\\E");
return new Location(Bukkit.getWorld(f[1]), Integer.parseInt(g[0]), Integer.parseInt(g[1]), Integer.parseInt(g[2]));
} catch(Throwable e) {
Iris.reportError(e);
return null;
}
}
/**
* Get a user friendly string of a location
*
* @param loc
* The location
* @return The string
*/
public static String locationToString(Location loc) {
if(loc == null) {
return "<#>";
}
return loc.getBlockX() + "," + loc.getBlockY() + "," + loc.getBlockZ() + " in " + loc.getWorld().getName();
}
/**
* Create a new blank Iris wand
*
* @return The wand itemstack
*/
public static ItemStack createWand() {
return createWand(null, null);
}
/**
* Create a new dust itemstack
*
* @return The stack
*/
public static ItemStack createDust() {
ItemStack is = new ItemStack(Material.GLOWSTONE_DUST);
is.addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 1);
ItemMeta im = is.getItemMeta();
im.setDisplayName(C.BOLD + "" + C.YELLOW + "Dust of Revealing");
im.setUnbreakable(true);
im.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_PLACED_ON, ItemFlag.HIDE_POTION_EFFECTS, ItemFlag.HIDE_DESTROYS, ItemFlag.HIDE_ENCHANTS);
im.setLore(new KList<String>().qadd("Right click on a block to reveal it's placement structure!"));
is.setItemMeta(im);
return is;
}
/**
* Finds an existing wand in a users inventory
*
* @param inventory
* The inventory to search
* @return The slot number the wand is in. Or -1 if none are found
*/
public static int findWand(Inventory inventory) {
ItemStack wand = createWand(); //Create blank wand
ItemMeta meta = wand.getItemMeta();
meta.setLore(new ArrayList<>()); //We are resetting the lore as the lore differs between wands
wand.setItemMeta(meta);
for(int s = 0; s < inventory.getSize(); s++) {
ItemStack stack = inventory.getItem(s);
if(stack == null) continue;
meta = stack.getItemMeta();
meta.setLore(new ArrayList<>()); //Reset the lore on this too so we can compare them
stack.setItemMeta(meta); //We dont need to clone the item as items from .get are cloned
if(wand.isSimilar(stack)) return s; //If the name, material and NBT is the same
}
return -1;
}
/**
* Creates an Iris wand. The locations should be the currently selected locations, or null
*
* @param a
* Location A
* @param b
* Location B
* @return A new wand
*/
public static ItemStack createWand(Location a, Location b) {
ItemStack is = new ItemStack(Material.BLAZE_ROD);
is.addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 1);
ItemMeta im = is.getItemMeta();
im.setDisplayName(C.BOLD + "" + C.GOLD + "Wand of Iris");
im.setUnbreakable(true);
im.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_PLACED_ON, ItemFlag.HIDE_POTION_EFFECTS, ItemFlag.HIDE_DESTROYS, ItemFlag.HIDE_ENCHANTS);
im.setLore(new KList<String>().add(locationToString(a), locationToString(b)));
is.setItemMeta(im);
return is;
}
public static Location[] getCuboidFromItem(ItemStack is) {
ItemMeta im = is.getItemMeta();
return new Location[] {stringToLocation(im.getLore().get(0)), stringToLocation(im.getLore().get(1))};
}
public static Location[] getCuboid(Player p) {
if(isHoldingIrisWand(p))
{
return getCuboidFromItem(p.getInventory().getItemInMainHand());
}
Cuboid c = WorldEditLink.getSelection(p);
if(c != null)
{
return new Location[] {c.getLowerNE(), c.getUpperSW()};
}
return null;
}
public static boolean isHoldingWand(Player p) {
return isHoldingIrisWand(p) || WorldEditLink.getSelection(p) != null;
}
public static boolean isHoldingIrisWand(Player p) {
ItemStack is = p.getInventory().getItemInMainHand();
return is != null && isWand(is);
}
/**
* Is the itemstack passed an Iris wand
*
* @param is
* The itemstack
* @return True if it is
*/
public static boolean isWand(ItemStack is) {
ItemStack wand = createWand();
if(is.getItemMeta() == null) return false;
return is.getType().equals(wand.getType()) &&
is.getItemMeta().getDisplayName().equals(wand.getItemMeta().getDisplayName()) &&
is.getItemMeta().getEnchants().equals(wand.getItemMeta().getEnchants()) &&
is.getItemMeta().getItemFlags().equals(wand.getItemMeta().getItemFlags());
}
@Override
public void onEnable() {
ItemStack wand = createWand();
dust = createDust();
J.ar(() -> {
for(Player i : Bukkit.getOnlinePlayers()) {
tick(i);
}
}, 0);
}
@Override
public void onDisable() {
}
public void tick(Player p) {
try {
try {
if((IrisSettings.get().getWorld().worldEditWandCUI && isHoldingWand(p)) || isWand(p.getInventory().getItemInMainHand())) {
Location[] d = getCuboid(p);
new WandSelection(new Cuboid(d[0], d[1]), p).draw();
}
} catch(Throwable e) {
Iris.reportError(e);
}
} catch(Throwable e) {
e.printStackTrace();
}
}
/**
* Draw the outline of a selected region
*
* @param d
* The cuboid
* @param p
* The player to show it to
*/
public void draw(Cuboid d, Player p) {
draw(new Location[] {d.getLowerNE(), d.getUpperSW()}, p);
}
/**
* Draw the outline of a selected region
*
* @param d
* A pair of locations
* @param p
* The player to show them to
*/
public void draw(Location[] d, Player p) {
Vector gx = Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65);
d[0].getWorld().spawnParticle(Particle.CRIT_MAGIC, d[0], 1, 0.5 + gx.getX(), 0.5 + gx.getY(), 0.5 + gx.getZ(), 0, null, false);
Vector gxx = Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65);
d[1].getWorld().spawnParticle(Particle.CRIT, d[1], 1, 0.5 + gxx.getX(), 0.5 + gxx.getY(), 0.5 + gxx.getZ(), 0, null, false);
if(!d[0].getWorld().equals(d[1].getWorld())) {
return;
}
if(d[0].distanceSquared(d[1]) > 64 * 64) {
return;
}
int minx = Math.min(d[0].getBlockX(), d[1].getBlockX());
int miny = Math.min(d[0].getBlockY(), d[1].getBlockY());
int minz = Math.min(d[0].getBlockZ(), d[1].getBlockZ());
int maxx = Math.max(d[0].getBlockX(), d[1].getBlockX());
int maxy = Math.max(d[0].getBlockY(), d[1].getBlockY());
int maxz = Math.max(d[0].getBlockZ(), d[1].getBlockZ());
for(double j = minx - 1; j < maxx + 1; j += 0.25) {
for(double k = miny - 1; k < maxy + 1; k += 0.25) {
for(double l = minz - 1; l < maxz + 1; l += 0.25) {
if(M.r(0.2)) {
boolean jj = j == minx || j == maxx;
boolean kk = k == miny || k == maxy;
boolean ll = l == minz || l == maxz;
if((jj && kk) || (jj && ll) || (ll && kk)) {
Vector push = new Vector(0, 0, 0);
if(j == minx) {
push.add(new Vector(-0.55, 0, 0));
}
if(k == miny) {
push.add(new Vector(0, -0.55, 0));
}
if(l == minz) {
push.add(new Vector(0, 0, -0.55));
}
if(j == maxx) {
push.add(new Vector(0.55, 0, 0));
}
if(k == maxy) {
push.add(new Vector(0, 0.55, 0));
}
if(l == maxz) {
push.add(new Vector(0, 0, 0.55));
}
Location lv = new Location(d[0].getWorld(), j, k, l).clone().add(0.5, 0.5, 0.5).clone().add(push);
Color color = Color.getHSBColor((float) (0.5f + (Math.sin((j + k + l + (p.getTicksLived() / 2f)) / 20f) / 2)), 1, 1);
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
p.spawnParticle(Particle.REDSTONE, lv.getX(), lv.getY(), lv.getZ(), 1, 0, 0, 0, 0, new Particle.DustOptions(org.bukkit.Color.fromRGB(r, g, b), 0.75f));
}
}
}
}
}
}
@EventHandler
public void on(PlayerInteractEvent e) {
if(e.getHand() != EquipmentSlot.HAND)
return;
try {
if(isHoldingWand(e.getPlayer())) {
if(e.getAction().equals(Action.LEFT_CLICK_BLOCK)) {
e.setCancelled(true);
e.getPlayer().getInventory().setItemInMainHand(update(true, Objects.requireNonNull(e.getClickedBlock()).getLocation(), e.getPlayer().getInventory().getItemInMainHand()));
e.getPlayer().playSound(e.getClickedBlock().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1f, 0.67f);
e.getPlayer().updateInventory();
} else if(e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
e.setCancelled(true);
e.getPlayer().getInventory().setItemInMainHand(update(false, Objects.requireNonNull(e.getClickedBlock()).getLocation(), e.getPlayer().getInventory().getItemInMainHand()));
e.getPlayer().playSound(e.getClickedBlock().getLocation(), Sound.BLOCK_END_PORTAL_FRAME_FILL, 1f, 1.17f);
e.getPlayer().updateInventory();
}
}
if(isHoldingDust(e.getPlayer())) {
if(e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
e.setCancelled(true);
e.getPlayer().playSound(Objects.requireNonNull(e.getClickedBlock()).getLocation(), Sound.ENTITY_ENDER_EYE_DEATH, 2f, 1.97f);
DustRevealer.spawn(e.getClickedBlock(), new VolmitSender(e.getPlayer(), Iris.instance.getTag()));
}
}
} catch(Throwable xx) {
Iris.reportError(xx);
}
}
/**
* Is the player holding Dust?
*
* @param p
* The player
* @return True if they are
*/
public boolean isHoldingDust(Player p) {
ItemStack is = p.getInventory().getItemInMainHand();
return is != null && isDust(is);
}
/**
* Is the itemstack passed Iris dust?
*
* @param is
* The itemstack
* @return True if it is
*/
public boolean isDust(ItemStack is) {
return is.isSimilar(dust);
}
/**
* Update the location on an Iris wand
*
* @param left
* True for first location, false for second
* @param a
* The location
* @param item
* The wand
* @return The updated wand
*/
public ItemStack update(boolean left, Location a, ItemStack item) {
if(!isWand(item)) {
return item;
}
Location[] f = getCuboidFromItem(item);
Location other = left ? f[1] : f[0];
if(other != null && !other.getWorld().getName().equals(a.getWorld().getName())) {
other = null;
}
return createWand(left ? a : other, left ? other : a);
}
}

View File

@ -1,210 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.tools;
import com.google.common.util.concurrent.AtomicDouble;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.exceptions.IrisException;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.O;
import lombok.Data;
import lombok.experimental.Accessors;
import org.bukkit.Bukkit;
import org.bukkit.GameRule;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import java.io.File;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
/**
* Makes it a lot easier to setup an engine, world, studio or whatever
*/
@Data
@Accessors(fluent = true, chain = true)
public class IrisCreator {
/**
* Specify an area to pregenerate during creation
*/
private PregenTask pregen;
/**
* Specify a sender to get updates & progress info + tp when world is created.
*/
private VolmitSender sender;
/**
* The seed to use for this generator
*/
private long seed = 1337;
/**
* The dimension to use. This can be any online dimension, or a dimension in the
* packs folder
*/
private String dimension = IrisSettings.get().getGenerator().getDefaultWorldType();
/**
* The name of this world.
*/
private String name = "irisworld";
/**
* Studio mode makes the engine hotloadable and uses the dimension in
* your Iris/packs folder instead of copying the dimension files into
* the world itself. Studio worlds are deleted when they are unloaded.
*/
private boolean studio = false;
/**
* Create the IrisAccess (contains the world)
*
* @return the IrisAccess
* @throws IrisException
* shit happens
*/
public World create() throws IrisException {
if(Bukkit.isPrimaryThread()) {
throw new IrisException("You cannot invoke create() on the main thread.");
}
IrisDimension d = IrisToolbelt.getDimension(dimension());
if(d == null) {
throw new IrisException("Dimension cannot be found null for id " + dimension());
}
if(!studio()) {
Iris.service(StudioSVC.class).installIntoWorld(sender, d.getLoadKey(), new File(name()));
}
PlatformChunkGenerator access = null;
AtomicReference<World> world = new AtomicReference<>();
AtomicDouble pp = new AtomicDouble(0);
O<Boolean> done = new O<>();
done.set(false);
WorldCreator wc = new IrisWorldCreator()
.dimension(dimension)
.name(name)
.seed(seed)
.studio(studio)
.create();
access = (PlatformChunkGenerator) wc.generator();
PlatformChunkGenerator finalAccess1 = access;
J.a(() ->
{
int req = 441;
Supplier<Integer> g = () -> {
if (finalAccess1 == null || finalAccess1.getEngine() == null) {
return 0;
}
return finalAccess1.getEngine().getGenerated();
};
while(g.get() < req) {
double v = (double) g.get() / (double) req;
if(sender.isPlayer()) {
sender.sendProgress(v, "Generating");
J.sleep(16);
} else {
sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - g.get()) + " Left)")));
J.sleep(1000);
}
}
});
try {
J.sfut(() -> {
world.set(wc.createWorld());
}).get();
} catch(Throwable e) {
e.printStackTrace();
}
if(access == null) {
throw new IrisException("Access is null. Something bad happened.");
}
done.set(true);
if(sender.isPlayer()) {
J.s(() -> {
sender.player().teleport(new Location(world.get(), 0, world.get().getHighestBlockYAt(0, 0), 0));
});
}
if(studio) {
J.s(() -> {
Iris.linkMultiverseCore.removeFromConfig(world.get());
if(IrisSettings.get().getStudio().isDisableTimeAndWeather()) {
world.get().setGameRule(GameRule.DO_WEATHER_CYCLE, false);
world.get().setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
world.get().setTime(6000);
}
});
}
if(pregen != null) {
CompletableFuture<Boolean> ff = new CompletableFuture<>();
IrisToolbelt.pregenerate(pregen, access)
.onProgress(pp::set)
.whenDone(() -> ff.complete(true));
try {
AtomicBoolean dx = new AtomicBoolean(false);
J.a(() -> {
while(!dx.get()) {
if(sender.isPlayer()) {
sender.sendProgress(pp.get(), "Pregenerating");
J.sleep(16);
} else {
sender.sendMessage(C.WHITE + "Pregenerating " + Form.pc(pp.get()));
J.sleep(1000);
}
}
});
ff.get();
dx.set(true);
} catch(Throwable e) {
e.printStackTrace();
}
}
return world.get();
}
}

View File

@ -1,40 +0,0 @@
package com.volmit.iris.core.tools;
import com.volmit.iris.util.data.B;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
/**
* This class is used by an external IrisLib for other plugins to interact with Iris. Do not change
* existing methods or their parameters as it will break the library that uses these methods
* feel free to add more methods so long as you also add the reflective methods to the library
*/
public class IrisReflectiveAPI {
public static boolean isIrisWorld(World world) {
return IrisToolbelt.isIrisWorld(world);
}
public static boolean isIrisStudioWorld(World world) {
return IrisToolbelt.isIrisStudioWorld(world);
}
public static void registerCustomBlockData(String namespace, String key, BlockData blockData) {
B.registerCustomBlockData(namespace, key, blockData);
}
public static void retainMantleData(String classname) {
IrisToolbelt.retainMantleDataForSlice(classname);
}
public static void setMantleData(World world, int x, int y, int z, Object data) {
IrisToolbelt.access(world).getEngine().getMantle().getMantle().set(x, y, z, data);
}
public static void deleteMantleData(World world, int x, int y, int z, Class c) {
IrisToolbelt.access(world).getEngine().getMantle().getMantle().remove(x, y, z, c);
}
public static Object getMantleData(World world, int x, int y, int z, Class c) {
return IrisToolbelt.access(world).getEngine().getMantle().getMantle().get(x, y, z, c);
}
}

View File

@ -1,251 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.tools;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.gui.PregeneratorJob;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.core.pregenerator.methods.HybridPregenMethod;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import java.io.File;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* Something you really want to wear if working on Iris. Shit gets pretty hectic down there.
* Hope you packed snacks & road sodas.
*/
public class IrisToolbelt {
public static Map<String, Boolean> toolbeltConfiguration = new HashMap<>();
/**
* Will find / download / search for the dimension or return null
* <p>
* - You can provide a dimenson in the packs folder by the folder name
* - You can provide a github repo by using (assumes branch is master unless specified)
* - GithubUsername/repository
* - GithubUsername/repository/branch
*
* @param dimension
* the dimension id such as overworld or flat
* @return the IrisDimension or null
*/
public static IrisDimension getDimension(String dimension) {
File pack = Iris.instance.getDataFolder("packs", dimension);
if(!pack.exists()) {
Iris.service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender(), Iris.instance.getTag()), dimension, false, false);
}
if(!pack.exists()) {
return null;
}
return IrisData.get(pack).getDimensionLoader().load(dimension);
}
/**
* Create a world with plenty of options
*
* @return the creator builder
*/
public static IrisCreator createWorld() {
return new IrisCreator();
}
/**
* Checks if the given world is an Iris World (same as access(world) != null)
*
* @param world
* the world
* @return true if it is an Iris Access world
*/
public static boolean isIrisWorld(World world) {
if(world == null) {
return false;
}
if(world.getGenerator() instanceof PlatformChunkGenerator f) {
f.touch(world);
return true;
}
return false;
}
public static boolean isIrisStudioWorld(World world) {
return isIrisWorld(world) && access(world).isStudio();
}
/**
* Get the Iris generator for the given world
*
* @param world
* the given world
* @return the IrisAccess or null if it's not an Iris World
*/
public static PlatformChunkGenerator access(World world) {
if(isIrisWorld(world)) {
return ((PlatformChunkGenerator) world.getGenerator());
} /*else {
Iris.warn("""
"---------- No World? ---------------
""");
}*/
return null;
}
/**
* Start a pregenerator task
*
* @param task
* the scheduled task
* @param method
* the method to execute the task
* @return the pregenerator job (already started)
*/
public static PregeneratorJob pregenerate(PregenTask task, PregeneratorMethod method, Engine engine) {
return new PregeneratorJob(task, method, engine);
}
/**
* Start a pregenerator task. If the supplied generator is headless, headless mode is used,
* otherwise Hybrid mode is used.
*
* @param task
* the scheduled task
* @param gen
* the Iris Generator
* @return the pregenerator job (already started)
*/
public static PregeneratorJob pregenerate(PregenTask task, PlatformChunkGenerator gen) {
return pregenerate(task, new HybridPregenMethod(gen.getEngine().getWorld().realWorld(),
IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), gen.getEngine());
}
/**
* Start a pregenerator task. If the supplied generator is headless, headless mode is used,
* otherwise Hybrid mode is used.
*
* @param task
* the scheduled task
* @param world
* the World
* @return the pregenerator job (already started)
*/
public static PregeneratorJob pregenerate(PregenTask task, World world) {
if(isIrisWorld(world)) {
return pregenerate(task, access(world));
}
return pregenerate(task, new HybridPregenMethod(world, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), null);
}
/**
* Evacuate all players from the world into literally any other world.
* If there are no other worlds, kick them! Not the best but what's mine is mine sometimes...
*
* @param world
* the world to evac
*/
public static boolean evacuate(World world) {
for(World i : Bukkit.getWorlds()) {
if(!i.getName().equals(world.getName())) {
for(Player j : world.getPlayers()) {
new VolmitSender(j, Iris.instance.getTag()).sendMessage("You have been evacuated from this world.");
j.teleport(i.getSpawnLocation());
}
return true;
}
}
return false;
}
/**
* Evacuate all players from the world
*
* @param world
* the world to leave
* @param m
* the message
* @return true if it was evacuated.
*/
public static boolean evacuate(World world, String m) {
for(World i : Bukkit.getWorlds()) {
if(!i.getName().equals(world.getName())) {
for(Player j : world.getPlayers()) {
new VolmitSender(j, Iris.instance.getTag()).sendMessage("You have been evacuated from this world. " + m);
j.teleport(i.getSpawnLocation());
}
return true;
}
}
return false;
}
public static boolean isStudio(World i) {
return isIrisWorld(i) && access(i).isStudio();
}
public static void retainMantleDataForSlice(String className) {
toolbeltConfiguration.put("retain.mantle." + className, true);
}
public static <T> T getMantleData(World world, int x, int y, int z, Class<T> of) {
PlatformChunkGenerator e = access(world);
if(e == null) {return null;}
return e.getEngine().getMantle().getMantle().get(x, y - world.getMinHeight(), z, of);
}
public static <T> void deleteMantleData(World world, int x, int y, int z, Class<T> of) {
PlatformChunkGenerator e = access(world);
if(e == null) {return;}
e.getEngine().getMantle().getMantle().remove(x, y - world.getMinHeight(), z, of);
}
}

View File

@ -1,100 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.tools;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisWorld;
import com.volmit.iris.engine.platform.BukkitChunkGenerator;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.generator.ChunkGenerator;
import java.io.File;
public class IrisWorldCreator {
private String name;
private boolean studio = false;
private String dimensionName = null;
private long seed = 1337;
public IrisWorldCreator() {
}
public IrisWorldCreator dimension(String loadKey) {
this.dimensionName = loadKey;
return this;
}
public IrisWorldCreator name(String name) {
this.name = name;
return this;
}
public IrisWorldCreator seed(long seed) {
this.seed = seed;
return this;
}
public IrisWorldCreator studioMode() {
this.studio = true;
return this;
}
public IrisWorldCreator productionMode() {
this.studio = false;
return this;
}
public WorldCreator create() {
IrisDimension dim = IrisData.loadAnyDimension(dimensionName);
IrisWorld w = IrisWorld.builder()
.name(name)
.minHeight(dim.getMinHeight())
.maxHeight(dim.getMaxHeight())
.seed(seed)
.worldFolder(new File(name))
.environment(findEnvironment())
.build();
ChunkGenerator g = new BukkitChunkGenerator(w, studio, studio
? dim.getLoader().getDataFolder() :
new File(w.worldFolder(), "iris/pack"), dimensionName);
return new WorldCreator(name)
.environment(findEnvironment())
.generateStructures(true)
.generator(g).seed(seed);
}
private World.Environment findEnvironment() {
IrisDimension dim = IrisData.loadAnyDimension(dimensionName);
if(dim == null || dim.getEnvironment() == null) {
return World.Environment.NORMAL;
} else {
return dim.getEnvironment();
}
}
public IrisWorldCreator studio(boolean studio) {
this.studio = studio;
return this;
}
}

View File

@ -1,114 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.wand;
import com.volmit.iris.util.data.Cuboid;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.awt.Color;
public class WandSelection {
private final Cuboid c;
private final Player p;
public WandSelection(Cuboid c, Player p) {
this.c = c;
this.p = p;
}
public void draw() {
double accuracy = M.lerpInverse(0, 64 * 64, p.getLocation().distanceSquared(c.getCenter()));
double dist = M.lerp(0.125, 3.5, accuracy);
for(double i = c.getLowerX() - 1; i < c.getUpperX() + 1; i += 0.25) {
for(double j = c.getLowerY() - 1; j < c.getUpperY() + 1; j += 0.25) {
for(double k = c.getLowerZ() - 1; k < c.getUpperZ() + 1; k += 0.25) {
boolean ii = i == c.getLowerX() || i == c.getUpperX();
boolean jj = j == c.getLowerY() || j == c.getUpperY();
boolean kk = k == c.getLowerZ() || k == c.getUpperZ();
if((ii && jj) || (ii && kk) || (kk && jj)) {
Vector push = new Vector(0, 0, 0);
if(i == c.getLowerX()) {
push.add(new Vector(-0.55, 0, 0));
}
if(j == c.getLowerY()) {
push.add(new Vector(0, -0.55, 0));
}
if(k == c.getLowerZ()) {
push.add(new Vector(0, 0, -0.55));
}
if(i == c.getUpperX()) {
push.add(new Vector(0.55, 0, 0));
}
if(j == c.getUpperY()) {
push.add(new Vector(0, 0.55, 0));
}
if(k == c.getUpperZ()) {
push.add(new Vector(0, 0, 0.55));
}
Location a = new Location(c.getWorld(), i, j, k).add(0.5, 0.5, 0.5).add(push);
accuracy = M.lerpInverse(0, 64 * 64, p.getLocation().distanceSquared(a));
dist = M.lerp(0.125, 3.5, accuracy);
if(M.r(M.min(dist * 5, 0.9D) * 0.995)) {
continue;
}
if(ii && jj) {
a.add(0, 0, RNG.r.d(-0.3, 0.3));
}
if(kk && jj) {
a.add(RNG.r.d(-0.3, 0.3), 0, 0);
}
if(ii && kk) {
a.add(0, RNG.r.d(-0.3, 0.3), 0);
}
if(p.getLocation().distanceSquared(a) < 256 * 256) {
Color color = Color.getHSBColor((float) (0.5f + (Math.sin((i + j + k + (p.getTicksLived() / 2f)) / (20f)) / 2)), 1, 1);
int r = color.getRed();
int g = color.getGreen();
int b = color.getBlue();
p.spawnParticle(Particle.REDSTONE, a.getX(), a.getY(), a.getZ(),
1, 0, 0, 0, 0,
new Particle.DustOptions(org.bukkit.Color.fromRGB(r, g, b),
(float) dist * 3f));
}
}
}
}
}
}
}

View File

@ -1,48 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine;
import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KMap;
public class EnginePanic {
private static final KMap<String, String> stuff = new KMap<>();
private static KMap<String, String> last = new KMap<>();
public static void add(String key, String value) {
stuff.put(key, value);
}
public static void saveLast() {
last = stuff.copy();
}
public static void lastPanic() {
for(String i : last.keySet()) {
Iris.error("Last Panic " + i + ": " + stuff.get(i));
}
}
public static void panic() {
lastPanic();
for(String i : stuff.keySet()) {
Iris.error("Engine Panic " + i + ": " + stuff.get(i));
}
}
}

View File

@ -1,374 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.InferredType;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDecorationPart;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.engine.object.IrisGenerator;
import com.volmit.iris.engine.object.IrisInterpolator;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.stream.ProceduralStream;
import com.volmit.iris.util.stream.interpolation.Interpolated;
import lombok.Data;
import org.bukkit.Material;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import java.util.UUID;
@Data
public class IrisComplex implements DataProvider {
private static final BlockData AIR = Material.AIR.createBlockData();
private RNG rng;
private double fluidHeight;
private IrisData data;
private KMap<IrisInterpolator, KSet<IrisGenerator>> generators;
private ProceduralStream<IrisRegion> regionStream;
private ProceduralStream<Double> regionStyleStream;
private ProceduralStream<Double> regionIdentityStream;
private ProceduralStream<UUID> regionIDStream;
private ProceduralStream<InferredType> bridgeStream;
private ProceduralStream<IrisBiome> landBiomeStream;
private ProceduralStream<IrisBiome> caveBiomeStream;
private ProceduralStream<IrisBiome> seaBiomeStream;
private ProceduralStream<IrisBiome> shoreBiomeStream;
private ProceduralStream<IrisBiome> baseBiomeStream;
private ProceduralStream<UUID> baseBiomeIDStream;
private ProceduralStream<IrisBiome> trueBiomeStream;
private ProceduralStream<Biome> trueBiomeDerivativeStream;
private ProceduralStream<Double> heightStream;
private ProceduralStream<Integer> roundedHeighteightStream;
private ProceduralStream<Double> maxHeightStream;
private ProceduralStream<Double> overlayStream;
private ProceduralStream<Double> heightFluidStream;
private ProceduralStream<Double> slopeStream;
private ProceduralStream<Integer> topSurfaceStream;
private ProceduralStream<IrisDecorator> terrainSurfaceDecoration;
private ProceduralStream<IrisDecorator> terrainCeilingDecoration;
private ProceduralStream<IrisDecorator> terrainCaveSurfaceDecoration;
private ProceduralStream<IrisDecorator> terrainCaveCeilingDecoration;
private ProceduralStream<IrisDecorator> seaSurfaceDecoration;
private ProceduralStream<IrisDecorator> seaFloorDecoration;
private ProceduralStream<IrisDecorator> shoreSurfaceDecoration;
private ProceduralStream<BlockData> rockStream;
private ProceduralStream<BlockData> fluidStream;
private IrisBiome focusBiome;
private IrisRegion focusRegion;
public IrisComplex(Engine engine) {
this(engine, false);
}
public IrisComplex(Engine engine, boolean simple) {
int cacheSize = IrisSettings.get().getPerformance().getCacheSize();
IrisBiome emptyBiome = new IrisBiome();
UUID focusUUID = UUID.nameUUIDFromBytes("focus".getBytes());
this.rng = new RNG(engine.getSeedManager().getComplex());
this.data = engine.getData();
double height = engine.getMaxHeight();
fluidHeight = engine.getDimension().getFluidHeight();
generators = new KMap<>();
focusBiome = engine.getFocus();
focusRegion = engine.getFocusRegion();
KMap<InferredType, ProceduralStream<IrisBiome>> inferredStreams = new KMap<>();
if(focusBiome != null) {
focusBiome.setInferredType(InferredType.LAND);
focusRegion = findRegion(focusBiome, engine);
}
//@builder
engine.getDimension().getRegions().forEach((i) -> data.getRegionLoader().load(i)
.getAllBiomes(this).forEach((b) -> b
.getGenerators()
.forEach((c) -> registerGenerator(c.getCachedGenerator(this)))));
overlayStream = ProceduralStream.ofDouble((x, z) -> 0.0D);
engine.getDimension().getOverlayNoise().forEach(i -> overlayStream = overlayStream.add((x, z) -> i.get(rng, getData(), x, z)));
rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream()
.select(engine.getDimension().getRockPalette().getBlockData(data));
fluidStream = engine.getDimension().getFluidPalette().getLayerGenerator(rng.nextParallelRNG(78), data).stream()
.select(engine.getDimension().getFluidPalette().getBlockData(data));
regionStyleStream = engine.getDimension().getRegionStyle().create(rng.nextParallelRNG(883), getData()).stream()
.zoom(engine.getDimension().getRegionZoom());
regionIdentityStream = regionStyleStream.fit(Integer.MIN_VALUE, Integer.MAX_VALUE);
regionStream = focusRegion != null ?
ProceduralStream.of((x, z) -> focusRegion,
Interpolated.of(a -> 0D, a -> focusRegion))
: regionStyleStream
.selectRarity(data.getRegionLoader().loadAll(engine.getDimension().getRegions()))
.cache2D("regionStream", engine, cacheSize);
regionIDStream = regionIdentityStream.convertCached((i) -> new UUID(Double.doubleToLongBits(i), String.valueOf(i * 38445).hashCode() * 3245556666L));
caveBiomeStream = regionStream.convert((r)
-> engine.getDimension().getCaveBiomeStyle().create(rng.nextParallelRNG(InferredType.CAVE.ordinal()), getData()).stream()
.zoom(r.getCaveBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getCaveBiomes()))
.onNull(emptyBiome)
).convertAware2D(ProceduralStream::get).cache2D("caveBiomeStream", engine, cacheSize);
inferredStreams.put(InferredType.CAVE, caveBiomeStream);
landBiomeStream = regionStream.convert((r)
-> engine.getDimension().getLandBiomeStyle().create(rng.nextParallelRNG(InferredType.LAND.ordinal()), getData()).stream()
.zoom(r.getLandBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getLandBiomes(), (t) -> t.setInferredType(InferredType.LAND)))
).convertAware2D(ProceduralStream::get)
.cache2D("landBiomeStream", engine, cacheSize);
inferredStreams.put(InferredType.LAND, landBiomeStream);
seaBiomeStream = regionStream.convert((r)
-> engine.getDimension().getSeaBiomeStyle().create(rng.nextParallelRNG(InferredType.SEA.ordinal()), getData()).stream()
.zoom(r.getSeaBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getSeaBiomes(), (t) -> t.setInferredType(InferredType.SEA)))
).convertAware2D(ProceduralStream::get)
.cache2D("seaBiomeStream", engine, cacheSize);
inferredStreams.put(InferredType.SEA, seaBiomeStream);
shoreBiomeStream = regionStream.convert((r)
-> engine.getDimension().getShoreBiomeStyle().create(rng.nextParallelRNG(InferredType.SHORE.ordinal()), getData()).stream()
.zoom(r.getShoreBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getShoreBiomes(), (t) -> t.setInferredType(InferredType.SHORE)))
).convertAware2D(ProceduralStream::get).cache2D("shoreBiomeStream", engine, cacheSize);
inferredStreams.put(InferredType.SHORE, shoreBiomeStream);
bridgeStream = focusBiome != null ? ProceduralStream.of((x, z) -> focusBiome.getInferredType(),
Interpolated.of(a -> 0D, a -> focusBiome.getInferredType())) :
engine.getDimension().getContinentalStyle().create(rng.nextParallelRNG(234234565), getData())
.bake().scale(1D / engine.getDimension().getContinentZoom()).bake().stream()
.convert((v) -> v >= engine.getDimension().getLandChance() ? InferredType.SEA : InferredType.LAND)
.cache2D("bridgeStream", engine, cacheSize);
baseBiomeStream = focusBiome != null ? ProceduralStream.of((x, z) -> focusBiome,
Interpolated.of(a -> 0D, a -> focusBiome)) :
bridgeStream.convertAware2D((t, x, z) -> inferredStreams.get(t).get(x, z))
.convertAware2D(this::implode)
.cache2D("baseBiomeStream", engine, cacheSize);
heightStream = ProceduralStream.of((x, z) -> {
IrisBiome b = focusBiome != null ? focusBiome : baseBiomeStream.get(x, z);
return getHeight(engine, b, x, z, engine.getSeedManager().getHeight());
}, Interpolated.DOUBLE).clamp(0, engine.getHeight()).cache2D("heightStream", engine, cacheSize);
roundedHeighteightStream = heightStream.round();
slopeStream = heightStream.slope(3).cache2D("slopeStream", engine, cacheSize);
trueBiomeStream = focusBiome != null ? ProceduralStream.of((x, y) -> focusBiome, Interpolated.of(a -> 0D,
b -> focusBiome))
.cache2D("trueBiomeStream-focus", engine, cacheSize) : heightStream
.convertAware2D((h, x, z) ->
fixBiomeType(h, baseBiomeStream.get(x, z),
regionStream.get(x, z), x, z, fluidHeight))
.cache2D("trueBiomeStream", engine, cacheSize);
trueBiomeDerivativeStream = trueBiomeStream.convert(IrisBiome::getDerivative).cache2D("trueBiomeDerivativeStream", engine, cacheSize);
heightFluidStream = heightStream.max(fluidHeight).cache2D("heightFluidStream", engine, cacheSize);
maxHeightStream = ProceduralStream.ofDouble((x, z) -> height);
terrainSurfaceDecoration = trueBiomeStream
.convertAware2D((b, xx, zz) -> decorateFor(b, xx, zz, IrisDecorationPart.NONE)).cache2D("terrainSurfaceDecoration", engine, cacheSize);
terrainCeilingDecoration = trueBiomeStream
.convertAware2D((b, xx, zz) -> decorateFor(b, xx, zz, IrisDecorationPart.CEILING)).cache2D("terrainCeilingDecoration", engine, cacheSize);
terrainCaveSurfaceDecoration = caveBiomeStream
.convertAware2D((b, xx, zz) -> decorateFor(b, xx, zz, IrisDecorationPart.NONE)).cache2D("terrainCaveSurfaceDecoration", engine, cacheSize);
terrainCaveCeilingDecoration = caveBiomeStream
.convertAware2D((b, xx, zz) -> decorateFor(b, xx, zz, IrisDecorationPart.CEILING)).cache2D("terrainCaveCeilingDecoration", engine, cacheSize);
shoreSurfaceDecoration = trueBiomeStream
.convertAware2D((b, xx, zz) -> decorateFor(b, xx, zz, IrisDecorationPart.SHORE_LINE)).cache2D("shoreSurfaceDecoration", engine, cacheSize);
seaSurfaceDecoration = trueBiomeStream
.convertAware2D((b, xx, zz) -> decorateFor(b, xx, zz, IrisDecorationPart.SEA_SURFACE)).cache2D("seaSurfaceDecoration", engine, cacheSize);
seaFloorDecoration = trueBiomeStream
.convertAware2D((b, xx, zz) -> decorateFor(b, xx, zz, IrisDecorationPart.SEA_FLOOR)).cache2D("seaFloorDecoration", engine, cacheSize);
baseBiomeIDStream = trueBiomeStream.convertAware2D((b, x, z) -> {
UUID d = regionIDStream.get(x, z);
return new UUID(b.getLoadKey().hashCode() * 818223L,
d.hashCode());
})
.cache2D("", engine, cacheSize);
//@done
}
public ProceduralStream<IrisBiome> getBiomeStream(InferredType type) {
switch(type) {
case CAVE:
return caveBiomeStream;
case LAND:
return landBiomeStream;
case SEA:
return seaBiomeStream;
case SHORE:
return shoreBiomeStream;
case DEFER:
default:
break;
}
return null;
}
private IrisRegion findRegion(IrisBiome focus, Engine engine) {
for(IrisRegion i : engine.getDimension().getAllRegions(engine)) {
if(i.getAllBiomeIds().contains(focus.getLoadKey())) {
return i;
}
}
return null;
}
private IrisDecorator decorateFor(IrisBiome b, double x, double z, IrisDecorationPart part) {
RNG rngc = new RNG(Cache.key(((int) x), ((int) z)));
for(IrisDecorator i : b.getDecorators()) {
if(!i.getPartOf().equals(part)) {
continue;
}
BlockData block = i.getBlockData(b, rngc, x, z, data);
if(block != null) {
return i;
}
}
return null;
}
private IrisBiome fixBiomeType(Double height, IrisBiome biome, IrisRegion region, Double x, Double z, double fluidHeight) {
double sh = region.getShoreHeight(x, z);
if(height >= fluidHeight - 1 && height <= fluidHeight + sh && !biome.isShore()) {
return shoreBiomeStream.get(x, z);
}
if(height > fluidHeight + sh && !biome.isLand()) {
return landBiomeStream.get(x, z);
}
if(height < fluidHeight && !biome.isAquatic()) {
return seaBiomeStream.get(x, z);
}
if(height == fluidHeight && !biome.isShore()) {
return shoreBiomeStream.get(x, z);
}
return biome;
}
private double interpolateGenerators(Engine engine, IrisInterpolator interpolator, KSet<IrisGenerator> generators, double x, double z, long seed) {
if(generators.isEmpty()) {
return 0;
}
double hi = interpolator.interpolate(x, z, (xx, zz) -> {
try {
IrisBiome bx = baseBiomeStream.get(xx, zz);
double b = 0;
for(IrisGenerator gen : generators) {
b += bx.getGenLinkMax(gen.getLoadKey());
}
return b;
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
Iris.error("Failed to sample hi biome at " + xx + " " + zz + "...");
}
return 0;
});
double lo = interpolator.interpolate(x, z, (xx, zz) -> {
try {
IrisBiome bx = baseBiomeStream.get(xx, zz);
double b = 0;
for(IrisGenerator gen : generators) {
b += bx.getGenLinkMin(gen.getLoadKey());
}
return b;
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
Iris.error("Failed to sample lo biome at " + xx + " " + zz + "...");
}
return 0;
});
double d = 0;
for(IrisGenerator i : generators) {
d += M.lerp(lo, hi, i.getHeight(x, z, seed + 239945));
}
return d / generators.size();
}
private double getInterpolatedHeight(Engine engine, double x, double z, long seed) {
double h = 0;
for(IrisInterpolator i : generators.keySet()) {
h += interpolateGenerators(engine, i, generators.get(i), x, z, seed);
}
return h;
}
private double getHeight(Engine engine, IrisBiome b, double x, double z, long seed) {
return Math.max(Math.min(getInterpolatedHeight(engine, x, z, seed) + fluidHeight + overlayStream.get(x, z), engine.getHeight()), 0);
}
private void registerGenerator(IrisGenerator cachedGenerator) {
generators.computeIfAbsent(cachedGenerator.getInterpolator(), (k) -> new KSet<>()).add(cachedGenerator);
}
private IrisBiome implode(IrisBiome b, Double x, Double z) {
if(b.getChildren().isEmpty()) {
return b;
}
return implode(b, x, z, 3);
}
private IrisBiome implode(IrisBiome b, Double x, Double z, int max) {
if(max < 0) {
return b;
}
if(b.getChildren().isEmpty()) {
return b;
}
CNG childCell = b.getChildrenGenerator(rng, 123, b.getChildShrinkFactor());
KList<IrisBiome> chx = b.getRealChildren(this).copy();
chx.add(b);
IrisBiome biome = childCell.fitRarity(chx, x, z);
biome.setInferredType(b.getInferredType());
return implode(biome, x, z, max - 1);
}
public void close() {
}
}

View File

@ -1,516 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine;
import com.google.common.util.concurrent.AtomicDouble;
import com.google.gson.Gson;
import com.volmit.iris.Iris;
import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.events.IrisEngineHotloadEvent;
import com.volmit.iris.core.gui.PregeneratorJob;
import com.volmit.iris.core.project.IrisProject;
import com.volmit.iris.core.service.PreservationSVC;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineEffects;
import com.volmit.iris.engine.framework.EngineMetrics;
import com.volmit.iris.engine.framework.EngineMode;
import com.volmit.iris.engine.framework.EngineTarget;
import com.volmit.iris.engine.framework.EngineWorldManager;
import com.volmit.iris.engine.framework.SeedManager;
import com.volmit.iris.engine.framework.WrongEngineBroException;
import com.volmit.iris.engine.mantle.EngineMantle;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomePaletteLayer;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.engine.object.IrisEngineData;
import com.volmit.iris.engine.object.IrisJigsawStructure;
import com.volmit.iris.engine.object.IrisObjectPlacement;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
import com.volmit.iris.util.atomics.AtomicRollingSequence;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Data;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.command.CommandSender;
import java.io.File;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@Data
public class IrisEngine implements Engine {
private final AtomicInteger bud;
private final AtomicInteger buds;
private final AtomicInteger generated;
private final AtomicInteger generatedLast;
private final AtomicDouble perSecond;
private final AtomicLong lastGPS;
private final EngineTarget target;
private final IrisContext context;
private final EngineMantle mantle;
private final ChronoLatch perSecondLatch;
private final ChronoLatch perSecondBudLatch;
private final EngineMetrics metrics;
private final boolean studio;
private final AtomicRollingSequence wallClock;
private final int art;
private EngineMode mode;
private final AtomicCache<IrisEngineData> engineData = new AtomicCache<>();
private final AtomicBoolean cleaning;
private final ChronoLatch cleanLatch;
private final SeedManager seedManager;
private EngineEffects effects;
private EngineExecutionEnvironment execution;
private EngineWorldManager worldManager;
private volatile int parallelism;
private volatile int minHeight;
private boolean failing;
private boolean closed;
private int cacheId;
private double maxBiomeObjectDensity;
private double maxBiomeLayerDensity;
private double maxBiomeDecoratorDensity;
private IrisComplex complex;
public IrisEngine(EngineTarget target, boolean studio) {
this.studio = studio;
this.target = target;
getEngineData();
verifySeed();
this.seedManager = new SeedManager(target.getWorld().getRawWorldSeed());
bud = new AtomicInteger(0);
buds = new AtomicInteger(0);
metrics = new EngineMetrics(32);
cleanLatch = new ChronoLatch(10000);
generatedLast = new AtomicInteger(0);
perSecond = new AtomicDouble(0);
perSecondLatch = new ChronoLatch(1000, false);
perSecondBudLatch = new ChronoLatch(1000, false);
wallClock = new AtomicRollingSequence(32);
lastGPS = new AtomicLong(M.ms());
generated = new AtomicInteger(0);
mantle = new IrisEngineMantle(this);
context = new IrisContext(this);
cleaning = new AtomicBoolean(false);
context.touch();
Iris.info("Initializing Engine: " + target.getWorld().name() + "/" + target.getDimension().getLoadKey() + " (" + target.getDimension().getDimensionHeight() + " height) Seed: " + getSeedManager().getSeed());
getData().setEngine(this);
minHeight = 0;
failing = false;
closed = false;
art = J.ar(this::tickRandomPlayer, 0);
setupEngine();
Iris.debug("Engine Initialized " + getCacheID());
}
private void verifySeed() {
if(getEngineData().getSeed() != null && getEngineData().getSeed() != target.getWorld().getRawWorldSeed()) {
target.getWorld().setRawWorldSeed(getEngineData().getSeed());
}
}
private void tickRandomPlayer() {
if(perSecondBudLatch.flip()) {
buds.set(bud.get());
bud.set(0);
}
if(effects != null) {
effects.tickRandomPlayer();
}
}
private void prehotload() {
worldManager.close();
complex.close();
execution.close();
effects.close();
mode.close();
J.a(() -> new IrisProject(getData().getDataFolder()).updateWorkspace());
}
private void setupEngine() {
try {
Iris.debug("Setup Engine " + getCacheID());
cacheId = RNG.r.nextInt();
worldManager = new IrisWorldManager(this);
complex = new IrisComplex(this);
execution = new IrisExecutionEnvironment(this);
effects = new IrisEngineEffects(this);
setupMode();
J.a(this::computeBiomeMaxes);
} catch(Throwable e) {
Iris.error("FAILED TO SETUP ENGINE!");
e.printStackTrace();
}
Iris.debug("Engine Setup Complete " + getCacheID());
}
private void setupMode() {
if(mode != null) {
mode.close();
}
mode = getDimension().getMode().getType().create(this);
}
@Override
public void generateMatter(int x, int z, boolean multicore) {
getMantle().generateMatter(x, z, multicore);
}
@Override
public Set<String> getObjectsAt(int x, int z) {
return getMantle().getObjectComponent().guess(x, z);
}
@Override
public IrisJigsawStructure getStructureAt(int x, int z) {
return getMantle().getJigsawComponent().guess(x, z);
}
private void warmupChunk(int x, int z) {
for(int i = 0; i < 16; i++) {
for(int j = 0; j < 16; j++) {
int xx = x + (i << 4);
int zz = z + (z << 4);
getComplex().getTrueBiomeStream().get(xx, zz);
getComplex().getHeightStream().get(xx, zz);
}
}
}
@Override
public void hotload() {
hotloadSilently();
Iris.callEvent(new IrisEngineHotloadEvent(this));
}
public void hotloadComplex() {
complex.close();
complex = new IrisComplex(this);
}
public void hotloadSilently() {
getData().dump();
getData().clearLists();
getTarget().setDimension(getData().getDimensionLoader().load(getDimension().getLoadKey()));
prehotload();
setupEngine();
J.a(() -> { synchronized(ServerConfigurator.class) { ServerConfigurator.installDataPacks(false); } });
}
@Override
public IrisEngineData getEngineData() {
World w = null;
return engineData.aquire(() -> {
//TODO: Method this file
File f = new File(getWorld().worldFolder(), "iris/engine-data/" + getDimension().getLoadKey() + ".json");
if(!f.exists()) {
try {
f.getParentFile().mkdirs();
IO.writeAll(f, new Gson().toJson(new IrisEngineData()));
} catch(IOException e) {
e.printStackTrace();
}
}
try {
return new Gson().fromJson(IO.readAll(f), IrisEngineData.class);
} catch(Throwable e) {
e.printStackTrace();
}
return new IrisEngineData();
});
}
@Override
public int getGenerated() {
return generated.get();
}
@Override
public double getGeneratedPerSecond() {
if(perSecondLatch.flip()) {
double g = generated.get() - generatedLast.get();
generatedLast.set(generated.get());
if(g == 0) {
return 0;
}
long dur = M.ms() - lastGPS.get();
lastGPS.set(M.ms());
perSecond.set(g / ((double) (dur) / 1000D));
}
return perSecond.get();
}
@Override
public boolean isStudio() {
return studio;
}
private void computeBiomeMaxes() {
for(IrisBiome i : getDimension().getAllBiomes(this)) {
double density = 0;
for(IrisObjectPlacement j : i.getObjects()) {
density += j.getDensity() * j.getChance();
}
maxBiomeObjectDensity = Math.max(maxBiomeObjectDensity, density);
density = 0;
for(IrisDecorator j : i.getDecorators()) {
density += Math.max(j.getStackMax(), 1) * j.getChance();
}
maxBiomeDecoratorDensity = Math.max(maxBiomeDecoratorDensity, density);
density = 0;
for(IrisBiomePaletteLayer j : i.getLayers()) {
density++;
}
maxBiomeLayerDensity = Math.max(maxBiomeLayerDensity, density);
}
}
@Override
public int getBlockUpdatesPerSecond() {
return buds.get();
}
public void printMetrics(CommandSender sender) {
KMap<String, Double> totals = new KMap<>();
KMap<String, Double> weights = new KMap<>();
double masterWallClock = wallClock.getAverage();
KMap<String, Double> timings = getMetrics().pull();
double totalWeight = 0;
double wallClock = getMetrics().getTotal().getAverage();
for(double j : timings.values()) {
totalWeight += j;
}
for(String j : timings.k()) {
weights.put(getName() + "." + j, (wallClock / totalWeight) * timings.get(j));
}
totals.put(getName(), wallClock);
double mtotals = 0;
for(double i : totals.values()) {
mtotals += i;
}
for(String i : totals.k()) {
totals.put(i, (masterWallClock / mtotals) * totals.get(i));
}
double v = 0;
for(double i : weights.values()) {
v += i;
}
for(String i : weights.k()) {
weights.put(i, weights.get(i) / v);
}
sender.sendMessage("Total: " + C.BOLD + C.WHITE + Form.duration(masterWallClock, 0));
for(String i : totals.k()) {
sender.sendMessage(" Engine " + C.UNDERLINE + C.GREEN + i + C.RESET + ": " + C.BOLD + C.WHITE + Form.duration(totals.get(i), 0));
}
sender.sendMessage("Details: ");
for(String i : weights.sortKNumber().reverse()) {
String befb = C.UNDERLINE + "" + C.GREEN + "" + i.split("\\Q[\\E")[0] + C.RESET + C.GRAY + "[";
String num = C.GOLD + i.split("\\Q[\\E")[1].split("]")[0] + C.RESET + C.GRAY + "].";
String afb = C.ITALIC + "" + C.AQUA + i.split("\\Q]\\E")[1].substring(1) + C.RESET + C.GRAY;
sender.sendMessage(" " + befb + num + afb + ": " + C.BOLD + C.WHITE + Form.pc(weights.get(i), 0));
}
}
@Override
public void close() {
PregeneratorJob.shutdownInstance();
closed = true;
J.car(art);
getWorldManager().close();
getTarget().close();
saveEngineData();
getMantle().close();
getComplex().close();
mode.close();
getData().dump();
getData().clearLists();
Iris.service(PreservationSVC.class).dereference();
Iris.debug("Engine Fully Shutdown!");
complex = null;
}
@Override
public boolean isClosed() {
return closed;
}
@Override
public void recycle() {
if(!cleanLatch.flip()) {
return;
}
if(cleaning.get()) {
cleanLatch.flipDown();
return;
}
cleaning.set(true);
J.a(() -> {
try {
getMantle().trim();
getData().getObjectLoader().clean();
} catch(Throwable e) {
Iris.reportError(e);
Iris.error("Cleanup failed! Enable debug to see stacktrace.");
}
cleaning.lazySet(false);
});
}
@BlockCoordinates
@Override
public void generate(int x, int z, Hunk<BlockData> vblocks, Hunk<Biome> vbiomes, boolean multicore) throws WrongEngineBroException {
if(closed) {
throw new WrongEngineBroException();
}
context.touch();
getEngineData().getStatistics().generatedChunk();
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
Hunk<BlockData> blocks = vblocks.listen((xx, y, zz, t) -> catchBlockUpdates(x + xx, y + getMinHeight(), z + zz, t));
if(getDimension().isDebugChunkCrossSections() && ((x >> 4) % getDimension().getDebugCrossSectionsMod() == 0 || (z >> 4) % getDimension().getDebugCrossSectionsMod() == 0)) {
for(int i = 0; i < 16; i++) {
for(int j = 0; j < 16; j++) {
blocks.set(i, 0, j, Material.CRYING_OBSIDIAN.createBlockData());
}
}
} else {
mode.generate(x, z, blocks, vbiomes, multicore);
}
getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.REAL, true);
getMetrics().getTotal().put(p.getMilliseconds());
generated.incrementAndGet();
recycle();
} catch(Throwable e) {
Iris.reportError(e);
fail("Failed to generate " + x + ", " + z, e);
}
}
@Override
public void saveEngineData() {
//TODO: Method this file
File f = new File(getWorld().worldFolder(), "iris/engine-data/" + getDimension().getLoadKey() + ".json");
f.getParentFile().mkdirs();
try {
IO.writeAll(f, new Gson().toJson(getEngineData()));
Iris.debug("Saved Engine Data");
} catch(IOException e) {
Iris.error("Failed to save Engine Data");
e.printStackTrace();
}
}
@Override
public void blockUpdatedMetric() {
bud.incrementAndGet();
}
@Override
public IrisBiome getFocus() {
if(getDimension().getFocus() == null || getDimension().getFocus().trim().isEmpty()) {
return null;
}
return getData().getBiomeLoader().load(getDimension().getFocus());
}
@Override
public IrisRegion getFocusRegion() {
if(getDimension().getFocusRegion() == null || getDimension().getFocusRegion().trim().isEmpty()) {
return null;
}
return getData().getRegionLoader().load(getDimension().getFocusRegion());
}
@Override
public void fail(String error, Throwable e) {
failing = true;
Iris.error(error);
e.printStackTrace();
}
@Override
public boolean hasFailed() {
return failing;
}
@Override
public int getCacheID() {
return cacheId;
}
}

View File

@ -1,91 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineAssignedComponent;
import com.volmit.iris.engine.framework.EngineEffects;
import com.volmit.iris.engine.framework.EnginePlayer;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Semaphore;
public class IrisEngineEffects extends EngineAssignedComponent implements EngineEffects {
private final KMap<UUID, EnginePlayer> players;
private final Semaphore limit;
public IrisEngineEffects(Engine engine) {
super(engine, "FX");
players = new KMap<>();
limit = new Semaphore(1);
}
@Override
public void updatePlayerMap() {
List<Player> pr = getEngine().getWorld().getPlayers();
if(pr == null) {
return;
}
for(Player i : pr) {
boolean pcc = players.containsKey(i.getUniqueId());
if(!pcc) {
players.put(i.getUniqueId(), new EnginePlayer(getEngine(), i));
}
}
for(UUID i : players.k()) {
if(!pr.contains(players.get(i).getPlayer())) {
players.remove(i);
}
}
}
@Override
public void tickRandomPlayer() {
if(limit.tryAcquire()) {
if(M.r(0.02)) {
updatePlayerMap();
limit.release();
return;
}
if(players.isEmpty()) {
limit.release();
return;
}
double limitms = 1.5;
int max = players.size();
PrecisionStopwatch p = new PrecisionStopwatch();
while(max-- > 0 && M.ms() - p.getMilliseconds() < limitms) {
players.v().getRandom().tick();
}
limit.release();
}
}
}

View File

@ -1,328 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.engine;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.mantle.EngineMantle;
import com.volmit.iris.engine.mantle.MantleComponent;
import com.volmit.iris.engine.mantle.components.MantleCarvingComponent;
import com.volmit.iris.engine.mantle.components.MantleFluidBodyComponent;
import com.volmit.iris.engine.mantle.components.MantleJigsawComponent;
import com.volmit.iris.engine.mantle.components.MantleObjectComponent;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisDepositGenerator;
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisObjectPlacement;
import com.volmit.iris.engine.object.IrisObjectScale;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.parallel.BurstExecutor;
import lombok.Data;
import org.bukkit.util.BlockVector;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@Data
public class IrisEngineMantle implements EngineMantle {
private final Engine engine;
private final Mantle mantle;
private final KList<MantleComponent> components;
private final int radius;
private final AtomicCache<Integer> radCache = new AtomicCache<>();
private final MantleObjectComponent object;
private final MantleJigsawComponent jigsaw;
public IrisEngineMantle(Engine engine) {
this.engine = engine;
this.mantle = new Mantle(new File(engine.getWorld().worldFolder(), "mantle"), engine.getTarget().getHeight());
radius = radCache.aquire(this::computeParallaxSize);
components = new KList<>();
registerComponent(new MantleCarvingComponent(this));
registerComponent(new MantleFluidBodyComponent(this));
jigsaw = new MantleJigsawComponent(this);
registerComponent(jigsaw);
object = new MantleObjectComponent(this);
registerComponent(object);
}
@Override
public void registerComponent(MantleComponent c) {
components.add(c);
}
@Override
public MantleJigsawComponent getJigsawComponent() {
return jigsaw;
}
@Override
public MantleObjectComponent getObjectComponent() {
return object;
}
private KList<IrisRegion> getAllRegions() {
KList<IrisRegion> r = new KList<>();
for(String i : getEngine().getDimension().getRegions()) {
r.add(getEngine().getData().getRegionLoader().load(i));
}
return r;
}
private KList<IrisBiome> getAllBiomes() {
KList<IrisBiome> r = new KList<>();
for(IrisRegion i : getAllRegions()) {
r.addAll(i.getAllBiomes(getEngine()));
}
return r;
}
private void warn(String ob, BlockVector bv) {
if(Math.max(bv.getBlockX(), bv.getBlockZ()) > 128) {
Iris.warn("Object " + ob + " has a large size (" + bv + ") and may increase memory usage!");
}
}
private void warnScaled(String ob, BlockVector bv, double ms) {
if(Math.max(bv.getBlockX(), bv.getBlockZ()) > 128) {
Iris.warn("Object " + ob + " has a large size (" + bv + ") and may increase memory usage! (Object scaled up to " + Form.pc(ms, 2) + ")");
}
}
private int computeParallaxSize() {
Iris.verbose("Calculating the Parallax Size in Parallel");
AtomicInteger xg = new AtomicInteger(0);
AtomicInteger zg = new AtomicInteger();
xg.set(0);
zg.set(0);
int jig = 0;
KSet<String> objects = new KSet<>();
KMap<IrisObjectScale, KList<String>> scalars = new KMap<>();
int x = xg.get();
int z = zg.get();
if(getEngine().getDimension().isUseMantle()) {
KList<IrisRegion> r = getAllRegions();
KList<IrisBiome> b = getAllBiomes();
for(IrisBiome i : b) {
for(IrisObjectPlacement j : i.getObjects()) {
if(j.getScale().canScaleBeyond()) {
scalars.put(j.getScale(), j.getPlace());
} else {
objects.addAll(j.getPlace());
}
}
for(IrisJigsawStructurePlacement j : i.getJigsawStructures()) {
jig = Math.max(jig, getData().getJigsawStructureLoader().load(j.getStructure()).getMaxDimension());
}
}
for(IrisRegion i : r) {
for(IrisObjectPlacement j : i.getObjects()) {
if(j.getScale().canScaleBeyond()) {
scalars.put(j.getScale(), j.getPlace());
} else {
objects.addAll(j.getPlace());
}
}
for(IrisJigsawStructurePlacement j : i.getJigsawStructures()) {
jig = Math.max(jig, getData().getJigsawStructureLoader().load(j.getStructure()).getMaxDimension());
}
}
for(IrisJigsawStructurePlacement j : getEngine().getDimension().getJigsawStructures()) {
jig = Math.max(jig, getData().getJigsawStructureLoader().load(j.getStructure()).getMaxDimension());
}
if(getEngine().getDimension().getStronghold() != null) {
try {
jig = Math.max(jig, getData().getJigsawStructureLoader().load(getEngine().getDimension().getStronghold()).getMaxDimension());
} catch(Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
}
Iris.verbose("Checking sizes for " + Form.f(objects.size()) + " referenced objects.");
BurstExecutor e = getEngine().getTarget().getBurster().burst(objects.size());
KMap<String, BlockVector> sizeCache = new KMap<>();
for(String i : objects) {
e.queue(() -> {
try {
BlockVector bv = sizeCache.computeIfAbsent(i, (k) -> {
try {
return IrisObject.sampleSize(getData().getObjectLoader().findFile(i));
} catch(IOException ex) {
Iris.reportError(ex);
ex.printStackTrace();
}
return null;
});
if(bv == null) {
throw new RuntimeException();
}
warn(i, bv);
synchronized(xg) {
xg.getAndSet(Math.max(bv.getBlockX(), xg.get()));
}
synchronized(zg) {
zg.getAndSet(Math.max(bv.getBlockZ(), zg.get()));
}
} catch(Throwable ed) {
Iris.reportError(ed);
}
});
}
for(Map.Entry<IrisObjectScale, KList<String>> entry : scalars.entrySet()) {
double ms = entry.getKey().getMaximumScale();
for(String j : entry.getValue()) {
e.queue(() -> {
try {
BlockVector bv = sizeCache.computeIfAbsent(j, (k) -> {
try {
return IrisObject.sampleSize(getData().getObjectLoader().findFile(j));
} catch(IOException ioException) {
Iris.reportError(ioException);
ioException.printStackTrace();
}
return null;
});
if(bv == null) {
throw new RuntimeException();
}
warnScaled(j, bv, ms);
synchronized(xg) {
xg.getAndSet((int) Math.max(Math.ceil(bv.getBlockX() * ms), xg.get()));
}
synchronized(zg) {
zg.getAndSet((int) Math.max(Math.ceil(bv.getBlockZ() * ms), zg.get()));
}
} catch(Throwable ee) {
Iris.reportError(ee);
}
});
}
}
e.complete();
x = xg.get();
z = zg.get();
for(IrisDepositGenerator i : getEngine().getDimension().getDeposits()) {
int max = i.getMaxDimension();
x = Math.max(max, x);
z = Math.max(max, z);
}
for(IrisRegion v : r) {
for(IrisDepositGenerator i : v.getDeposits()) {
int max = i.getMaxDimension();
x = Math.max(max, x);
z = Math.max(max, z);
}
}
for(IrisBiome v : b) {
for(IrisDepositGenerator i : v.getDeposits()) {
int max = i.getMaxDimension();
x = Math.max(max, x);
z = Math.max(max, z);
}
}
} else {
return 0;
}
x = Math.max(z, x);
int u = x;
int c = Math.max(computeCarvingRange(), computeBodyRange());
x = Math.max(jig, x);
x = Math.max(x, c);
x = (Math.max(x, 16) + 16) >> 4;
x = x % 2 == 0 ? x + 1 : x;
Iris.info("Mantle Size: " + x + " Chunks");
Iris.info(" Object Mantle Size: " + u + " (" + ((Math.max(u, 16) + 16) >> 4) + ")");
Iris.info(" Jigsaw Mantle Size: " + jig + " (" + ((Math.max(jig, 16) + 16) >> 4) + ")");
Iris.info(" Carving Mantle Size: " + c + " (" + ((Math.max(c, 16) + 16) >> 4) + ")");
return x;
}
private int computeBodyRange() {
int m = 0;
m = Math.max(m, getDimension().getFluidBodies().getMaxRange(getData()));
for(IrisRegion i : getDimension().getAllRegions(getEngine())) {
m = Math.max(m, i.getFluidBodies().getMaxRange(getData()));
}
for(IrisBiome i : getDimension().getAllBiomes(getEngine())) {
m = Math.max(m, i.getFluidBodies().getMaxRange(getData()));
}
return m;
}
private int computeCarvingRange() {
int m = 0;
m = Math.max(m, getDimension().getCarving().getMaxRange(getData()));
for(IrisRegion i : getDimension().getAllRegions(getEngine())) {
m = Math.max(m, i.getCarving().getMaxRange(getData()));
}
for(IrisBiome i : getDimension().getAllBiomes(getEngine())) {
m = Math.max(m, i.getCarving().getMaxRange(getData()));
}
return m;
}
}

Some files were not shown because too many files have changed in this diff Show More