mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-12-20 15:39:31 +00:00
Compare commits
27 Commits
old/v3.4.3
...
old/iris3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d6224db08 | ||
|
|
4f53b058fa | ||
|
|
fdca73405e | ||
|
|
003087ee94 | ||
|
|
0a72a1acfc | ||
|
|
e88519f474 | ||
|
|
6d8c92b512 | ||
|
|
efe800c606 | ||
|
|
1634454700 | ||
|
|
d31a9605d5 | ||
|
|
f061b5848a | ||
|
|
a4b47dee6c | ||
|
|
54331d8e76 | ||
|
|
1a7ba74517 | ||
|
|
6285651194 | ||
|
|
3339f77e1c | ||
|
|
8b124bf298 | ||
|
|
0a2e3e5e88 | ||
|
|
6873051bcb | ||
|
|
5e2438d6f6 | ||
|
|
9d4caa7be4 | ||
|
|
cbfad43467 | ||
|
|
cc70a30315 | ||
|
|
c209895389 | ||
|
|
1f9f7101e2 | ||
|
|
ed89e7c845 | ||
|
|
80dff702fc |
67
.github/ISSUE_TEMPLATE/bug.yml
vendored
67
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -1,67 +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
|
||||
- 1.19
|
||||
- 1.20
|
||||
- 1.21
|
||||
- 1.22
|
||||
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."
|
||||
46
.github/ISSUE_TEMPLATE/feature.yml
vendored
46
.github/ISSUE_TEMPLATE/feature.yml
vendored
@@ -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."
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,5 @@
|
||||
|
||||
build/
|
||||
libs/
|
||||
|
||||
.gradle/
|
||||
|
||||
@@ -10,4 +9,4 @@ libs/
|
||||
|
||||
collection/
|
||||
|
||||
/core/src/main/java/com/volmit/iris/util/uniques/
|
||||
src/main/java/com/volmit/iris/util/uniques/
|
||||
|
||||
518
LICENSE.md
518
LICENSE.md
@@ -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>.
|
||||
28
README.md
28
README.md
@@ -1,17 +1,18 @@
|
||||
# Iris
|
||||
# IrisBukkit
|
||||
|
||||
The master branch is for the latest version of minecraft.
|
||||
|
||||
# [Support](https://discord.gg/3xxPTpT) **|** [Documentation](https://docs.volmit.com/iris/) **|** [Git](https://github.com/IrisDimensions)
|
||||
# [Support](https://discord.gg/3xxPTpT) **|** [Documentation](https://docs.volmit.com/iris/) **
|
||||
|** [Git](https://github.com/IrisDimensions)
|
||||
|
||||
# Building
|
||||
|
||||
Building Iris is fairly simple, though you will need to setup a few things if your system has never been used for java
|
||||
Building IrisBukkit is fairly simple, though you will need to setup a few things if your system has never been used for
|
||||
java
|
||||
development.
|
||||
|
||||
Consider supporting our development by buying Iris on spigot! We work hard to make Iris the best it can be for everyone.
|
||||
|
||||
## Preface: if you need help compiling and you are a developer / intend to help out in the community or with development we would love to help you regardless in the discord! however do not come to the discord asking for free copies, or a tutorial on how to compile.
|
||||
Consider supporting our development by buying IrisBukkit on spigot! We work hard to make IrisBukkit the best it can be
|
||||
for everyone.
|
||||
|
||||
### Command Line Builds
|
||||
|
||||
@@ -30,17 +31,23 @@ Consider supporting our development by buying Iris on spigot! We work hard to ma
|
||||
3. Add `export JAVA_HOME=$(/usr/libexec/java_home)` as a new line
|
||||
4. Use `CTRL + X`, then Press `Y`, Then `ENTER`
|
||||
5. Quit & Reopen Terminal and verify with `echo $JAVA_HOME`. It should print a directory
|
||||
3. Once the project has setup, run `gradlew iris`
|
||||
4. The Iris jar will be placed in `Iris/build/Iris-XXX-XXX.jar` Enjoy! Consider supporting us by buying it on spigot!
|
||||
3. If this is your first time building IrisBukkit for MC 1.18+ run `gradlew setup` inside the root IrisBukkit project
|
||||
folder.
|
||||
Otherwise, skip this step. Grab a coffee, this may take up to 5 minutes depending on your cpu & internet connection.
|
||||
4. Once the project has setup, run `gradlew iris`
|
||||
5. The IrisBukkit jar will be placed in `IrisBukkit/build/IrisBukkit-XXX-XXX.jar` Enjoy! Consider supporting us by
|
||||
buying it on spigot!
|
||||
|
||||
### IDE Builds (for development)
|
||||
|
||||
* Run `gradlew setup` any time you get dependency issues with craftbukkit
|
||||
* Configure ITJ Gradle to use JDK 17 (in settings, search for gradle)
|
||||
* Add a build line in the build.gradle for your own build task to directly compile Iris into your plugins folder if you
|
||||
* Add a build line in the build.gradle for your own build task to directly compile IrisBukkit into your plugins folder
|
||||
if you
|
||||
prefer.
|
||||
* Resync the project & run your newly created task (under the development folder in gradle tasks!)
|
||||
|
||||
# Iris Toolbelt
|
||||
# IrisBukkit Toolbelt
|
||||
|
||||
Everyone needs a tool-belt.
|
||||
|
||||
@@ -66,6 +73,7 @@ IrisAccess access=IrisToolbelt.createWorld() // If you like builders...
|
||||
.name("myWorld") // The world name
|
||||
.dimension("terrifyinghands")
|
||||
.seed(69133742) // The world seed
|
||||
.headless(true) // Headless make gen go fast
|
||||
.pregen(PregenTask // Define a pregen job to run
|
||||
.builder()
|
||||
.center(new Position2(0,0)) // REGION coords (1 region = 32x32 chunks)
|
||||
|
||||
248
build.gradle
248
build.gradle
@@ -1,253 +1,41 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
buildscript() {
|
||||
repositories {
|
||||
maven { url 'https://jitpack.io'}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.github.VolmitSoftware:NMSTools:1.0.1'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'java-library'
|
||||
id "io.github.goooler.shadow" version "8.1.7"
|
||||
id "de.undercouch.download" version "5.0.1"
|
||||
id "io.freefair.lombok" version "6.3.0"
|
||||
}
|
||||
|
||||
version '3.4.3-1.19.2-1.21.1'
|
||||
group 'com.volmit.iris'
|
||||
version '1.0-SNAPSHOT'
|
||||
|
||||
// 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', 'C://Dan/MinecraftDevelopment/Server/plugins')
|
||||
registerCustomOutputTask('ArcaneArts', 'C://Users/arcane/Documents/development/server/plugins')
|
||||
registerCustomOutputTask('Coco', 'D://mcsm/plugins')
|
||||
registerCustomOutputTask('Strange', 'D://Servers/1.17 Test Server/plugins')
|
||||
registerCustomOutputTask('Vatuu', 'D://Minecraft/Servers/1.19.4/plugins')
|
||||
registerCustomOutputTask('CrazyDev22', 'C://Users/Julian/Desktop/server/plugins')
|
||||
registerCustomOutputTask('Pixel', 'D://Iris Dimension Engine/1.20.4 - Development/plugins')
|
||||
registerCustomOutputTask('PixelFury', 'C://Users/RePixelatedMC/Iris/1.21 - Development-v3/plugins')
|
||||
// ========================== UNIX ==============================
|
||||
registerCustomOutputTaskUnix('CyberpwnLT', '/Users/danielmills/development/server/plugins')
|
||||
registerCustomOutputTaskUnix('PsychoLT', '/Users/brianfopiano/Developer/RemoteGit/Server/plugins')
|
||||
registerCustomOutputTaskUnix('PixelMac', '/Users/test/Desktop/mcserver/plugins')
|
||||
registerCustomOutputTaskUnix('CrazyDev22LT', '/home/julian/Desktop/server/plugins')
|
||||
// ==============================================================
|
||||
|
||||
def NMS_BINDINGS = Map.of(
|
||||
"v1_21_R1", "1.21.1-R0.1-SNAPSHOT",
|
||||
"v1_20_R4", "1.20.6-R0.1-SNAPSHOT",
|
||||
"v1_20_R3", "1.20.4-R0.1-SNAPSHOT",
|
||||
"v1_20_R2", "1.20.2-R0.1-SNAPSHOT",
|
||||
"v1_20_R1", "1.20.1-R0.1-SNAPSHOT",
|
||||
"v1_19_R3", "1.19.4-R0.1-SNAPSHOT",
|
||||
"v1_19_R2", "1.19.3-R0.1-SNAPSHOT",
|
||||
"v1_19_R1", "1.19.2-R0.1-SNAPSHOT"
|
||||
)
|
||||
def JVM_VERSION = Map.of(
|
||||
"v1_21_R1", 21,
|
||||
"v1_20_R4", 21,
|
||||
)
|
||||
NMS_BINDINGS.each { nms ->
|
||||
project(":nms:${nms.key}") {
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'com.volmit.nmstools'
|
||||
|
||||
nmsTools {
|
||||
it.jvm = JVM_VERSION.getOrDefault(nms.key, 17)
|
||||
it.version = nms.value
|
||||
jar {
|
||||
manifest {
|
||||
attributes('Contains-Sources': 'java,class')
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(":core")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
NMS_BINDINGS.each {
|
||||
dependsOn(":nms:${it.key}:remap")
|
||||
from("${project(":nms:${it.key}").layout.buildDirectory.asFile.get()}/libs/${it.key}-mapped.jar")
|
||||
}
|
||||
|
||||
//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'
|
||||
archiveFileName.set("Iris-${project.version}.jar")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':core')
|
||||
}
|
||||
|
||||
configurations.configureEach {
|
||||
resolutionStrategy.cacheChangingModulesFor 60, 'minutes'
|
||||
resolutionStrategy.cacheDynamicVersionsFor 60, 'minutes'
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply plugin: 'java'
|
||||
|
||||
repositories {
|
||||
maven { url "https://arcanearts.jfrog.io/artifactory/archives" }
|
||||
mavenCentral()
|
||||
maven { url "https://repo.papermc.io/repository/maven-public/" }
|
||||
maven { url "https://repo.codemc.org/repository/maven-public" }
|
||||
maven { url "https://mvn.lumine.io/repository/maven-public/" }
|
||||
maven { url "https://jitpack.io" }
|
||||
|
||||
maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots" }
|
||||
maven { url "https://mvn.lumine.io/repository/maven/" }
|
||||
maven { url "https://repo.triumphteam.dev/snapshots" }
|
||||
maven { url "https://repo.mineinabyss.com/releases" }
|
||||
maven { url 'https://hub.jeff-media.com/nexus/repository/jeff-media-public/' }
|
||||
maven { url "https://repo.oraxen.com/releases" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Provided or Classpath
|
||||
compileOnly 'org.projectlombok:lombok:1.18.24'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.24'
|
||||
|
||||
// Shaded
|
||||
implementation 'com.dfsek:Paralithic:0.4.0'
|
||||
implementation 'io.papermc:paperlib:1.0.5'
|
||||
implementation "net.kyori:adventure-text-minimessage:4.17.0"
|
||||
implementation 'net.kyori:adventure-platform-bukkit:4.3.4'
|
||||
implementation 'net.kyori:adventure-api:4.17.0'
|
||||
//implementation 'org.bytedeco:javacpp:1.5.10'
|
||||
//implementation 'org.bytedeco:cuda-platform:12.3-8.9-1.5.10'
|
||||
compileOnly 'io.lumine:Mythic-Dist:5.2.1'
|
||||
compileOnly 'io.lumine:MythicCrucible-Dist:2.0.0'
|
||||
|
||||
// Dynamically Loaded
|
||||
compileOnly 'io.timeandspace:smoothie-map:2.0.2'
|
||||
compileOnly 'it.unimi.dsi:fastutil:8.5.8'
|
||||
compileOnly 'com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2'
|
||||
compileOnly 'org.zeroturnaround:zt-zip:1.14'
|
||||
compileOnly 'com.google.code.gson:gson:2.10.1'
|
||||
compileOnly 'org.ow2.asm:asm:9.2'
|
||||
compileOnly 'com.google.guava:guava:33.0.0-jre'
|
||||
compileOnly 'bsf:bsf:2.4.0'
|
||||
compileOnly 'rhino:js:1.7R2'
|
||||
compileOnly 'com.github.ben-manes.caffeine:caffeine:3.0.6'
|
||||
compileOnly 'org.apache.commons:commons-lang3:3.12.0'
|
||||
}
|
||||
|
||||
/**
|
||||
* We need parameter meta for the decree command system
|
||||
*/
|
||||
compileJava {
|
||||
options.compilerArgs << '-parameters'
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options.encoding = "UTF-8"
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||
archiveClassifier.set('sources')
|
||||
from sourceSets.main.allSource
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||
archiveClassifier.set('javadoc')
|
||||
from javadoc.destinationDir
|
||||
annotationProcessor 'systems.manifold:manifold-ext:2022.1.19'
|
||||
implementation 'art.arcane:Source:22.9.3'
|
||||
implementation 'art.arcane:Cram:22.9.3'
|
||||
implementation 'art.arcane:Amulet:22.9.5'
|
||||
implementation 'com.google.code.gson:gson:2.9.0'
|
||||
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.1'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
|
||||
testAnnotationProcessor 'systems.manifold:manifold-ext:2022.1.19'
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
dependencies {
|
||||
|
||||
}
|
||||
|
||||
task iris(type: Copy) {
|
||||
group "iris"
|
||||
from new File(layout.buildDirectory.asFile.get(), "libs/Iris-${version}.jar")
|
||||
into layout.buildDirectory.asFile.get()
|
||||
dependsOn(build)
|
||||
}
|
||||
|
||||
// with classifier: 'javadoc' and 'sources'
|
||||
task irisDev(type: Copy) {
|
||||
group "iris"
|
||||
from("core/build/libs/core-javadoc.jar", "core/build/libs/core-sources.jar")
|
||||
rename { String fileName ->
|
||||
fileName.replace("core", "Iris-${version}")
|
||||
}
|
||||
into layout.buildDirectory.asFile.get()
|
||||
dependsOn(iris)
|
||||
dependsOn("core:sourcesJar")
|
||||
dependsOn("core:javadocJar")
|
||||
}
|
||||
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.build.dependsOn(shadowJar)
|
||||
|
||||
290
bukkit/build.gradle
Normal file
290
bukkit/build.gradle
Normal file
@@ -0,0 +1,290 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
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"
|
||||
}
|
||||
|
||||
group rootProject.group
|
||||
version rootProject.version
|
||||
|
||||
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.platform.bukkit.IrisBukkit'
|
||||
|
||||
// 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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 'art.arcane', 'com.volmit.iris.util.arcane'
|
||||
relocate 'manifold', 'com.volmit.iris.util.manifold'
|
||||
relocate 'art.arcane.source', 'com.volmit.iris.util.source'
|
||||
relocate 'ChumBukkit.extensions', 'com.volmit.iris.util.extensions'
|
||||
relocate 'IrisBukkit.extensions', 'com.volmit.iris.util.extensions'
|
||||
relocate 'Fukkit.extensions', 'com.volmit.iris.util.extensions'
|
||||
relocate 'Amulet.extensions', 'com.volmit.iris.util.extensions'
|
||||
relocate 'Iris.extensions', 'com.volmit.iris.util.extensions'
|
||||
dependencies {
|
||||
include(dependency('art.arcane:'))
|
||||
include(dependency('systems.manifold:'))
|
||||
include(dependency("com.dfsek:Paralithic:"))
|
||||
include(dependency(":engine"))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Faster dependency caches
|
||||
*/
|
||||
configurations.all {
|
||||
resolutionStrategy.cacheChangingModulesFor 60, 'minutes'
|
||||
resolutionStrategy.cacheDynamicVersionsFor 60, 'minutes'
|
||||
}
|
||||
|
||||
configurations {
|
||||
testImplementation.extendsFrom annotationProcessor
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(17)
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url "https://arcanearts.jfrog.io/artifactory/archives" }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.spigotmc:spigot-api:1.19-R0.1-SNAPSHOT'
|
||||
implementation 'art.arcane:Fukkit:22.9.2'
|
||||
implementation project(":engine")
|
||||
}
|
||||
|
||||
if (JavaVersion.current() != JavaVersion.VERSION_1_8 &&
|
||||
sourceSets.main.allJava.files.any { it.name == "module-info.java" }) {
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs += ['-Xplugin:Manifold', '--module-path', it.classpath.asPath]
|
||||
}
|
||||
} else {
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs += ['-Xplugin:Manifold']
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
System.out.println(buildDir);
|
||||
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/bukkit-" + version + "-all.jar");
|
||||
def ssiJar = new File(buildDir, "specialsource/bukkit-" + 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
package com.volmit.iris.platform.bukkit;
|
||||
|
||||
import art.arcane.amulet.io.IO;
|
||||
import art.arcane.amulet.logging.LogListener;
|
||||
import com.volmit.iris.engine.EngineConfiguration;
|
||||
import com.volmit.iris.platform.IrisPlatform;
|
||||
import com.volmit.iris.platform.PlatformBiome;
|
||||
import com.volmit.iris.platform.block.PlatformBlock;
|
||||
import com.volmit.iris.platform.PlatformNamespaceKey;
|
||||
import com.volmit.iris.platform.PlatformWorld;
|
||||
import com.volmit.iris.platform.bukkit.wrapper.BukkitBiome;
|
||||
import com.volmit.iris.platform.bukkit.wrapper.BukkitBlock;
|
||||
import com.volmit.iris.platform.bukkit.wrapper.BukkitKey;
|
||||
import com.volmit.iris.platform.bukkit.wrapper.BukkitWorld;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Warning;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class IrisBukkit extends JavaPlugin implements IrisPlatform, LogListener {
|
||||
private static final String TAG = ChatColor.DARK_GRAY + "[" + ChatColor.GREEN + "Iris" + ChatColor.DARK_GREEN + "/";
|
||||
private static final String TAG_STRIPPED = ChatColor.stripColor(TAG);
|
||||
private static IrisBukkit instance;
|
||||
private ConsoleCommandSender consoleSender;
|
||||
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
consoleSender = Bukkit.getConsoleSender();
|
||||
LogListener.listener.set(this);
|
||||
|
||||
getServer().getScheduler().scheduleSyncDelayedTask(this, () -> {
|
||||
World world = Bukkit.createWorld(new WorldCreator("iristests/" + UUID.randomUUID()).generator(new IrisBukkitChunkGenerator(this, EngineConfiguration.builder()
|
||||
.timings(true).mutable(true)
|
||||
.build())));
|
||||
for(Player i : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
i.teleport(world.getSpawnLocation());
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
|
||||
public void onDisable() {
|
||||
World w = null;
|
||||
for(World i : Bukkit.getWorlds()) {
|
||||
if(!i.getName().startsWith("iristest")) {
|
||||
w = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(World i : Bukkit.getWorlds()) {
|
||||
if(i.getName().startsWith("iristest"))
|
||||
{
|
||||
for(Player j : i.getPlayers())
|
||||
{
|
||||
j.teleport(w.getSpawnLocation());
|
||||
}
|
||||
|
||||
if(i.getGenerator() instanceof Closeable c)
|
||||
{
|
||||
try {
|
||||
c.close();
|
||||
} catch(IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
BukkitWorld.of(i).unloadChunks(false, true);
|
||||
File folder = i.getWorldFolder();
|
||||
Bukkit.unloadWorld(i, false);
|
||||
IO.delete(folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IrisBukkit getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void messageConsole(String color, String key, Object o) {
|
||||
try {
|
||||
consoleSender.sendMessage(TAG + key + ChatColor.DARK_GRAY + "]: " + color + o.toString());
|
||||
}
|
||||
|
||||
catch(Throwable e) {
|
||||
System.out.println(TAG_STRIPPED + key + "]: " + o.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logError(String k, Object o) {
|
||||
messageConsole(ChatColor.RED.toString(), k, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logInfo(String k, Object o) {
|
||||
messageConsole(ChatColor.WHITE.toString(), k, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logWarning(String k, Object o) {
|
||||
messageConsole(ChatColor.YELLOW.toString(), k, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logDebug(String k, Object o) {
|
||||
messageConsole(ChatColor.GRAY.toString(), k, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformName() {
|
||||
return "Bukkit";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<PlatformBlock> getBlocks() {
|
||||
//This is because it's a method extension
|
||||
//noinspection Convert2MethodRef
|
||||
return Arrays.stream(Material.values())
|
||||
.filter(i -> !i.isLegacy())
|
||||
.filter(Material::isBlock)
|
||||
.map(Material::createBlockData).map(i -> BukkitBlock.of(i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<PlatformBiome> getBiomes() {
|
||||
//This is because it's a method extension
|
||||
//noinspection Convert2MethodRef
|
||||
return Arrays.stream(Biome.values()).parallel().filter((i) -> i != Biome.CUSTOM).map(i -> BukkitBiome.of(i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWorldLoaded(String name) {
|
||||
return Bukkit.getWorlds().keepWhere(i -> i.getName().equals(name)).isNotEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformWorld getWorld(String name) {
|
||||
World w = Bukkit.getWorld(name);
|
||||
|
||||
if(w == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return BukkitWorld.of(w);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformBlock parseBlock(String raw) {
|
||||
return BukkitBlock.of(Bukkit.createBlockData(raw));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformNamespaceKey key(String namespace, String key) {
|
||||
return BukkitKey.of(namespace, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getStudioFolder(String dimension) {
|
||||
File f = new File(getDataFolder(), "packs/" + dimension);
|
||||
f.mkdirs();
|
||||
return f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getStudioFolder() {
|
||||
File f = new File(getDataFolder(), "packs/");
|
||||
f.mkdirs();
|
||||
return f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
|
||||
return new IrisBukkitChunkGenerator(this, EngineConfiguration.builder()
|
||||
.threads(4)
|
||||
.mutable(true)
|
||||
.timings(true)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void i(String s, Object o) {
|
||||
logInfo(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void f(String s, Object o) {
|
||||
logError(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void w(String s, Object o) {
|
||||
logWarning(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void d(String s, Object o) {
|
||||
logDebug(s, o);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package com.volmit.iris.platform.bukkit;
|
||||
|
||||
import art.arcane.chrono.Average;
|
||||
import art.arcane.chrono.PrecisionStopwatch;
|
||||
import art.arcane.spatial.hunk.Hunk;
|
||||
import com.volmit.iris.engine.EngineConfiguration;
|
||||
import com.volmit.iris.engine.Engine;
|
||||
import com.volmit.iris.engine.feature.FeatureSizedTarget;
|
||||
import com.volmit.iris.engine.feature.FeatureTarget;
|
||||
import com.volmit.iris.engine.pipeline.PipedHunkStack;
|
||||
import com.volmit.iris.platform.IrisPlatform;
|
||||
import com.volmit.iris.platform.block.PlatformBlock;
|
||||
import com.volmit.iris.platform.bukkit.util.StaticBiomeProvider;
|
||||
import com.volmit.iris.platform.bukkit.wrapper.BukkitWorld;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.generator.BiomeProvider;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import com.volmit.iris.platform.bukkit.util.ChunkDataHunkView;
|
||||
import org.bukkit.generator.WorldInfo;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class IrisBukkitChunkGenerator extends ChunkGenerator implements Closeable {
|
||||
private final IrisPlatform platform;
|
||||
private final EngineConfiguration configuration;
|
||||
private final AtomicReference<Engine> engine;
|
||||
private final ReentrantLock engineLock;
|
||||
private final AtomicInteger perSecond;
|
||||
private final PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||
private final Average a = new Average(128);
|
||||
private final StaticBiomeProvider staticBiomeProvider;
|
||||
|
||||
public IrisBukkitChunkGenerator(IrisPlatform platform, EngineConfiguration configuration) {
|
||||
this.perSecond = new AtomicInteger(0);
|
||||
this.platform = platform;
|
||||
this.configuration = configuration;
|
||||
this.staticBiomeProvider = new StaticBiomeProvider(Biome.PLAINS);
|
||||
this.engine = new AtomicReference<>();
|
||||
this.engineLock = new ReentrantLock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkData generateChunkData(World world, Random random, int x, int z, BiomeGrid biome) {
|
||||
PrecisionStopwatch pp = PrecisionStopwatch.start();
|
||||
initEngine(world);
|
||||
ChunkData data = Bukkit.createChunkData(world);
|
||||
Hunk<PlatformBlock> chunk = new ChunkDataHunkView(data);
|
||||
FeatureSizedTarget targetSize = FeatureSizedTarget.builder()
|
||||
.width(chunk.getWidth())
|
||||
.height(chunk.getHeight())
|
||||
.depth(chunk.getDepth())
|
||||
.offsetX(x << 4)
|
||||
.offsetZ(z << 4)
|
||||
.offsetY(0)
|
||||
.build();
|
||||
FeatureTarget<PlatformBlock> blockTarget = new FeatureTarget<>(chunk, targetSize);
|
||||
PipedHunkStack stack = new PipedHunkStack();
|
||||
stack.register(PlatformBlock.class, blockTarget);
|
||||
engine.get().getPlumbing().generate(engine.get(), targetSize, stack);
|
||||
perSecond.incrementAndGet();
|
||||
a.put(pp.getMilliseconds());
|
||||
|
||||
if(p.getMilliseconds() > 1000)
|
||||
{
|
||||
p.reset();
|
||||
p.begin();
|
||||
System.out.println("PERSECOND: " + perSecond.getAndSet(0) + " AMS: " + ((int)Math.round(a.getAverage())) + "ms");
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private void initEngine(World world) {
|
||||
if(engine.get() == null)
|
||||
{
|
||||
engineLock.lock();
|
||||
|
||||
if(engine.get() == null)
|
||||
{
|
||||
try {
|
||||
engine.set(new Engine(platform, BukkitWorld.of(world), configuration));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
engineLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSpawn(World world, int x, int z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeProvider getDefaultBiomeProvider(WorldInfo worldInfo) {
|
||||
return staticBiomeProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
engine.get().close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateNoise() {
|
||||
return super.shouldGenerateNoise();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateSurface() {
|
||||
return super.shouldGenerateSurface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateBedrock() {
|
||||
return super.shouldGenerateBedrock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateCaves() {
|
||||
return super.shouldGenerateCaves();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateDecorations() {
|
||||
return super.shouldGenerateDecorations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateMobs() {
|
||||
return super.shouldGenerateMobs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateStructures() {
|
||||
return super.shouldGenerateStructures();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.volmit.iris.platform.bukkit.util;
|
||||
|
||||
import art.arcane.spatial.hunk.Hunk;
|
||||
import com.volmit.iris.platform.block.PlatformBlock;
|
||||
import com.volmit.iris.platform.bukkit.wrapper.BukkitBlock;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
|
||||
@SuppressWarnings("ClassCanBeRecord")
|
||||
public class ChunkDataHunkView implements Hunk<PlatformBlock> {
|
||||
private final ChunkGenerator.ChunkData chunk;
|
||||
|
||||
public ChunkDataHunkView(ChunkGenerator.ChunkData chunk) {
|
||||
this.chunk = chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDepth() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return chunk.getMaxHeight() - chunk.getMinHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void set(int x1, int y1, int z1, int x2, int y2, int z2, PlatformBlock t) {
|
||||
if(t == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
chunk.setRegion(x1, y1 + chunk.getMinHeight(), z1, x2, y2 + chunk.getMinHeight(), z2, ((BukkitBlock)t).getDelegate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setRaw(int x, int y, int z, PlatformBlock t) {
|
||||
if(t == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
chunk.setBlock(x, y + chunk.getMinHeight(), z, ((BukkitBlock)t).getDelegate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformBlock getRaw(int x, int y, int z) {
|
||||
return BukkitBlock.of(chunk.getBlockData(x, y + chunk.getMinHeight(), z));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.volmit.iris.platform.bukkit.util;
|
||||
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.generator.BiomeProvider;
|
||||
import org.bukkit.generator.WorldInfo;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class StaticBiomeProvider extends BiomeProvider {
|
||||
private static final List<Biome> ALL_BIOMES = Arrays.stream(Biome.values()).without((i) -> i.equals(Biome.CUSTOM)).toList().unmodifiable();
|
||||
private final Biome defaultBiome;
|
||||
|
||||
public StaticBiomeProvider(Biome defaultBiome) {
|
||||
this.defaultBiome = defaultBiome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(WorldInfo worldInfo, int x, int y, int z) {
|
||||
return defaultBiome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Biome> getBiomes(WorldInfo worldInfo) {
|
||||
return ALL_BIOMES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.volmit.iris.platform.bukkit.wrapper;
|
||||
|
||||
import com.volmit.iris.platform.PlatformBiome;
|
||||
import com.volmit.iris.platform.PlatformNamespaceKey;
|
||||
import lombok.Data;
|
||||
import org.bukkit.block.Biome;
|
||||
|
||||
@Data
|
||||
public class BukkitBiome implements PlatformBiome {
|
||||
private final Biome delegate;
|
||||
|
||||
private BukkitBiome(Biome delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformNamespaceKey getKey() {
|
||||
return BukkitKey.of(delegate.getKey());
|
||||
}
|
||||
|
||||
public static BukkitBiome of(Biome biome) {
|
||||
return new BukkitBiome(biome);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.volmit.iris.platform.bukkit.wrapper;
|
||||
|
||||
import com.volmit.iris.platform.block.PlatformBlock;
|
||||
import com.volmit.iris.platform.PlatformNamespaceKey;
|
||||
import com.volmit.iris.platform.block.PlatformBlock;
|
||||
import lombok.Data;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.Ageable;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class BukkitBlock implements PlatformBlock {
|
||||
private final BlockData delegate;
|
||||
private final Map<String, String> properties;
|
||||
|
||||
private BukkitBlock(BlockData delegate, Map<String, String> properties) {
|
||||
this.delegate = delegate;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
private BukkitBlock(BlockData delegate) {
|
||||
this.delegate = delegate;
|
||||
String s = delegate.getAsString(true);
|
||||
|
||||
if(s.contains("[")) {
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
String[] props = new String[] {s.split("\\Q[\\E")[1].split("\\Q]\\E")[0]};
|
||||
String[] p;
|
||||
if(props[0].contains(",")) {
|
||||
for(String i : props[0].split("\\Q,\\E")) {
|
||||
p = i.split("\\Q=\\E");
|
||||
properties.put(p[0], p[1]);
|
||||
}
|
||||
} else {
|
||||
p = props[0].split("\\Q=\\E");
|
||||
properties.put(p[0], p[1]);
|
||||
}
|
||||
|
||||
this.properties = Collections.unmodifiableMap(properties);
|
||||
} else {
|
||||
this.properties = Map.of();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getProperties() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformNamespaceKey getKey() {
|
||||
return BukkitKey.of(delegate.getMaterial().getKey());
|
||||
}
|
||||
|
||||
public static BukkitBlock of(BlockData blockData) {
|
||||
return new BukkitBlock(blockData);
|
||||
}
|
||||
|
||||
public static BukkitBlock of(Material material) {
|
||||
return of(material.createBlockData());
|
||||
}
|
||||
|
||||
public static BukkitBlock of(String raw) {
|
||||
return of(Bukkit.createBlockData(raw));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.volmit.iris.platform.bukkit.wrapper;
|
||||
|
||||
import com.volmit.iris.platform.PlatformChunk;
|
||||
import org.bukkit.Chunk;
|
||||
|
||||
public class BukkitChunk implements PlatformChunk {
|
||||
private final Chunk delegate;
|
||||
|
||||
private BukkitChunk(Chunk delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return delegate.getX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
return delegate.getZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload(boolean save, boolean force) {
|
||||
if(force) {
|
||||
delegate.getPluginChunkTickets().forEach(delegate::removePluginChunkTicket);
|
||||
}
|
||||
|
||||
delegate.unload(save);
|
||||
}
|
||||
|
||||
public static BukkitChunk of(Chunk chunk) {
|
||||
return new BukkitChunk(chunk);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.volmit.iris.platform.bukkit.wrapper;
|
||||
|
||||
import com.volmit.iris.platform.PlatformNamespaceKey;
|
||||
import lombok.Data;
|
||||
import org.bukkit.NamespacedKey;
|
||||
|
||||
@Data
|
||||
public class BukkitKey implements PlatformNamespaceKey {
|
||||
private final NamespacedKey delegate;
|
||||
|
||||
private BukkitKey(NamespacedKey delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return delegate.getNamespace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return delegate.getKey();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
public static BukkitKey of(String nsk) {
|
||||
if(nsk.contains(":")) {
|
||||
String[] f = nsk.split("\\Q:\\E");
|
||||
return of(f[0], f[1]);
|
||||
}
|
||||
|
||||
return of("minecraft", nsk);
|
||||
}
|
||||
|
||||
public static BukkitKey of(String namespace, String key) {
|
||||
return of(new NamespacedKey(namespace, key));
|
||||
}
|
||||
|
||||
public static BukkitKey of(NamespacedKey key) {
|
||||
return new BukkitKey(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.volmit.iris.platform.bukkit.wrapper;
|
||||
|
||||
import art.arcane.amulet.geometry.Vec;
|
||||
import com.volmit.iris.platform.PlatformPlayer;
|
||||
import com.volmit.iris.platform.PlatformWorld;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitPlayer implements PlatformPlayer {
|
||||
private final Player delegate;
|
||||
|
||||
private BukkitPlayer(Player delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID() {
|
||||
return delegate.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return delegate.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec getLocation() {
|
||||
return delegate.getLocation().vec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformWorld getWorld() {
|
||||
return BukkitWorld.of(delegate.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseIris() {
|
||||
return delegate.isOp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
delegate.sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActionBar(String message) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitleMessage(String title, String subtitle, int in, int stay, int out) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static BukkitPlayer of(Player player) {
|
||||
return new BukkitPlayer(player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.volmit.iris.platform.bukkit.wrapper;
|
||||
|
||||
import com.volmit.iris.platform.PlatformBiome;
|
||||
import com.volmit.iris.platform.block.PlatformBlock;
|
||||
import com.volmit.iris.platform.PlatformChunk;
|
||||
import com.volmit.iris.platform.PlatformPlayer;
|
||||
import com.volmit.iris.platform.PlatformWorld;
|
||||
import com.volmit.iris.util.WorldHeight;
|
||||
import lombok.Data;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Data
|
||||
public class BukkitWorld implements PlatformWorld {
|
||||
private final World delegate;
|
||||
private final WorldHeight worldHeight;
|
||||
|
||||
private BukkitWorld(World delegate) {
|
||||
this.delegate = delegate;
|
||||
this.worldHeight = new WorldHeight(delegate.getMinHeight(), delegate.getMaxHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldHeight getHeight() {
|
||||
return worldHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return delegate.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getFolder() {
|
||||
return delegate.getWorldFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<PlatformPlayer> getPlayers() {
|
||||
//noinspection Convert2MethodRef
|
||||
return delegate.getPlayers().stream().map(i -> BukkitPlayer.of(i)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<PlatformChunk> getLoadedChunks() {
|
||||
//noinspection Convert2MethodRef
|
||||
return Arrays.stream(delegate.getLoadedChunks()).map(i -> BukkitChunk.of(i)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformChunk getOrLoadChunk(int x, int z) {
|
||||
return BukkitChunk.of(delegate.getChunkAt(x, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformBlock getBlock(int x, int y, int z) {
|
||||
return BukkitBlock.of(delegate.getBlockAt(x, y, z).getBlockData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformBiome getBiome(int x, int y, int z) {
|
||||
return BukkitBiome.of(delegate.getBiome(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSeed() {
|
||||
return delegate.getSeed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkLoaded(int x, int z) {
|
||||
return delegate.isChunkLoaded(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, PlatformBlock block) {
|
||||
delegate.setBlockData(x, y, z, ((BukkitBlock) block).getDelegate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int y, int z, PlatformBiome biome) {
|
||||
delegate.setBiome(x, y, z, ((BukkitBiome) biome).getDelegate());
|
||||
}
|
||||
|
||||
public static BukkitWorld of(World world) {
|
||||
return new BukkitWorld(world);
|
||||
}
|
||||
}
|
||||
8
bukkit/src/main/resources/plugin.yml
Normal file
8
bukkit/src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
name: Iris
|
||||
main: com.volmit.iris.platform.bukkit.IrisBukkit
|
||||
version: 1.0.0
|
||||
api-version: 1.19
|
||||
libraries:
|
||||
- org.apache-extras.beanshell:bsh:2.0b6
|
||||
- com.google.code.gson:gson:2.8.9
|
||||
- com.github.ben-manes.caffeine:caffeine:3.1.1
|
||||
@@ -1,92 +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 "8.6"
|
||||
}
|
||||
|
||||
def apiVersion = '1.19'
|
||||
def main = 'com.volmit.iris.Iris'
|
||||
|
||||
/**
|
||||
* We need parameter meta for the decree command system
|
||||
*/
|
||||
compileJava {
|
||||
options.compilerArgs << '-parameters'
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url 'https://nexus.phoenixdevt.fr/repository/maven-public/'}
|
||||
maven { url 'https://repo.auxilor.io/repository/maven-public/' }
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT'
|
||||
compileOnly 'org.apache.logging.log4j:log4j-api:2.19.0'
|
||||
compileOnly 'org.apache.logging.log4j:log4j-core:2.19.0'
|
||||
compileOnly 'commons-io:commons-io:2.14.0'
|
||||
compileOnly 'commons-lang:commons-lang:2.6'
|
||||
compileOnly 'com.github.oshi:oshi-core:5.8.5'
|
||||
compileOnly 'org.lz4:lz4-java:1.8.0'
|
||||
|
||||
// Third Party Integrations
|
||||
compileOnly 'com.ticxo.playeranimator:PlayerAnimator:R1.2.7'
|
||||
compileOnly 'io.th0rgal:oraxen:1.173.0'
|
||||
compileOnly 'com.github.LoneDev6:api-itemsadder:3.4.1-r4'
|
||||
compileOnly 'com.github.PlaceholderAPI:placeholderapi:2.11.3'
|
||||
compileOnly 'com.github.Ssomar-Developement:SCore:4.23.10.8'
|
||||
compileOnly 'net.Indyuce:MMOItems-API:6.9.5-SNAPSHOT'
|
||||
compileOnly 'com.willfp:EcoItems:5.44.0'
|
||||
//implementation files('libs/CustomItems.jar')
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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': rootProject.name.toString(),
|
||||
'version': rootProject.version.toString(),
|
||||
'main': main.toString(),
|
||||
'apiversion': apiVersion.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,904 +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.IrisPapiExpansion;
|
||||
import com.volmit.iris.core.link.MultiverseCoreLink;
|
||||
import com.volmit.iris.core.link.MythicMobsLink;
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.core.nms.INMS;
|
||||
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
||||
import com.volmit.iris.core.pregenerator.LazyPregenerator;
|
||||
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.core.safeguard.IrisSafeguard;
|
||||
import com.volmit.iris.core.safeguard.UtilsSFG;
|
||||
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.FileWatcher;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.io.InstanceState;
|
||||
import com.volmit.iris.util.io.JarScanner;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.misc.getHardware;
|
||||
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 lombok.Getter;
|
||||
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.WorldCreator;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
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.lang.management.ManagementFactory;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
|
||||
import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware;
|
||||
import static com.volmit.iris.util.misc.getHardware.getCPUModel;
|
||||
|
||||
@SuppressWarnings("CanBeFinal")
|
||||
public class Iris extends VolmitPlugin implements Listener {
|
||||
public static final String OVERWORLD_TAG = "3800";
|
||||
|
||||
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() {
|
||||
if (sender == null) {
|
||||
sender = new VolmitSender(Bukkit.getConsoleSender());
|
||||
sender.setTag(instance.getTag());
|
||||
}
|
||||
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 {
|
||||
getSender().sendMessage(string);
|
||||
} catch (Throwable e) {
|
||||
try {
|
||||
instance.getLogger().info(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 format, Object... args) {
|
||||
msg(C.WHITE + String.format(format, args));
|
||||
}
|
||||
public static void safeguard(String format, Object... args) {
|
||||
msg(C.RESET + String.format(format, args));
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
public 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 String getJava() {
|
||||
String javaRuntimeName = System.getProperty("java.vm.name");
|
||||
String javaRuntimeVendor = System.getProperty("java.vendor");
|
||||
String javaRuntimeVersion = System.getProperty("java.vm.version");
|
||||
return String.format("%s %s (build %s)", javaRuntimeName, javaRuntimeVendor, javaRuntimeVersion);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
Iris.info("DUMPED! See " + fi.getAbsolutePath());
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void panic() {
|
||||
EnginePanic.panic();
|
||||
}
|
||||
|
||||
public static void addPanic(String s, String v) {
|
||||
EnginePanic.add(s, v);
|
||||
}
|
||||
|
||||
private static void fixShading() {
|
||||
ShadeFix.fix(ComponentSerializer.class);
|
||||
}
|
||||
private void enable() {
|
||||
instance = this;
|
||||
services = new KMap<>();
|
||||
setupAudience();
|
||||
initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class<? extends IrisService>) i.getClass(), (IrisService) i));
|
||||
INMS.get();
|
||||
IO.delete(new File("iris"));
|
||||
IrisSafeguard.IrisSafeguardSystem();
|
||||
getSender().setTag(getTag());
|
||||
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(LazyPregenerator::loadLazyGenerators, 100);
|
||||
J.a(this::bstats);
|
||||
J.ar(this::checkConfigHotload, 60);
|
||||
J.sr(this::tickQueue, 0);
|
||||
J.s(this::setupPapi);
|
||||
J.a(ServerConfigurator::configure, 20);
|
||||
splash();
|
||||
UtilsSFG.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"));
|
||||
ConfigurationSection section = fc.getConfigurationSection("worlds");
|
||||
if (section == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String s : section.getKeys(false)) {
|
||||
ConfigurationSection entry = section.getConfigurationSection(s);
|
||||
if (!entry.contains("generator", true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String generator = entry.getString("generator");
|
||||
if (generator.startsWith("Iris:")) {
|
||||
generator = generator.split("\\Q:\\E")[1];
|
||||
} else if (generator.equalsIgnoreCase("Iris")) {
|
||||
generator = IrisSettings.get().getGenerator().getDefaultWorldType();
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
Iris.info("2 World: %s | Generator: %s", s, generator);
|
||||
|
||||
if (Bukkit.getWorlds().stream().anyMatch(w -> w.getName().equals(s))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
|
||||
new WorldCreator(s)
|
||||
.generator(getDefaultWorldGenerator(s, generator))
|
||||
.environment(IrisData.loadAnyDimension(generator).getEnvironment())
|
||||
.createWorld();
|
||||
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
|
||||
}
|
||||
} 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) : getSender(), 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 void postShutdown(Runnable r) {
|
||||
postShutdown.add(r);
|
||||
}
|
||||
|
||||
public void onEnable() {
|
||||
enable();
|
||||
super.onEnable();
|
||||
Bukkit.getPluginManager().registerEvents(this, this);
|
||||
setupChecks();
|
||||
}
|
||||
|
||||
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 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) {
|
||||
if (unstablemode) {
|
||||
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.RED + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
|
||||
}
|
||||
if (warningmode) {
|
||||
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.GOLD + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
|
||||
}
|
||||
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.IRIS + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
|
||||
|
||||
}
|
||||
|
||||
private boolean setupChecks() {
|
||||
boolean passed = true;
|
||||
Iris.info("Version Information: " + instance.getServer().getVersion() + " | " + instance.getServer().getBukkitVersion());
|
||||
if (INMS.get() instanceof NMSBinding1X) {
|
||||
passed = false;
|
||||
Iris.warn("============================================");
|
||||
Iris.warn("=");
|
||||
Iris.warn("=");
|
||||
Iris.warn("=");
|
||||
Iris.warn("Iris is not compatible with this version of Minecraft.");
|
||||
Iris.warn("=");
|
||||
Iris.warn("=");
|
||||
Iris.warn("=");
|
||||
Iris.warn("============================================");
|
||||
}
|
||||
if (!instance.getServer().getVersion().contains("Purpur")) {
|
||||
passed = false;
|
||||
Iris.info("We recommend using Purpur for the best experience with Iris.");
|
||||
Iris.info("Purpur is a fork of Paper that is optimized for performance and stability.");
|
||||
Iris.info("Plugins that work on Spigot / Paper work on Purpur.");
|
||||
Iris.info("You can download it here: https://purpurmc.org");
|
||||
}
|
||||
return passed;
|
||||
}
|
||||
|
||||
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(Bukkit.getWorldContainer(), 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(getSender(), dim.getLoadKey(), w.worldFolder());
|
||||
}
|
||||
|
||||
return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey(), false);
|
||||
}
|
||||
|
||||
public void splash() {
|
||||
if (!IrisSettings.get().getGeneral().isSplashLogoStartup()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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()};
|
||||
if (unstablemode) {
|
||||
info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + getDescription().getVersion()};
|
||||
}
|
||||
if (warningmode) {
|
||||
info = new String[]{"", "", "", "", "", padd2 + C.GOLD + " Iris", padd2 + C.GRAY + " by " + C.GOLD + "Volmit Software", padd2 + C.GRAY + " v" + C.GOLD + getDescription().getVersion()};
|
||||
}
|
||||
|
||||
String[] splashstable = {
|
||||
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 + "@@@@@@@@@@@@@@"
|
||||
};
|
||||
|
||||
String[] splashunstable = {
|
||||
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
|
||||
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.RED + " .(((()))). ",
|
||||
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.RED + " .((((((())))))). ",
|
||||
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.RED + " ((((((((())))))))) " + C.GRAY + " @",
|
||||
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.RED + " ((((((((-))))))))) " + C.GRAY + " @@",
|
||||
padd + C.GRAY + "@@@&&" + C.RED + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
|
||||
padd + C.GRAY + "@@" + C.RED + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
|
||||
padd + C.GRAY + "@" + C.RED + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
|
||||
padd + C.GRAY + "" + C.RED + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
|
||||
padd + C.GRAY + "" + C.RED + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
|
||||
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
|
||||
};
|
||||
String[] splashwarning = {
|
||||
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
|
||||
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.GOLD + " .(((()))). ",
|
||||
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.GOLD + " .((((((())))))). ",
|
||||
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.GOLD + " ((((((((())))))))) " + C.GRAY + " @",
|
||||
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.GOLD + " ((((((((-))))))))) " + C.GRAY + " @@",
|
||||
padd + C.GRAY + "@@@&&" + C.GOLD + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
|
||||
padd + C.GRAY + "@@" + C.GOLD + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
|
||||
padd + C.GRAY + "@" + C.GOLD + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
|
||||
padd + C.GRAY + "" + C.GOLD + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
|
||||
padd + C.GRAY + "" + C.GOLD + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
|
||||
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
|
||||
};
|
||||
String[] splash;
|
||||
File freeSpace = new File(Bukkit.getWorldContainer() + ".");
|
||||
if (unstablemode) {
|
||||
splash = splashunstable;
|
||||
} else if (warningmode) {
|
||||
splash = splashwarning;
|
||||
} else {
|
||||
splash = splashstable;
|
||||
}
|
||||
|
||||
if (!passedserversoftware) {
|
||||
Iris.info("Server type & version: " + C.RED + Bukkit.getVersion());
|
||||
} else { Iris.info("Server type & version: " + Bukkit.getVersion()); }
|
||||
Iris.info("Java: " + getJava());
|
||||
try {
|
||||
if (getCPUModel().contains("Intel")) {
|
||||
Iris.info("Server Cpu: " + C.BLUE + getCPUModel());
|
||||
}
|
||||
if (getCPUModel().contains("Ryzen")) {
|
||||
Iris.info("Server Cpu: " + C.RED + getCPUModel());
|
||||
}
|
||||
if (!getCPUModel().contains("Ryzen") && !getCPUModel().contains("Intel")) {
|
||||
Iris.info("Server Cpu: " + C.GRAY + getCPUModel());
|
||||
}
|
||||
|
||||
} catch (Exception e){
|
||||
Iris.info("Server Cpu: " + C.DARK_RED + "Failed");
|
||||
}
|
||||
|
||||
Iris.info("Threads: " + C.GRAY + Runtime.getRuntime().availableProcessors());
|
||||
if (!instance.getServer().getVersion().contains("Purpur")) {
|
||||
if (instance.getServer().getVersion().contains("Spigot") && instance.getServer().getVersion().contains("Bukkit")) {
|
||||
Iris.info(C.RED + " Iris requires paper or above to function properly..");
|
||||
} else {
|
||||
Iris.info(C.YELLOW + "Purpur is recommended to use with iris.");
|
||||
}
|
||||
}
|
||||
if (getHardware.getProcessMemory() < 5999) {
|
||||
Iris.warn("6GB+ Ram is recommended");
|
||||
Iris.warn("Process Memory: " + getHardware.getProcessMemory() + " MB");
|
||||
}
|
||||
Iris.info("Bukkit distro: " + Bukkit.getName());
|
||||
Iris.info("Custom Biomes: " + INMS.get().countCustomBiomes());
|
||||
setupChecks();
|
||||
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);
|
||||
}
|
||||
|
||||
public int getIrisVersion() {
|
||||
String input = Iris.instance.getDescription().getVersion();
|
||||
int hyphenIndex = input.indexOf('-');
|
||||
if (hyphenIndex != -1) {
|
||||
String result = input.substring(0, hyphenIndex);
|
||||
result = result.replaceAll("\\.", "");
|
||||
return Integer.parseInt(result);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getMCVersion() {
|
||||
try {
|
||||
String version = Bukkit.getVersion();
|
||||
Matcher matcher = Pattern.compile("\\(MC: ([\\d.]+)\\)").matcher(version);
|
||||
if (matcher.find()) {
|
||||
version = matcher.group(1).replaceAll("\\.", "");
|
||||
long versionNumber = Long.parseLong(version);
|
||||
if (versionNumber > Integer.MAX_VALUE) {
|
||||
return -1;
|
||||
}
|
||||
return (int) versionNumber;
|
||||
}
|
||||
return -1;
|
||||
} catch (Exception e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,221 +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 com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
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();
|
||||
private IrisSettingsUpdater updater = new IrisSettingsUpdater();
|
||||
|
||||
public static int getThreadCount(int c) {
|
||||
if (System.getProperty("os.name").toLowerCase().contains("win"))
|
||||
return Runtime.getRuntime().availableProcessors();
|
||||
return switch (c) {
|
||||
case -1, -2, -4 -> Runtime.getRuntime().availableProcessors() / -c;
|
||||
case 0, 1, 2 -> 1;
|
||||
default -> Math.max(c, 2);
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
public boolean windowsFullPerformance = true;
|
||||
}
|
||||
|
||||
@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 IrisSettingsUpdater {
|
||||
public double threadMultiplier = 2;
|
||||
public double chunkLoadSensitivity = 0.7;
|
||||
public MsRange emptyMsRange = new MsRange(80, 100);
|
||||
public MsRange defaultMsRange = new MsRange(20, 40);
|
||||
|
||||
public double getThreadMultiplier() {
|
||||
return Math.min(Math.abs(threadMultiplier), 0.1);
|
||||
}
|
||||
|
||||
public double getChunkLoadSensitivity() {
|
||||
return Math.min(chunkLoadSensitivity, 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class MsRange {
|
||||
public int min = 20;
|
||||
public int max = 40;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class IrisSettingsGeneral {
|
||||
public boolean DoomsdayAnnihilationSelfDestructMode = false;
|
||||
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;
|
||||
public String cartographerMessage = "Iris does not allow cartographers in its world due to crashes.";
|
||||
|
||||
|
||||
@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;
|
||||
public boolean colorMode = true;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@@ -1,269 +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.core.nms.datapack.DataVersion;
|
||||
import com.volmit.iris.core.nms.datapack.IDataFixer;
|
||||
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.engine.object.IrisRange;
|
||||
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.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.List;
|
||||
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("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(20) + " (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(15) + " (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 List<File> getDatapacksFolder() {
|
||||
if (!IrisSettings.get().getGeneral().forceMainWorld.isEmpty()) {
|
||||
return new KList<File>().qadd(new File(Bukkit.getWorldContainer(), IrisSettings.get().getGeneral().forceMainWorld + "/datapacks"));
|
||||
}
|
||||
KList<File> worlds = new KList<>();
|
||||
Bukkit.getServer().getWorlds().forEach(w -> worlds.add(new File(w.getWorldFolder(), "datapacks")));
|
||||
return worlds;
|
||||
}
|
||||
|
||||
public static void installDataPacks(boolean fullInstall) {
|
||||
installDataPacks(DataVersion.getDefault(), fullInstall);
|
||||
}
|
||||
|
||||
public static void installDataPacks(IDataFixer fixer, boolean fullInstall) {
|
||||
Iris.info("Checking Data Packs...");
|
||||
File packs = new File("plugins/Iris/packs");
|
||||
double ultimateMaxHeight = 0;
|
||||
double ultimateMinHeight = 0;
|
||||
if (packs.exists() && packs.isDirectory()) {
|
||||
for (File pack : packs.listFiles()) {
|
||||
IrisData data = IrisData.get(pack);
|
||||
if (pack.isDirectory()) {
|
||||
File dimensionsFolder = new File(pack, "dimensions");
|
||||
if (dimensionsFolder.exists() && dimensionsFolder.isDirectory()) {
|
||||
for (File file : dimensionsFolder.listFiles()) {
|
||||
if (file.isFile() && file.getName().endsWith(".json")) {
|
||||
IrisDimension dim = data.getDimensionLoader().load(file.getName().split("\\Q.\\E")[0]);
|
||||
if (ultimateMaxHeight < dim.getDimensionHeight().getMax()) {
|
||||
ultimateMaxHeight = dim.getDimensionHeight().getMax();
|
||||
}
|
||||
if (ultimateMinHeight > dim.getDimensionHeight().getMin()) {
|
||||
ultimateMinHeight = dim.getDimensionHeight().getMin();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
for (File dpack : getDatapacksFolder()) {
|
||||
dim.installDataPack(fixer, () -> data, dpack, ultimateMaxHeight, ultimateMinHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,336 +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.ServerConfigurator;
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.core.nms.INMS;
|
||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||
import com.volmit.iris.core.service.IrisEngineSVC;
|
||||
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.core.tools.IrisWorldAnalytics;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.object.IrisDimension;
|
||||
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.io.IO;
|
||||
import com.volmit.iris.util.mantle.TectonicPlate;
|
||||
import com.volmit.iris.util.nbt.mca.MCAFile;
|
||||
import com.volmit.iris.util.nbt.mca.MCAUtil;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
import com.volmit.iris.util.plugin.VolmitSender;
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||
import net.jpountz.lz4.LZ4FrameInputStream;
|
||||
import net.jpountz.lz4.LZ4FrameOutputStream;
|
||||
import org.apache.commons.lang.RandomStringUtils;
|
||||
import org.bukkit.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
@Decree(name = "Developer", origin = DecreeOrigin.BOTH, description = "Iris World Manager", aliases = {"dev"})
|
||||
public class CommandDeveloper implements DecreeExecutor {
|
||||
private CommandUpdater updater;
|
||||
|
||||
@Decree(description = "Get Loaded TectonicPlates Count", origin = DecreeOrigin.BOTH, sync = true)
|
||||
public void EngineStatus() {
|
||||
List<World> IrisWorlds = new ArrayList<>();
|
||||
int TotalLoadedChunks = 0;
|
||||
int TotalQueuedTectonicPlates = 0;
|
||||
int TotalNotQueuedTectonicPlates = 0;
|
||||
int TotalTectonicPlates = 0;
|
||||
|
||||
long lowestUnloadDuration = 0;
|
||||
long highestUnloadDuration = 0;
|
||||
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
try {
|
||||
if (IrisToolbelt.access(world).getEngine() != null) {
|
||||
IrisWorlds.add(world);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// no
|
||||
}
|
||||
}
|
||||
|
||||
for (World world : IrisWorlds) {
|
||||
Engine engine = IrisToolbelt.access(world).getEngine();
|
||||
TotalQueuedTectonicPlates += (int) engine.getMantle().getToUnload();
|
||||
TotalNotQueuedTectonicPlates += (int) engine.getMantle().getNotQueuedLoadedRegions();
|
||||
TotalTectonicPlates += engine.getMantle().getLoadedRegionCount();
|
||||
if (highestUnloadDuration <= (long) engine.getMantle().getTectonicDuration()) {
|
||||
highestUnloadDuration = (long) engine.getMantle().getTectonicDuration();
|
||||
}
|
||||
if (lowestUnloadDuration >= (long) engine.getMantle().getTectonicDuration()) {
|
||||
lowestUnloadDuration = (long) engine.getMantle().getTectonicDuration();
|
||||
}
|
||||
for (Chunk chunk : world.getLoadedChunks()) {
|
||||
if (chunk.isLoaded()) {
|
||||
TotalLoadedChunks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Iris.info("-------------------------");
|
||||
Iris.info(C.DARK_PURPLE + "Engine Status");
|
||||
Iris.info(C.DARK_PURPLE + "Total Loaded Chunks: " + C.LIGHT_PURPLE + TotalLoadedChunks);
|
||||
Iris.info(C.DARK_PURPLE + "Tectonic Limit: " + C.LIGHT_PURPLE + IrisEngineSVC.getTectonicLimit());
|
||||
Iris.info(C.DARK_PURPLE + "Tectonic Total Plates: " + C.LIGHT_PURPLE + TotalTectonicPlates);
|
||||
Iris.info(C.DARK_PURPLE + "Tectonic Active Plates: " + C.LIGHT_PURPLE + TotalNotQueuedTectonicPlates);
|
||||
Iris.info(C.DARK_PURPLE + "Tectonic ToUnload: " + C.LIGHT_PURPLE + TotalQueuedTectonicPlates);
|
||||
Iris.info(C.DARK_PURPLE + "Lowest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(lowestUnloadDuration));
|
||||
Iris.info(C.DARK_PURPLE + "Highest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(highestUnloadDuration));
|
||||
Iris.info(C.DARK_PURPLE + "Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize()));
|
||||
Iris.info("-------------------------");
|
||||
}
|
||||
|
||||
@Decree(description = "Test")
|
||||
public void benchmarkMantle(
|
||||
@Param(description = "The world to bench", aliases = {"world"})
|
||||
World world
|
||||
) throws IOException, ClassNotFoundException {
|
||||
Engine engine = IrisToolbelt.access(world).getEngine();
|
||||
int maxHeight = engine.getTarget().getHeight();
|
||||
File folder = new File(Bukkit.getWorldContainer(), world.getName());
|
||||
int c = 0;
|
||||
//MCAUtil.read()
|
||||
|
||||
File tectonicplates = new File(folder, "mantle");
|
||||
for (File i : Objects.requireNonNull(tectonicplates.listFiles())) {
|
||||
TectonicPlate.read(maxHeight, i);
|
||||
c++;
|
||||
Iris.info("Loaded count: " + c );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Decree(description = "Test")
|
||||
public void packBenchmark(
|
||||
@Param(description = "The pack to bench", aliases = {"pack"})
|
||||
IrisDimension dimension
|
||||
) {
|
||||
Iris.info("test");
|
||||
IrisPackBenchmarking benchmark = new IrisPackBenchmarking(dimension, 1);
|
||||
|
||||
}
|
||||
|
||||
@Decree(description = "gets wg height")
|
||||
public void whatHeight() {
|
||||
Iris.info("test");
|
||||
sender().sendMessage("Height: " + player().getWorld().getHighestBlockAt(player().getLocation(), HeightMap.MOTION_BLOCKING).getY());
|
||||
}
|
||||
|
||||
@Decree(description = "check", aliases = {"ck"} )
|
||||
public void check() {
|
||||
sender().sendMessage("Data Pack Biome: " + INMS.get().getTrueBiomeBaseKey(player().getLocation()) + " (ID: " + INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(player().getLocation())) + ")");
|
||||
}
|
||||
|
||||
@Decree(description = "Upgrade to another Minecraft version")
|
||||
public void upgrade(
|
||||
@Param(description = "The version to upgrade to", defaultValue = "latest") DataVersion version) {
|
||||
sender().sendMessage(C.GREEN + "Upgrading to " + version.getVersion() + "...");
|
||||
ServerConfigurator.installDataPacks(version.get(), false);
|
||||
sender().sendMessage(C.GREEN + "Done upgrading! You can now update your server version to " + version.getVersion());
|
||||
}
|
||||
|
||||
@Decree(description = "test")
|
||||
public void mca (
|
||||
@Param(description = "String") String world) {
|
||||
try {
|
||||
File[] McaFiles = new File(world, "region").listFiles((dir, name) -> name.endsWith(".mca"));
|
||||
for (File mca : McaFiles) {
|
||||
MCAFile MCARegion = MCAUtil.read(mca);
|
||||
int i = 0;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Decree(description = "test")
|
||||
public void anl (
|
||||
@Param(description = "String") String world) {
|
||||
try {
|
||||
IrisWorldAnalytics a = new IrisWorldAnalytics(world);
|
||||
a.execute();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Decree(description = "UnloadChunks for good reasons.")
|
||||
public void unloadchunks() {
|
||||
List<World> IrisWorlds = new ArrayList<>();
|
||||
int chunksUnloaded = 0;
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
try {
|
||||
if (IrisToolbelt.access(world).getEngine() != null) {
|
||||
IrisWorlds.add(world);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// no
|
||||
}
|
||||
}
|
||||
|
||||
for (World world : IrisWorlds) {
|
||||
for (Chunk chunk : world.getLoadedChunks()) {
|
||||
if (chunk.isLoaded()) {
|
||||
chunk.unload();
|
||||
chunksUnloaded++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Iris.info(C.IRIS + "Chunks Unloaded: " + chunksUnloaded);
|
||||
|
||||
}
|
||||
|
||||
@Decree
|
||||
public void objects(@Param(defaultValue = "overworld") IrisDimension dimension) {
|
||||
var loader = dimension.getLoader().getObjectLoader();
|
||||
var sender = sender();
|
||||
var keys = loader.getPossibleKeys();
|
||||
var burst = MultiBurst.burst.burst(keys.length);
|
||||
AtomicInteger failed = new AtomicInteger();
|
||||
for (String key : keys) {
|
||||
burst.queue(() -> {
|
||||
if (loader.load(key) == null)
|
||||
failed.incrementAndGet();
|
||||
});
|
||||
}
|
||||
burst.complete();
|
||||
sender.sendMessage(C.RED + "Failed to load " + failed.get() + " of " + keys.length + " objects");
|
||||
}
|
||||
|
||||
@Decree(description = "Test", aliases = {"ip"})
|
||||
public void network() {
|
||||
try {
|
||||
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
|
||||
for (NetworkInterface ni : Collections.list(networkInterfaces)) {
|
||||
Iris.info("Display Name: %s", ni.getDisplayName());
|
||||
Enumeration<InetAddress> inetAddresses = ni.getInetAddresses();
|
||||
for (InetAddress ia : Collections.list(inetAddresses)) {
|
||||
Iris.info("IP: %s", ia.getHostAddress());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Decree(description = "Test the compression algorithms")
|
||||
public void compression(
|
||||
@Param(description = "base IrisWorld") World world,
|
||||
@Param(description = "raw TectonicPlate File") String path,
|
||||
@Param(description = "Algorithm to Test") String algorithm,
|
||||
@Param(description = "Amount of Tests") int amount) {
|
||||
if (!IrisToolbelt.isIrisWorld(world)) {
|
||||
sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", Bukkit.getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList()));
|
||||
return;
|
||||
}
|
||||
|
||||
File file = new File(path);
|
||||
if (!file.exists()) return;
|
||||
|
||||
Engine engine = IrisToolbelt.access(world).getEngine();
|
||||
if(engine != null) {
|
||||
int height = engine.getTarget().getHeight();
|
||||
ExecutorService service = Executors.newFixedThreadPool(1);
|
||||
VolmitSender sender = sender();
|
||||
service.submit(() -> {
|
||||
try {
|
||||
DataInputStream raw = new DataInputStream(new FileInputStream(file));
|
||||
TectonicPlate plate = new TectonicPlate(height, raw);
|
||||
raw.close();
|
||||
|
||||
double d1 = 0;
|
||||
double d2 = 0;
|
||||
long size = 0;
|
||||
File folder = new File("tmp");
|
||||
folder.mkdirs();
|
||||
for (int i = 0; i < amount; i++) {
|
||||
File tmp = new File(folder, RandomStringUtils.randomAlphanumeric(10) + "." + algorithm + ".bin");
|
||||
DataOutputStream dos = createOutput(tmp, algorithm);
|
||||
long start = System.currentTimeMillis();
|
||||
plate.write(dos);
|
||||
dos.close();
|
||||
d1 += System.currentTimeMillis() - start;
|
||||
if (size == 0)
|
||||
size = tmp.length();
|
||||
start = System.currentTimeMillis();
|
||||
DataInputStream din = createInput(tmp, algorithm);
|
||||
new TectonicPlate(height, din);
|
||||
din.close();
|
||||
d2 += System.currentTimeMillis() - start;
|
||||
tmp.delete();
|
||||
}
|
||||
IO.delete(folder);
|
||||
sender.sendMessage(algorithm + " is " + Form.fileSize(size) + " big after compression");
|
||||
sender.sendMessage(algorithm + " Took " + d2/amount + "ms to read");
|
||||
sender.sendMessage(algorithm + " Took " + d1/amount + "ms to write");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
service.shutdown();
|
||||
} else {
|
||||
Iris.info(C.RED + "Engine is null!");
|
||||
}
|
||||
}
|
||||
|
||||
private DataInputStream createInput(File file, String algorithm) throws Throwable {
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
|
||||
return new DataInputStream(switch (algorithm) {
|
||||
case "gzip" -> new GZIPInputStream(in);
|
||||
case "lz4f" -> new LZ4FrameInputStream(in);
|
||||
case "lz4b" -> new LZ4BlockInputStream(in);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + algorithm);
|
||||
});
|
||||
}
|
||||
|
||||
private DataOutputStream createOutput(File file, String algorithm) throws Throwable {
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
|
||||
return new DataOutputStream(switch (algorithm) {
|
||||
case "gzip" -> new GZIPOutputStream(out);
|
||||
case "lz4f" -> new LZ4FrameOutputStream(out);
|
||||
case "lz4b" -> new LZ4BlockOutputStream(out);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + algorithm);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,179 +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.*;
|
||||
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.*;
|
||||
|
||||
|
||||
@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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,117 +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,
|
||||
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||
boolean teleport
|
||||
) {
|
||||
Engine e = engine();
|
||||
|
||||
if (e == null) {
|
||||
sender().sendMessage(C.GOLD + "Not in an Iris World!");
|
||||
return;
|
||||
}
|
||||
|
||||
e.gotoBiome(biome, player(), teleport);
|
||||
}
|
||||
|
||||
@Decree(description = "Find a region")
|
||||
public void region(
|
||||
@Param(description = "The region to look for")
|
||||
IrisRegion region,
|
||||
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||
boolean teleport
|
||||
) {
|
||||
Engine e = engine();
|
||||
|
||||
if (e == null) {
|
||||
sender().sendMessage(C.GOLD + "Not in an Iris World!");
|
||||
return;
|
||||
}
|
||||
|
||||
e.gotoRegion(region, player(), teleport);
|
||||
}
|
||||
|
||||
@Decree(description = "Find a structure")
|
||||
public void structure(
|
||||
@Param(description = "The structure to look for")
|
||||
IrisJigsawStructure structure,
|
||||
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||
boolean teleport
|
||||
) {
|
||||
Engine e = engine();
|
||||
|
||||
if (e == null) {
|
||||
sender().sendMessage(C.GOLD + "Not in an Iris World!");
|
||||
return;
|
||||
}
|
||||
|
||||
e.gotoJigsaw(structure, player(), teleport);
|
||||
}
|
||||
|
||||
@Decree(description = "Find a point of interest.")
|
||||
public void poi(
|
||||
@Param(description = "The type of PoI to look for.")
|
||||
String type,
|
||||
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||
boolean teleport
|
||||
) {
|
||||
Engine e = engine();
|
||||
if (e == null) {
|
||||
sender().sendMessage(C.GOLD + "Not in an Iris World!");
|
||||
return;
|
||||
}
|
||||
|
||||
e.gotoPOI(type, player(), teleport);
|
||||
}
|
||||
|
||||
@Decree(description = "Find an object")
|
||||
public void object(
|
||||
@Param(description = "The object to look for", customHandler = ObjectHandler.class)
|
||||
String object,
|
||||
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||
boolean teleport
|
||||
) {
|
||||
Engine e = engine();
|
||||
|
||||
if (e == null) {
|
||||
sender().sendMessage(C.GOLD + "Not in an Iris World!");
|
||||
return;
|
||||
}
|
||||
|
||||
e.gotoObject(object, player(), teleport);
|
||||
}
|
||||
}
|
||||
@@ -1,652 +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.ServerConfigurator;
|
||||
import com.volmit.iris.core.loader.IrisData;
|
||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||
import com.volmit.iris.core.pregenerator.ChunkUpdater;
|
||||
import com.volmit.iris.core.service.StudioSVC;
|
||||
import com.volmit.iris.core.tools.IrisBenchmarking;
|
||||
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.core.safeguard.UtilsSFG;
|
||||
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.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.NullablePlayerHandler;
|
||||
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 lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Difficulty;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.io.Console;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.volmit.iris.Iris.service;
|
||||
import static com.volmit.iris.core.service.EditSVC.deletingWorld;
|
||||
import static com.volmit.iris.core.tools.IrisBenchmarking.inProgress;
|
||||
import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode;
|
||||
import static com.volmit.iris.core.safeguard.ServerBootSFG.incompatibilities;
|
||||
import static org.bukkit.Bukkit.getServer;
|
||||
|
||||
@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;
|
||||
private CommandDeveloper developer;
|
||||
public static boolean worldCreation = false;
|
||||
String WorldEngine;
|
||||
String worldNameToCheck = "YourWorldName";
|
||||
VolmitSender sender = Iris.getSender();
|
||||
|
||||
@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,
|
||||
@Param(description = "If it should convert the dimension to match the vanilla height system.", defaultValue = "false")
|
||||
boolean vanillaheight
|
||||
) {
|
||||
if(sender() instanceof Player) {
|
||||
if (incompatibilities.get("Multiverse-Core")) {
|
||||
sender().sendMessage(C.RED + "Your server has an incompatibility that may corrupt all worlds on the server if not handled properly.");
|
||||
sender().sendMessage(C.RED + "it is strongly advised for you to take action. see log for full detail");
|
||||
sender().sendMessage(C.RED + "----------------------------------------------------------------");
|
||||
sender().sendMessage(C.RED + "Command ran: /iris create");
|
||||
sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings());
|
||||
sender().sendMessage(C.RED + "----------------------------------------------------------------");
|
||||
}
|
||||
if (unstablemode && !incompatibilities.get("Multiverse-Core")) {
|
||||
sender().sendMessage(C.RED + "Your server is experiencing an incompatibility with the Iris plugin.");
|
||||
sender().sendMessage(C.RED + "Please rectify this problem to avoid further complications.");
|
||||
sender().sendMessage(C.RED + "----------------------------------------------------------------");
|
||||
sender().sendMessage(C.RED + "Command ran: /iris create");
|
||||
sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings());
|
||||
sender().sendMessage(C.RED + "----------------------------------------------------------------");
|
||||
}
|
||||
}
|
||||
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 (name.equals("Benchmark")) {
|
||||
sender().sendMessage(C.RED + "You cannot use the world name \"Benchmark\" for creating worlds as Iris uses this directory for Benchmarking Packs.");
|
||||
sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?");
|
||||
return;
|
||||
}
|
||||
|
||||
if (new File(Bukkit.getWorldContainer(), name).exists()) {
|
||||
sender().sendMessage(C.RED + "That folder already exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
worldCreation = true;
|
||||
IrisToolbelt.createWorld()
|
||||
.dimension(type.getLoadKey())
|
||||
.name(name)
|
||||
.seed(seed)
|
||||
.sender(sender())
|
||||
.studio(false)
|
||||
.smartVanillaHeight(vanillaheight)
|
||||
.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);
|
||||
worldCreation = false;
|
||||
return;
|
||||
}
|
||||
worldCreation = false;
|
||||
sender().sendMessage(C.GREEN + "Successfully created your world!");
|
||||
}
|
||||
|
||||
@Decree(description = "Teleport to another world", aliases = {"tp"}, sync = true)
|
||||
public void teleport(
|
||||
@Param(description = "World to teleport to")
|
||||
World world,
|
||||
@Param(description = "Player to teleport", defaultValue = "---", customHandler = NullablePlayerHandler.class)
|
||||
Player player
|
||||
) {
|
||||
if (player == null && sender().isPlayer())
|
||||
player = sender().player();
|
||||
|
||||
final Player target = player;
|
||||
if (target == null) {
|
||||
sender().sendMessage(C.RED + "The specified player does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
target.teleport(world.getSpawnLocation());
|
||||
new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + ".");
|
||||
}
|
||||
}.runTask(Iris.instance);
|
||||
}
|
||||
|
||||
@Decree(description = "Print version information")
|
||||
public void version() {
|
||||
sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software");
|
||||
}
|
||||
|
||||
//todo Move to React
|
||||
@Decree(description = "Benchmark your server", origin = DecreeOrigin.CONSOLE)
|
||||
public void serverbenchmark() throws InterruptedException {
|
||||
if(!inProgress) {
|
||||
IrisBenchmarking.runBenchmark();
|
||||
} else {
|
||||
Iris.info(C.RED + "Benchmark already is in progress.");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/todo
|
||||
@Decree(description = "Benchmark a pack", origin = DecreeOrigin.CONSOLE)
|
||||
public void packbenchmark(
|
||||
@Param(description = "Dimension to benchmark")
|
||||
IrisDimension type
|
||||
) throws InterruptedException {
|
||||
|
||||
BenchDimension = type.getLoadKey();
|
||||
|
||||
IrisPackBenchmarking.runBenchmark();
|
||||
} */
|
||||
|
||||
@Decree(description = "Print world height information", origin = DecreeOrigin.PLAYER)
|
||||
public void height() {
|
||||
if (sender().isPlayer()) {
|
||||
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()));
|
||||
} else {
|
||||
World mainWorld = getServer().getWorlds().get(0);
|
||||
Iris.info(C.GREEN + "" + mainWorld.getMinHeight() + " to " + mainWorld.getMaxHeight());
|
||||
Iris.info(C.GREEN + "Total Height: " + (mainWorld.getMaxHeight() - mainWorld.getMinHeight()));
|
||||
}
|
||||
}
|
||||
|
||||
@Decree(description = "QOL command to open a overworld studio world.", sync = true)
|
||||
public void so() {
|
||||
sender().sendMessage(C.GREEN + "Opening studio for the \"Overworld\" pack (seed: 1337)");
|
||||
Iris.service(StudioSVC.class).open(sender(), 1337, "overworld");
|
||||
}
|
||||
|
||||
@Decree(description = "Check access of all worlds.", aliases = {"accesslist"})
|
||||
public void worlds() {
|
||||
KList<World> IrisWorlds = new KList<>();
|
||||
KList<World> BukkitWorlds = new KList<>();
|
||||
|
||||
for (World w : Bukkit.getServer().getWorlds()) {
|
||||
try {
|
||||
Engine engine = IrisToolbelt.access(w).getEngine();
|
||||
if (engine != null) {
|
||||
IrisWorlds.add(w);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
BukkitWorlds.add(w);
|
||||
}
|
||||
}
|
||||
|
||||
if (sender().isPlayer()) {
|
||||
sender().sendMessage(C.BLUE + "Iris Worlds: ");
|
||||
for (World IrisWorld : IrisWorlds.copy()) {
|
||||
sender().sendMessage(C.IRIS + "- " +IrisWorld.getName());
|
||||
}
|
||||
sender().sendMessage(C.GOLD + "Bukkit Worlds: ");
|
||||
for (World BukkitWorld : BukkitWorlds.copy()) {
|
||||
sender().sendMessage(C.GRAY + "- " +BukkitWorld.getName());
|
||||
}
|
||||
} else {
|
||||
Iris.info(C.BLUE + "Iris Worlds: ");
|
||||
for (World IrisWorld : IrisWorlds.copy()) {
|
||||
Iris.info(C.IRIS + "- " +IrisWorld.getName());
|
||||
}
|
||||
Iris.info(C.GOLD + "Bukkit Worlds: ");
|
||||
for (World BukkitWorld : BukkitWorlds.copy()) {
|
||||
Iris.info(C.GRAY + "- " +BukkitWorld.getName());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Decree(description = "Remove an Iris world", aliases = {"del", "rm", "delete"}, sync = true)
|
||||
public void remove(
|
||||
@Param(description = "The world to remove")
|
||||
World world,
|
||||
@Param(description = "Whether to also remove the folder (if set to false, just does not load the world)", defaultValue = "true")
|
||||
boolean delete
|
||||
) {
|
||||
if (!IrisToolbelt.isIrisWorld(world)) {
|
||||
sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList()));
|
||||
return;
|
||||
}
|
||||
sender().sendMessage(C.GREEN + "Removing world: " + world.getName());
|
||||
try {
|
||||
if (IrisToolbelt.removeWorld(world)) {
|
||||
sender().sendMessage(C.GREEN + "Successfully removed " + world.getName() + " from bukkit.yml");
|
||||
} else {
|
||||
sender().sendMessage(C.YELLOW + "Looks like the world was already removed from bukkit.yml");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
sender().sendMessage(C.RED + "Failed to save bukkit.yml because of " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
IrisToolbelt.evacuate(world, "Deleting world");
|
||||
deletingWorld = true;
|
||||
Bukkit.unloadWorld(world, false);
|
||||
int retries = 12;
|
||||
if (delete) {
|
||||
if (deleteDirectory(world.getWorldFolder())) {
|
||||
sender().sendMessage(C.GREEN + "Successfully removed world folder");
|
||||
} else {
|
||||
while(true){
|
||||
if (deleteDirectory(world.getWorldFolder())){
|
||||
sender().sendMessage(C.GREEN + "Successfully removed world folder");
|
||||
break;
|
||||
}
|
||||
retries--;
|
||||
if (retries == 0){
|
||||
sender().sendMessage(C.RED + "Failed to remove world folder");
|
||||
break;
|
||||
}
|
||||
J.sleep(3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
deletingWorld = false;
|
||||
}
|
||||
|
||||
public static boolean deleteDirectory(File dir) {
|
||||
if (dir.isDirectory()) {
|
||||
File[] children = dir.listFiles();
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
boolean success = deleteDirectory(children[i]);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dir.delete();
|
||||
}
|
||||
|
||||
@Decree(description = "Updates all chunk in the specified world")
|
||||
public void updater(
|
||||
@Param(description = "World to update chunks at")
|
||||
World world
|
||||
) {
|
||||
if (!IrisToolbelt.isIrisWorld(world)) {
|
||||
sender().sendMessage(C.GOLD + "This is not an Iris world");
|
||||
return;
|
||||
}
|
||||
ChunkUpdater updater = new ChunkUpdater(world);
|
||||
if (sender().isPlayer()) {
|
||||
sender().sendMessage(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks()));
|
||||
} else {
|
||||
Iris.info(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks()));
|
||||
}
|
||||
updater.start();
|
||||
}
|
||||
|
||||
@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
|
||||
) {
|
||||
sender().sendMessage(C.GREEN + "Downloading pack: " + pack + "/" + branch + (trim ? " trimmed" : "") + (overwrite ? " overwriting" : ""));
|
||||
if (pack.equals("overworld")) {
|
||||
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + Iris.OVERWORLD_TAG + "/overworld.zip";
|
||||
Iris.service(StudioSVC.class).downloadRelease(sender(), url, trim, overwrite);
|
||||
} else {
|
||||
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(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.getName() + " " + pack.getLoadKey() + " 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);
|
||||
}
|
||||
|
||||
@Decree(description = "Unload an Iris World", origin = DecreeOrigin.PLAYER, sync = true)
|
||||
public void unloadWorld(
|
||||
@Param(description = "The world to unload")
|
||||
World world
|
||||
) {
|
||||
if (!IrisToolbelt.isIrisWorld(world)) {
|
||||
sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList()));
|
||||
return;
|
||||
}
|
||||
sender().sendMessage(C.GREEN + "Unloading world: " + world.getName());
|
||||
try {
|
||||
IrisToolbelt.evacuate(world);
|
||||
Bukkit.unloadWorld(world, false);
|
||||
sender().sendMessage(C.GREEN + "World unloaded successfully.");
|
||||
} catch (Exception e) {
|
||||
sender().sendMessage(C.RED + "Failed to unload the world: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Decree(description = "Load an Iris World", origin = DecreeOrigin.PLAYER, sync = true, aliases = {"import"})
|
||||
public void loadWorld(
|
||||
@Param(description = "The name of the world to load")
|
||||
String world
|
||||
) {
|
||||
World worldloaded = Bukkit.getWorld(world);
|
||||
worldNameToCheck = world;
|
||||
boolean worldExists = doesWorldExist(worldNameToCheck);
|
||||
WorldEngine = world;
|
||||
|
||||
if (!worldExists) {
|
||||
sender().sendMessage(C.YELLOW + world + " Doesnt exist on the server.");
|
||||
return;
|
||||
}
|
||||
|
||||
File BUKKIT_YML = new File("bukkit.yml");
|
||||
String pathtodim = world + File.separator +"iris"+File.separator +"pack"+File.separator +"dimensions"+File.separator;
|
||||
File directory = new File(Bukkit.getWorldContainer(), pathtodim);
|
||||
|
||||
String dimension = null;
|
||||
if (directory.exists() && directory.isDirectory()) {
|
||||
File[] files = directory.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.isFile()) {
|
||||
String fileName = file.getName();
|
||||
if (fileName.endsWith(".json")) {
|
||||
dimension = fileName.substring(0, fileName.length() - 5);
|
||||
sender().sendMessage(C.BLUE + "Generator: " + dimension);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sender().sendMessage(C.GOLD + world + " is not an iris world.");
|
||||
return;
|
||||
}
|
||||
sender().sendMessage(C.GREEN + "Loading world: " + world);
|
||||
|
||||
YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML);
|
||||
String gen = "Iris:" + dimension;
|
||||
ConfigurationSection section = yml.contains("worlds") ? yml.getConfigurationSection("worlds") : yml.createSection("worlds");
|
||||
if (!section.contains(world)) {
|
||||
section.createSection(world).set("generator", gen);
|
||||
try {
|
||||
yml.save(BUKKIT_YML);
|
||||
Iris.info("Registered \"" + world + "\" in bukkit.yml");
|
||||
} catch (IOException e) {
|
||||
Iris.error("Failed to update bukkit.yml!");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
checkForBukkitWorlds(world);
|
||||
sender().sendMessage(C.GREEN + world + " loaded successfully.");
|
||||
}
|
||||
@Decree(description = "Evacuate an iris world", origin = DecreeOrigin.PLAYER, sync = true)
|
||||
public void evacuate(
|
||||
@Param(description = "Evacuate the world")
|
||||
World world
|
||||
) {
|
||||
if (!IrisToolbelt.isIrisWorld(world)) {
|
||||
sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList()));
|
||||
return;
|
||||
}
|
||||
sender().sendMessage(C.GREEN + "Evacuating world" + world.getName());
|
||||
IrisToolbelt.evacuate(world);
|
||||
}
|
||||
|
||||
boolean doesWorldExist(String worldName) {
|
||||
File worldContainer = Bukkit.getWorldContainer();
|
||||
File worldDirectory = new File(worldContainer, worldName);
|
||||
return worldDirectory.exists() && worldDirectory.isDirectory();
|
||||
}
|
||||
private void checkForBukkitWorlds(String world) {
|
||||
FileConfiguration fc = new YamlConfiguration();
|
||||
try {
|
||||
fc.load(new File("bukkit.yml"));
|
||||
ConfigurationSection section = fc.getConfigurationSection("worlds");
|
||||
if (section == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> worldsToLoad = Collections.singletonList(world);
|
||||
|
||||
for (String s : section.getKeys(false)) {
|
||||
if (!worldsToLoad.contains(s)) {
|
||||
continue;
|
||||
}
|
||||
ConfigurationSection entry = section.getConfigurationSection(s);
|
||||
if (!entry.contains("generator", true)) {
|
||||
continue;
|
||||
}
|
||||
String generator = entry.getString("generator");
|
||||
if (generator.startsWith("Iris:")) {
|
||||
generator = generator.split("\\Q:\\E")[1];
|
||||
} else if (generator.equalsIgnoreCase("Iris")) {
|
||||
generator = IrisSettings.get().getGenerator().getDefaultWorldType();
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
Iris.info("2 World: %s | Generator: %s", s, generator);
|
||||
if (Bukkit.getWorlds().stream().anyMatch(w -> w.getName().equals(s))) {
|
||||
continue;
|
||||
}
|
||||
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
|
||||
new WorldCreator(s)
|
||||
.generator(getDefaultWorldGenerator(s, generator))
|
||||
.environment(IrisData.loadAnyDimension(generator).getEnvironment())
|
||||
.createWorld();
|
||||
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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(Bukkit.getWorldContainer(), 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(), false);
|
||||
}
|
||||
}
|
||||
@@ -1,121 +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.framework.placer.WorldObjectPlacer;
|
||||
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.plugin.VolmitSender;
|
||||
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();
|
||||
try {
|
||||
var world = world();
|
||||
WorldObjectPlacer placer = new WorldObjectPlacer(world);
|
||||
PlannedStructure ps = new PlannedStructure(structure, new IrisPosition(player().getLocation().add(0, world.getMinHeight(), 0)), new RNG(), true);
|
||||
VolmitSender sender = sender();
|
||||
sender.sendMessage(C.GREEN + "Generated " + ps.getPieces().size() + " pieces in " + Form.duration(p.getMilliseconds(), 2));
|
||||
ps.place(placer, failed -> sender.sendMessage(failed ? C.GREEN + "Placed the structure!" : C.RED + "Failed to place the structure!"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
sender().sendMessage(C.RED + "Failed to place the structure: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@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");
|
||||
}
|
||||
}
|
||||
@@ -1,551 +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.core.tools.IrisConverter;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.object.*;
|
||||
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.misc.E;
|
||||
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.*;
|
||||
|
||||
@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(E.getOrDefault(Material.class, "GRASS", "SHORT_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 tile) {
|
||||
tile.toBukkitTry(world.getBlockAt(xx, yy, zz));
|
||||
}
|
||||
|
||||
@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().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 = "Shrink an object to its minimum size")
|
||||
public void shrink(@Param(description = "The object to shrink", customHandler = ObjectHandler.class) String object) {
|
||||
IrisObject o = IrisData.loadAnyObject(object);
|
||||
sender().sendMessage("Current Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD());
|
||||
o.shrinkwrap();
|
||||
sender().sendMessage("New Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD());
|
||||
try {
|
||||
o.write(o.getLoadFile());
|
||||
} catch (IOException e) {
|
||||
sender().sendMessage("Failed to save object " + o.getLoadFile() + ": " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Decree(description = "Convert .schem files in the 'convert' folder to .iob files.")
|
||||
public void convert () {
|
||||
try {
|
||||
IrisConverter.convertSchematics(sender());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@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());
|
||||
if (b == null) {
|
||||
return;
|
||||
}
|
||||
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 (g == null) {
|
||||
return;
|
||||
}
|
||||
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 (g == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
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(C.IRIS + "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, sender());
|
||||
} 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();
|
||||
if (d == null) {
|
||||
return; // HOW DID THIS HAPPEN
|
||||
}
|
||||
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(C.BLUE + "Reverted " + actualReverts + C.BLUE +" 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!");
|
||||
}
|
||||
}
|
||||
@@ -1,90 +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.PregeneratorJob;
|
||||
import com.volmit.iris.core.pregenerator.LazyPregenerator;
|
||||
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.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@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.getBlockX() >> 9, center.getBlockZ() >> 9))
|
||||
.gui(true)
|
||||
.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()) {
|
||||
Iris.info( C.BLUE + "Finishing up mca region...");
|
||||
} 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
@@ -1,899 +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.IrisConverter;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.engine.object.*;
|
||||
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.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.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.Position2;
|
||||
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.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
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.QueueJob;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.BlockVector;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
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.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Decree(name = "studio", aliases = {"std", "s"}, description = "Studio Commands", studio = true)
|
||||
public class CommandStudio implements DecreeExecutor {
|
||||
private CommandFind find;
|
||||
private CommandEdit edit;
|
||||
//private CommandDeepSearch deepSearch;
|
||||
|
||||
public static String hrf(Duration duration) {
|
||||
return duration.toString().substring(2).replaceAll("(\\d[HMS])(?!$)", "$1 ").toLowerCase();
|
||||
}
|
||||
|
||||
@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 = "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(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 = "Convert objects in the \"convert\" folder")
|
||||
public void convert() {
|
||||
Iris.service(ConversionSVC.class).check(sender());
|
||||
//IrisConverter.convertSchematics(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().getWorld(), 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().getWorld(), 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 = "Get all structures in a radius of chunks", aliases = "dist", origin = DecreeOrigin.PLAYER)
|
||||
public void distances(@Param(description = "The radius in chunks") int radius) {
|
||||
var engine = engine();
|
||||
if (engine == null) {
|
||||
sender().sendMessage(C.RED + "Only works in an Iris world!");
|
||||
return;
|
||||
}
|
||||
var sender = sender();
|
||||
int d = radius * 2;
|
||||
KMap<String, KList<Position2>> data = new KMap<>();
|
||||
var multiBurst = new MultiBurst("Distance Sampler", Thread.MIN_PRIORITY);
|
||||
var executor = multiBurst.burst(radius * radius);
|
||||
|
||||
sender.sendMessage(C.GRAY + "Generating data...");
|
||||
var loc = player().getLocation();
|
||||
int totalTasks = d * d;
|
||||
AtomicInteger completedTasks = new AtomicInteger(0);
|
||||
int c = J.ar(() -> {
|
||||
sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding structures");
|
||||
}, 0);
|
||||
|
||||
new Spiraler(d, d, (x, z) -> executor.queue(() -> {
|
||||
var struct = engine.getStructureAt(x, z);
|
||||
if (struct != null) {
|
||||
data.computeIfAbsent(struct.getLoadKey(), (k) -> new KList<>()).add(new Position2(x, z));
|
||||
}
|
||||
completedTasks.incrementAndGet();
|
||||
})).setOffset(loc.getBlockX(), loc.getBlockZ()).drain();
|
||||
|
||||
executor.complete();
|
||||
multiBurst.close();
|
||||
J.car(c);
|
||||
|
||||
for (var key : data.keySet()) {
|
||||
var list = data.get(key);
|
||||
KList<Long> distances = new KList<>(list.size() - 1);
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
var pos = list.get(i);
|
||||
double dist = Integer.MAX_VALUE;
|
||||
for (var p : list) {
|
||||
if (p.equals(pos)) continue;
|
||||
dist = Math.min(dist, Math.sqrt(Math.pow(pos.getX() - p.getX(), 2) + Math.pow(pos.getZ() - p.getZ(), 2)));
|
||||
}
|
||||
if (dist == Integer.MAX_VALUE) continue;
|
||||
distances.add(Math.round(dist * 16));
|
||||
}
|
||||
long[] array = new long[distances.size()];
|
||||
for (int i = 0; i < distances.size(); i++) {
|
||||
array[i] = distances.get(i);
|
||||
}
|
||||
Arrays.sort(array);
|
||||
long min = array.length > 0 ? array[0] : 0;
|
||||
long max = array.length > 0 ? array[array.length - 1] : 0;
|
||||
long sum = Arrays.stream(array).sum();
|
||||
long avg = array.length > 0 ? Math.round(sum / (double) array.length) : 0;
|
||||
String msg = "%s: %s => min: %s/max: %s -> avg: %s".formatted(key, list.size(), min, max, avg);
|
||||
sender.sendMessage(msg);
|
||||
}
|
||||
if (data.isEmpty()) {
|
||||
sender.sendMessage(C.RED + "No data found!");
|
||||
} else {
|
||||
sender.sendMessage(C.GREEN + "Done!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@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
|
||||
) {
|
||||
// Todo: Make this more accurate
|
||||
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 = "Spawn an Iris entity", aliases = "summon", origin = DecreeOrigin.PLAYER)
|
||||
public void spawn(
|
||||
@Param(description = "The entity to spawn")
|
||||
IrisEntity entity,
|
||||
@Param(description = "The location to spawn the entity at", contextual = true)
|
||||
Vector location
|
||||
) {
|
||||
if (!IrisToolbelt.isIrisWorld(player().getWorld())) {
|
||||
sender().sendMessage(C.RED + "You have to be in an Iris world to spawn entities properly. Trying to spawn the best we can do.");
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.commands;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.pregenerator.ChunkUpdater;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
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;
|
||||
|
||||
@Decree(name = "updater", origin = DecreeOrigin.BOTH, description = "Iris World Updater")
|
||||
public class CommandUpdater implements DecreeExecutor {
|
||||
private ChunkUpdater chunkUpdater;
|
||||
|
||||
@Decree(description = "Updates all chunk in the specified world")
|
||||
public void start(
|
||||
@Param(description = "World to update chunks at", contextual = true)
|
||||
World world
|
||||
) {
|
||||
if (!IrisToolbelt.isIrisWorld(world)) {
|
||||
sender().sendMessage(C.GOLD + "This is not an Iris world");
|
||||
return;
|
||||
}
|
||||
if (chunkUpdater != null) {
|
||||
chunkUpdater.stop();
|
||||
}
|
||||
|
||||
chunkUpdater = new ChunkUpdater(world);
|
||||
if (sender().isPlayer()) {
|
||||
sender().sendMessage(C.GREEN + "Updating " + world.getName() + C.GRAY + " Total chunks: " + Form.f(chunkUpdater.getChunks()));
|
||||
} else {
|
||||
Iris.info(C.GREEN + "Updating " + world.getName() + C.GRAY + " Total chunks: " + Form.f(chunkUpdater.getChunks()));
|
||||
}
|
||||
chunkUpdater.start();
|
||||
}
|
||||
|
||||
@Decree(description = "Pause the updater")
|
||||
public void pause( ) {
|
||||
if (chunkUpdater == null) {
|
||||
sender().sendMessage(C.GOLD + "You cant pause something that doesnt exist?");
|
||||
return;
|
||||
}
|
||||
boolean status = chunkUpdater.pause();
|
||||
if (sender().isPlayer()) {
|
||||
if (status) {
|
||||
sender().sendMessage(C.IRIS + "Paused task for: " + C.GRAY + chunkUpdater.getName());
|
||||
} else {
|
||||
sender().sendMessage(C.IRIS + "Unpause task for: " + C.GRAY + chunkUpdater.getName());
|
||||
}
|
||||
} else {
|
||||
if (status) {
|
||||
Iris.info(C.IRIS + "Paused task for: " + C.GRAY + chunkUpdater.getName());
|
||||
} else {
|
||||
Iris.info(C.IRIS + "Unpause task for: " + C.GRAY + chunkUpdater.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Decree(description = "Stops the updater")
|
||||
public void stop() {
|
||||
if (chunkUpdater == null) {
|
||||
sender().sendMessage(C.GOLD + "You cant stop something that doesnt exist?");
|
||||
return;
|
||||
}
|
||||
if (sender().isPlayer()) {
|
||||
sender().sendMessage("Stopping Updater for: " + C.GRAY + chunkUpdater.getName());
|
||||
} else {
|
||||
Iris.info("Stopping Updater for: " + C.GRAY + chunkUpdater.getName());
|
||||
}
|
||||
chunkUpdater.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,169 +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.framework.Engine;
|
||||
import com.volmit.iris.engine.object.IrisBiome;
|
||||
import com.volmit.iris.engine.object.IrisRegion;
|
||||
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.Objects;
|
||||
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().getWorld().getMinHeight(), 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 region am i in?", origin = DecreeOrigin.PLAYER)
|
||||
public void region() {
|
||||
try {
|
||||
Chunk chunk = world().getChunkAt(player().getLocation().getBlockZ() / 16, player().getLocation().getBlockZ() / 16);
|
||||
IrisRegion r = engine().getRegion(chunk);
|
||||
sender().sendMessage("IRegion: " + r.getLoadKey() + " (" + r.getName() + ")");
|
||||
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
sender().sendMessage(C.IRIS + "Iris worlds only.");
|
||||
}
|
||||
}
|
||||
|
||||
@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(C.IRIS + "Iris worlds only.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,253 +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.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.service.WandSVC;
|
||||
import com.volmit.iris.engine.object.*;
|
||||
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) { // This gets all the objects in an array that are connectors
|
||||
KList<JSONObject> o = new KList<>();
|
||||
|
||||
for (int i = 0; i < a.getJSONArray("connectors").length(); i++) {
|
||||
o.add(a.getJSONArray("connectors").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)) {
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,338 +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.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.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
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 = IrisSettings.get().getGui().colorMode;
|
||||
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().sort();
|
||||
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);
|
||||
//Color color = colorMode ? Color.getHSBColor((float) (n), (float) (n * n * n * n * n * n), (float) n) : Color.getHSBColor(0f, 0f, (float) n);
|
||||
//Color color = colorMode ? Color.getHSBColor((float) n, (float) (n * n * n * n * n * n), (float) n) : Color.getHSBColor(0f, 0f, (float) n);
|
||||
|
||||
int rgb = color.getRGB();
|
||||
img.setRGB(xx, z, rgb);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,437 +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.core.tools.IrisPackBenchmarking;
|
||||
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.*;
|
||||
import java.awt.*;
|
||||
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;
|
||||
|
||||
import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmarkInProgress;
|
||||
|
||||
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 final ChronoLatch cl = new ChronoLatch(TimeUnit.MINUTES.toMillis(1));
|
||||
private final Engine engine;
|
||||
private JFrame frame;
|
||||
private PregenRenderer renderer;
|
||||
private int rgc = 0;
|
||||
private String[] info;
|
||||
|
||||
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);
|
||||
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() && task.isGui()) {
|
||||
open();
|
||||
}
|
||||
|
||||
var t = new Thread(() -> {
|
||||
J.sleep(1000);
|
||||
this.pregenerator.start();
|
||||
}, "Iris Pregenerator");
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
t.start();
|
||||
}
|
||||
|
||||
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 Mantle getMantle() {
|
||||
return pregenerator.getMantle();
|
||||
}
|
||||
|
||||
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) {
|
||||
Iris.error("Failed to draw pregen");
|
||||
}
|
||||
}
|
||||
|
||||
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 ignored) {
|
||||
Iris.error("Error closing pregen gui");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 ignored) {
|
||||
Iris.error("Error opening pregen gui");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,842 +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.*;
|
||||
import javax.swing.event.MouseInputListener;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,85 +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.engine.object.IrisBiome;
|
||||
import com.volmit.iris.engine.object.IrisBiomeGeneratorLink;
|
||||
import com.volmit.iris.util.interpolation.IrisInterpolation;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
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();
|
||||
case CONTINENT -> colorFunction = (x, z) -> {
|
||||
IrisBiome b = renderer.getBiome((int) Math.round(x), renderer.getMaxHeight() - 1, (int) Math.round(z));
|
||||
IrisBiomeGeneratorLink g = b.getGenerators().get(0);
|
||||
Color c;
|
||||
if (g.getMax(renderer) <= 0) {
|
||||
// Max is below water level, so it is most likely an ocean biome
|
||||
c = Color.BLUE;
|
||||
} else if (g.getMin(renderer) < 0) {
|
||||
// Min is below water level, but max is not, so it is most likely a shore biome
|
||||
c = Color.YELLOW;
|
||||
} else {
|
||||
// Both min and max are above water level, so it is most likely a land biome
|
||||
c = Color.GREEN;
|
||||
}
|
||||
return c.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;
|
||||
}
|
||||
}
|
||||
@@ -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, CONTINENT, LAYER_LOAD
|
||||
}
|
||||
@@ -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.*;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Renderer {
|
||||
Color draw(double x, double z);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
//package com.volmit.iris.core.link;
|
||||
//
|
||||
//import com.jojodmo.customitems.api.CustomItemsAPI;
|
||||
//import com.jojodmo.customitems.item.custom.CustomItem;
|
||||
//import com.jojodmo.customitems.item.custom.block.CustomMushroomBlock;
|
||||
//import com.jojodmo.customitems.version.SafeMaterial;
|
||||
//import com.volmit.iris.util.collection.KList;
|
||||
//import com.volmit.iris.util.reflect.WrappedField;
|
||||
//import com.volmit.iris.util.reflect.WrappedReturningMethod;
|
||||
//import org.bukkit.block.BlockFace;
|
||||
//import org.bukkit.block.data.BlockData;
|
||||
//import org.bukkit.block.data.MultipleFacing;
|
||||
//import org.bukkit.inventory.ItemStack;
|
||||
//
|
||||
//import java.util.Map;
|
||||
//import java.util.MissingResourceException;
|
||||
//
|
||||
//public class CustomItemsDataProvider extends ExternalDataProvider {
|
||||
//
|
||||
// private static final String FIELD_FACES = "faces";
|
||||
// private static final String METHOD_GET_MATERIAL = "getMaterial";
|
||||
//
|
||||
// private WrappedField<CustomMushroomBlock, Map<Integer, boolean[]>> mushroomFaces;
|
||||
// private WrappedReturningMethod<CustomMushroomBlock, SafeMaterial> mushroomMaterial;
|
||||
//
|
||||
// public CustomItemsDataProvider() {
|
||||
// super("CustomItems");
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void init() {
|
||||
// this.mushroomFaces = new WrappedField<>(CustomMushroomBlock.class, FIELD_FACES);
|
||||
// this.mushroomMaterial = new WrappedReturningMethod<>(CustomMushroomBlock.class, METHOD_GET_MATERIAL);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public BlockData getBlockData(Identifier blockId) throws MissingResourceException {
|
||||
// CustomItem item = CustomItem.get(blockId.key());
|
||||
// if(item == null) {
|
||||
// throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
// } else if(item.getBlockTexture().isSpawner()) {
|
||||
// throw new MissingResourceException("Iris does not yet support SpawnerBlocks from CustomItems.", blockId.namespace(), blockId.key());
|
||||
// } else if(item.getBlockTexture() != null && item.getBlockTexture().isValid()) {
|
||||
// throw new MissingResourceException("Tried to fetch BlockData for a CustomItem that is not placeable!", blockId.namespace(), blockId.key());
|
||||
// }
|
||||
// return getMushroomData(item);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public ItemStack getItemStack(Identifier itemId) throws MissingResourceException {
|
||||
// ItemStack stack = CustomItemsAPI.getCustomItem(itemId.key());
|
||||
// if(stack == null) {
|
||||
// throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
|
||||
// }
|
||||
// return stack;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Identifier[] getBlockTypes() {
|
||||
// KList<Identifier> names = new KList<>();
|
||||
// for (String name : CustomItemsAPI.listBlockCustomItemIDs()) {
|
||||
// try {
|
||||
// Identifier key = new Identifier("cui", name);
|
||||
// if (getItemStack(key) != null)
|
||||
// names.add(key);
|
||||
// } catch (MissingResourceException ignored) { }
|
||||
// }
|
||||
//
|
||||
// return names.toArray(new Identifier[0]);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Identifier[] getItemTypes() {
|
||||
// KList<Identifier> names = new KList<>();
|
||||
// for (String name : CustomItemsAPI.listCustomItemIDs()) {
|
||||
// try {
|
||||
// Identifier key = new Identifier("cui", name);
|
||||
// if (getItemStack(key) != null)
|
||||
// names.add(key);
|
||||
// } catch (MissingResourceException ignored) { }
|
||||
// }
|
||||
//
|
||||
// return names.toArray(new Identifier[0]);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean isValidProvider(Identifier key, boolean isItem) {
|
||||
// return key.namespace().equalsIgnoreCase("cui");
|
||||
// }
|
||||
//
|
||||
// private BlockData getMushroomData(CustomItem item) {
|
||||
// MultipleFacing data = (MultipleFacing)mushroomMaterial.invoke(item.getBlockTexture().getMushroomId()).parseMaterial().createBlockData();
|
||||
// boolean[] values = mushroomFaces.get().get(item.getBlockTexture().getMushroomId());
|
||||
// data.setFace(BlockFace.DOWN, values[0]);
|
||||
// data.setFace(BlockFace.EAST, values[1]);
|
||||
// data.setFace(BlockFace.NORTH, values[2]);
|
||||
// data.setFace(BlockFace.SOUTH, values[3]);
|
||||
// data.setFace(BlockFace.UP, values[4]);
|
||||
// data.setFace(BlockFace.WEST, values[5]);
|
||||
// return data;
|
||||
// }
|
||||
//}
|
||||
@@ -1,72 +0,0 @@
|
||||
package com.volmit.iris.core.link;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.reflect.WrappedField;
|
||||
import com.willfp.ecoitems.items.EcoItem;
|
||||
import com.willfp.ecoitems.items.EcoItems;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
public class EcoItemsDataProvider extends ExternalDataProvider {
|
||||
private WrappedField<EcoItem, ItemStack> itemStack;
|
||||
private WrappedField<EcoItem, NamespacedKey> id;
|
||||
|
||||
public EcoItemsDataProvider() {
|
||||
super("EcoItems");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
Iris.info("Setting up EcoItems Link...");
|
||||
itemStack = new WrappedField<>(EcoItem.class, "_itemStack");
|
||||
if (this.itemStack.hasFailed()) {
|
||||
Iris.error("Failed to set up EcoItems Link: Unable to fetch ItemStack field!");
|
||||
}
|
||||
id = new WrappedField<>(EcoItem.class, "id");
|
||||
if (this.id.hasFailed()) {
|
||||
Iris.error("Failed to set up EcoItems Link: Unable to fetch id field!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException {
|
||||
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException {
|
||||
EcoItem item = EcoItems.INSTANCE.getByID(itemId.key());
|
||||
if (item == null) throw new MissingResourceException("Failed to find Item!", itemId.namespace(), itemId.key());
|
||||
return itemStack.get(item).clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getBlockTypes() {
|
||||
return new Identifier[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getItemTypes() {
|
||||
KList<Identifier> names = new KList<>();
|
||||
for (EcoItem item : EcoItems.INSTANCE.values()) {
|
||||
try {
|
||||
Identifier key = Identifier.fromNamespacedKey(id.get(item));
|
||||
if (getItemStack(key) != null)
|
||||
names.add(key);
|
||||
} catch (MissingResourceException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return names.toArray(new Identifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidProvider(Identifier id, boolean isItem) {
|
||||
return id.namespace().equalsIgnoreCase("ecoitems") && isItem;
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.volmit.iris.core.link;
|
||||
|
||||
import com.ssomar.score.api.executableitems.ExecutableItemsAPI;
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ExecutableItemsDataProvider extends ExternalDataProvider {
|
||||
public ExecutableItemsDataProvider() {
|
||||
super("ExecutableItems");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
Iris.info("Setting up ExecutableItems Link...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException {
|
||||
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException {
|
||||
return ExecutableItemsAPI.getExecutableItemsManager().getExecutableItem(itemId.key())
|
||||
.map(item -> item.buildItem(1, Optional.empty()))
|
||||
.orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getBlockTypes() {
|
||||
return new Identifier[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getItemTypes() {
|
||||
KList<Identifier> names = new KList<>();
|
||||
for (String name : ExecutableItemsAPI.getExecutableItemsManager().getExecutableItemIdsList()) {
|
||||
try {
|
||||
Identifier key = new Identifier("executable_items", name);
|
||||
if (getItemStack(key) != null)
|
||||
names.add(key);
|
||||
} catch (MissingResourceException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return names.toArray(new Identifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidProvider(Identifier key, boolean isItem) {
|
||||
return key.namespace().equalsIgnoreCase("executable_items") && isItem;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.volmit.iris.core.link;
|
||||
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.Block;
|
||||
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 isReady() {
|
||||
return getPlugin() != null && getPlugin().isEnabled();
|
||||
}
|
||||
|
||||
public abstract void init();
|
||||
|
||||
public BlockData getBlockData(Identifier blockId) throws MissingResourceException {
|
||||
return getBlockData(blockId, new KMap<>());
|
||||
}
|
||||
|
||||
public abstract BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException;
|
||||
|
||||
public ItemStack getItemStack(Identifier itemId) throws MissingResourceException {
|
||||
return getItemStack(itemId, new KMap<>());
|
||||
}
|
||||
|
||||
public abstract ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException;
|
||||
|
||||
public void processUpdate(Engine engine, Block block, Identifier blockId) {}
|
||||
|
||||
public abstract Identifier[] getBlockTypes();
|
||||
|
||||
public abstract Identifier[] getItemTypes();
|
||||
|
||||
public abstract boolean isValidProvider(Identifier id, boolean isItem);
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
package com.volmit.iris.core.link;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.service.ExternalDataSVC;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.data.IrisBlockData;
|
||||
import com.volmit.iris.util.reflect.WrappedField;
|
||||
import com.volmit.iris.util.reflect.WrappedReturningMethod;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Leaves;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class HMCLeavesDataProvider extends ExternalDataProvider {
|
||||
private Object apiInstance;
|
||||
private WrappedReturningMethod<Object, Material> worldBlockType;
|
||||
private WrappedReturningMethod<Object, Boolean> setCustomBlock;
|
||||
private Map<String, Object> blockDataMap = Map.of();
|
||||
private Map<String, Supplier<ItemStack>> itemDataField = Map.of();
|
||||
|
||||
public HMCLeavesDataProvider() {
|
||||
super("HMCLeaves");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginId() {
|
||||
return "HMCLeaves";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
try {
|
||||
worldBlockType = new WrappedReturningMethod<>((Class<Object>) Class.forName("io.github.fisher2911.hmcleaves.data.BlockData"), "worldBlockType");
|
||||
apiInstance = getApiInstance(Class.forName("io.github.fisher2911.hmcleaves.api.HMCLeavesAPI"));
|
||||
setCustomBlock = new WrappedReturningMethod<>((Class<Object>) apiInstance.getClass(), "setCustomBlock", Location.class, String.class, boolean.class);
|
||||
Object config = getLeavesConfig(apiInstance.getClass());
|
||||
blockDataMap = getMap(config, "blockDataMap");
|
||||
itemDataField = getMap(config, "itemSupplierMap");
|
||||
} catch (Throwable e) {
|
||||
Iris.error("Failed to initialize HMCLeavesDataProvider: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException {
|
||||
Object o = blockDataMap.get(blockId.key());
|
||||
if (o == null)
|
||||
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
Material material = worldBlockType.invoke(o, new Object[0]);
|
||||
if (material == null)
|
||||
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
BlockData blockData = Bukkit.createBlockData(material);
|
||||
if (IrisSettings.get().getGenerator().preventLeafDecay && blockData instanceof Leaves leaves)
|
||||
leaves.setPersistent(true);
|
||||
return new IrisBlockData(blockData, ExternalDataSVC.buildState(blockId, state));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException {
|
||||
if (!itemDataField.containsKey(itemId.key()))
|
||||
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
|
||||
return itemDataField.get(itemId.key()).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processUpdate(Engine engine, Block block, Identifier blockId) {
|
||||
var pair = ExternalDataSVC.parseState(blockId);
|
||||
blockId = pair.getA();
|
||||
Boolean result = setCustomBlock.invoke(apiInstance, new Object[]{block.getLocation(), blockId.key(), false});
|
||||
if (result == null || !result)
|
||||
Iris.warn("Failed to set custom block! " + blockId.key() + " " + block.getX() + " " + block.getY() + " " + block.getZ());
|
||||
else if (IrisSettings.get().getGenerator().preventLeafDecay) {
|
||||
BlockData blockData = block.getBlockData();
|
||||
if (blockData instanceof Leaves leaves)
|
||||
leaves.setPersistent(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getBlockTypes() {
|
||||
KList<Identifier> names = new KList<>();
|
||||
for (String name : blockDataMap.keySet()) {
|
||||
try {
|
||||
Identifier key = new Identifier("hmcleaves", name);
|
||||
if (getBlockData(key) != null)
|
||||
names.add(key);
|
||||
} catch (MissingResourceException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return names.toArray(new Identifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getItemTypes() {
|
||||
KList<Identifier> names = new KList<>();
|
||||
for (String name : itemDataField.keySet()) {
|
||||
try {
|
||||
Identifier key = new Identifier("hmcleaves", name);
|
||||
if (getItemStack(key) != null)
|
||||
names.add(key);
|
||||
} catch (MissingResourceException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return names.toArray(new Identifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidProvider(Identifier id, boolean isItem) {
|
||||
return (isItem ? itemDataField.keySet() : blockDataMap.keySet()).contains(id.key());
|
||||
}
|
||||
|
||||
private <C, T> Map<String, T> getMap(C config, String name) {
|
||||
WrappedField<C, Map<String, T>> field = new WrappedField<>((Class<C>) config.getClass(), name);
|
||||
return field.get(config);
|
||||
}
|
||||
|
||||
private <A> A getApiInstance(Class<A> apiClass) {
|
||||
WrappedReturningMethod<A, A> instance = new WrappedReturningMethod<>(apiClass, "getInstance");
|
||||
return instance.invoke();
|
||||
}
|
||||
|
||||
private <A, C> C getLeavesConfig(Class<A> apiClass) {
|
||||
WrappedReturningMethod<A, A> instance = new WrappedReturningMethod<>(apiClass, "getInstance");
|
||||
WrappedField<A, C> config = new WrappedField<>(apiClass, "config");
|
||||
return config.get(instance.invoke());
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.volmit.iris.core.link;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
|
||||
public record Identifier(String namespace, String key) {
|
||||
|
||||
private static final String DEFAULT_NAMESPACE = "minecraft";
|
||||
|
||||
public static Identifier fromNamespacedKey(NamespacedKey key) {
|
||||
return new Identifier(key.getNamespace(), key.getKey());
|
||||
}
|
||||
|
||||
public static Identifier fromString(String id) {
|
||||
String[] strings = id.split(":", 2);
|
||||
if (strings.length == 1) {
|
||||
return new Identifier(DEFAULT_NAMESPACE, strings[0]);
|
||||
} else {
|
||||
return new Identifier(strings[0], strings[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return namespace + ":" + key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Identifier i) {
|
||||
return i.namespace().equals(this.namespace) && i.key().equals(this.key);
|
||||
} else if (obj instanceof NamespacedKey i) {
|
||||
return i.getNamespace().equals(this.namespace) && i.getKey().equals(this.key);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,116 +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.object.IrisBiome;
|
||||
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
// See/update https://app.gitbook.com/@volmitsoftware/s/iris/compatability/papi/
|
||||
public class IrisPapiExpansion extends PlaceholderExpansion {
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return "iris";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getAuthor() {
|
||||
return "Volmit Software";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getVersion() {
|
||||
return Iris.instance.getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persist() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onRequest(OfflinePlayer player, String p) {
|
||||
Location l = null;
|
||||
PlatformChunkGenerator a = null;
|
||||
|
||||
if (player.isOnline() && player.getPlayer() != null) {
|
||||
l = player.getPlayer().getLocation().add(0, 2, 0);
|
||||
a = IrisToolbelt.access(l.getWorld());
|
||||
}
|
||||
|
||||
if (p.equalsIgnoreCase("biome_name")) {
|
||||
if (a != null) {
|
||||
return getBiome(a, l).getName();
|
||||
}
|
||||
} else if (p.equalsIgnoreCase("biome_id")) {
|
||||
if (a != null) {
|
||||
return getBiome(a, l).getLoadKey();
|
||||
}
|
||||
} else if (p.equalsIgnoreCase("biome_file")) {
|
||||
if (a != null) {
|
||||
return getBiome(a, 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;
|
||||
}
|
||||
|
||||
private IrisBiome getBiome(PlatformChunkGenerator a, Location l) {
|
||||
return a.getEngine().getBiome(l.getBlockX(), l.getBlockY() - l.getWorld().getMinHeight(), l.getBlockZ());
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.volmit.iris.core.link;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import dev.lone.itemsadder.api.CustomBlock;
|
||||
import dev.lone.itemsadder.api.CustomStack;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
public class ItemAdderDataProvider extends ExternalDataProvider {
|
||||
|
||||
private KList<String> itemNamespaces, blockNamespaces;
|
||||
|
||||
public ItemAdderDataProvider() {
|
||||
super("ItemsAdder");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
this.itemNamespaces = new KList<>();
|
||||
this.blockNamespaces = new KList<>();
|
||||
|
||||
for (Identifier i : getItemTypes()) {
|
||||
itemNamespaces.addIfMissing(i.namespace());
|
||||
}
|
||||
for (Identifier i : getBlockTypes()) {
|
||||
blockNamespaces.addIfMissing(i.namespace());
|
||||
Iris.info("Found ItemAdder Block: " + i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException {
|
||||
return CustomBlock.getBaseBlockData(blockId.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException {
|
||||
CustomStack stack = CustomStack.getInstance(itemId.toString());
|
||||
if (stack == null) {
|
||||
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
|
||||
}
|
||||
return stack.getItemStack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getBlockTypes() {
|
||||
KList<Identifier> keys = new KList<>();
|
||||
for (String s : CustomBlock.getNamespacedIdsInRegistry()) {
|
||||
keys.add(Identifier.fromString(s));
|
||||
}
|
||||
return keys.toArray(new Identifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getItemTypes() {
|
||||
KList<Identifier> keys = new KList<>();
|
||||
for (String s : CustomStack.getNamespacedIdsInRegistry()) {
|
||||
keys.add(Identifier.fromString(s));
|
||||
}
|
||||
return keys.toArray(new Identifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidProvider(Identifier id, boolean isItem) {
|
||||
return isItem ? this.itemNamespaces.contains(id.namespace()) : this.blockNamespaces.contains(id.namespace());
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
package com.volmit.iris.core.link;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.ItemTier;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.block.CustomBlock;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class MMOItemsDataProvider extends ExternalDataProvider {
|
||||
|
||||
public MMOItemsDataProvider() {
|
||||
super("MMOItems");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
Iris.info("Setting up MMOItems Link...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException {
|
||||
int id = -1;
|
||||
try {
|
||||
id = Integer.parseInt(blockId.key());
|
||||
} catch (NumberFormatException ignored) {}
|
||||
CustomBlock block = api().getCustomBlocks().getBlock(id);
|
||||
if (block == null) throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
return block.getState().getBlockData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException {
|
||||
String[] parts = itemId.namespace().split("_", 2);
|
||||
if (parts.length != 2)
|
||||
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
|
||||
CompletableFuture<ItemStack> future = new CompletableFuture<>();
|
||||
Runnable run = () -> {
|
||||
try {
|
||||
var type = api().getTypes().get(parts[1]);
|
||||
int level = -1;
|
||||
ItemTier tier = null;
|
||||
|
||||
if (customNbt != null) {
|
||||
level = (int) customNbt.getOrDefault("level", -1);
|
||||
tier = api().getTiers().get(String.valueOf(customNbt.get("tier")));
|
||||
}
|
||||
|
||||
ItemStack itemStack;
|
||||
if (type == null) {
|
||||
future.complete(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (level != -1 && tier != null) {
|
||||
itemStack = api().getItem(type, itemId.key(), level, tier);
|
||||
} else {
|
||||
itemStack = api().getItem(type, itemId.key());
|
||||
}
|
||||
future.complete(itemStack);
|
||||
} catch (Throwable e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
};
|
||||
if (Bukkit.isPrimaryThread()) run.run();
|
||||
else J.s(run);
|
||||
ItemStack item = null;
|
||||
try {
|
||||
item = future.get();
|
||||
} catch (InterruptedException | ExecutionException ignored) {}
|
||||
if (item == null)
|
||||
throw new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key());
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getBlockTypes() {
|
||||
KList<Identifier> names = new KList<>();
|
||||
for (Integer id : api().getCustomBlocks().getBlockIds()) {
|
||||
try {
|
||||
Identifier key = new Identifier("mmoitems", String.valueOf(id));
|
||||
if (getBlockData(key) != null)
|
||||
names.add(key);
|
||||
} catch (MissingResourceException ignored) {
|
||||
}
|
||||
}
|
||||
return names.toArray(new Identifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getItemTypes() {
|
||||
KList<Identifier> names = new KList<>();
|
||||
Runnable run = () -> {
|
||||
for (Type type : api().getTypes().getAll()) {
|
||||
for (String name : api().getTemplates().getTemplateNames(type)) {
|
||||
try {
|
||||
Identifier key = new Identifier("mmoitems_" + type.getId(), name);
|
||||
if (getItemStack(key) != null)
|
||||
names.add(key);
|
||||
} catch (MissingResourceException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Bukkit.isPrimaryThread()) run.run();
|
||||
else {
|
||||
try {
|
||||
J.sfut(run).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
Iris.error("Failed getting MMOItems item types!");
|
||||
Iris.reportError(e);
|
||||
}
|
||||
}
|
||||
return names.toArray(new Identifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidProvider(Identifier id, boolean isItem) {
|
||||
return isItem ? id.namespace().split("_", 2).length == 2 : id.namespace().equals("mmoitems");
|
||||
}
|
||||
|
||||
private MMOItems api() {
|
||||
return MMOItems.plugin;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,166 +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.nms.INMS;
|
||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||
import com.volmit.iris.core.service.ExternalDataSVC;
|
||||
import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
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.data.IrisBlockData;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import io.lumine.mythic.bukkit.BukkitAdapter;
|
||||
import io.lumine.mythic.bukkit.utils.serialize.Chroma;
|
||||
import io.lumine.mythiccrucible.MythicCrucible;
|
||||
import io.lumine.mythiccrucible.items.CrucibleItem;
|
||||
import io.lumine.mythiccrucible.items.ItemManager;
|
||||
import io.lumine.mythiccrucible.items.blocks.CustomBlockItemContext;
|
||||
import io.lumine.mythiccrucible.items.furniture.FurnitureItemContext;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Optional;
|
||||
|
||||
public class MythicCrucibleDataProvider extends ExternalDataProvider {
|
||||
|
||||
private ItemManager itemManager;
|
||||
|
||||
public MythicCrucibleDataProvider() {
|
||||
super("MythicCrucible");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
Iris.info("Setting up MythicCrucible Link...");
|
||||
try {
|
||||
this.itemManager = MythicCrucible.inst().getItemManager();
|
||||
} catch (Exception e) {
|
||||
Iris.error("Failed to set up MythicCrucible Link: Unable to fetch MythicCrucible instance!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException {
|
||||
CrucibleItem crucibleItem = this.itemManager.getItem(blockId.key())
|
||||
.orElseThrow(() -> new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key()));
|
||||
CustomBlockItemContext blockItemContext = crucibleItem.getBlockData();
|
||||
FurnitureItemContext furnitureItemContext = crucibleItem.getFurnitureData();
|
||||
if (furnitureItemContext != null) {
|
||||
return new IrisBlockData(B.getAir(), ExternalDataSVC.buildState(blockId, state));
|
||||
} else if (blockItemContext != null) {
|
||||
return blockItemContext.getBlockData();
|
||||
}
|
||||
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException {
|
||||
Optional<CrucibleItem> opt = this.itemManager.getItem(itemId.key());
|
||||
return BukkitAdapter.adapt(opt.orElseThrow(() ->
|
||||
new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key()))
|
||||
.getMythicItem()
|
||||
.generateItemStack(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getBlockTypes() {
|
||||
KList<Identifier> names = new KList<>();
|
||||
for (CrucibleItem item : this.itemManager.getItems()) {
|
||||
if (item.getBlockData() == null) continue;
|
||||
try {
|
||||
Identifier key = new Identifier("crucible", item.getInternalName());
|
||||
if (getBlockData(key) != null) {
|
||||
Iris.info("getBlockTypes: Block loaded '" + item.getInternalName() + "'");
|
||||
names.add(key);
|
||||
}
|
||||
} catch (MissingResourceException ignored) {}
|
||||
}
|
||||
return names.toArray(new Identifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getItemTypes() {
|
||||
KList<Identifier> names = new KList<>();
|
||||
for (CrucibleItem item : this.itemManager.getItems()) {
|
||||
try {
|
||||
Identifier key = new Identifier("crucible", item.getInternalName());
|
||||
if (getItemStack(key) != null) {
|
||||
Iris.info("getItemTypes: Item loaded '" + item.getInternalName() + "'");
|
||||
names.add(key);
|
||||
}
|
||||
} catch (MissingResourceException ignored) {}
|
||||
}
|
||||
return names.toArray(new Identifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processUpdate(Engine engine, Block block, Identifier blockId) {
|
||||
var pair = ExternalDataSVC.parseState(blockId);
|
||||
var state = pair.getB();
|
||||
blockId = pair.getA();
|
||||
|
||||
Optional<CrucibleItem> item = itemManager.getItem(blockId.key());
|
||||
if (item.isEmpty()) return;
|
||||
FurnitureItemContext furniture = item.get().getFurnitureData();
|
||||
if (furniture == null) return;
|
||||
|
||||
float yaw = 0;
|
||||
BlockFace face = BlockFace.NORTH;
|
||||
long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY();
|
||||
RNG rng = new RNG(seed);
|
||||
if ("true".equals(state.get("randomYaw"))) {
|
||||
yaw = rng.f(0, 360);
|
||||
} else if (state.containsKey("yaw")) {
|
||||
yaw = Float.parseFloat(state.get("yaw"));
|
||||
}
|
||||
if ("true".equals(state.get("randomFace"))) {
|
||||
BlockFace[] faces = BlockFace.values();
|
||||
face = faces[rng.i(0, faces.length - 1)];
|
||||
} else if (state.containsKey("face")) {
|
||||
face = BlockFace.valueOf(state.get("face").toUpperCase());
|
||||
}
|
||||
if (face == BlockFace.SELF) {
|
||||
face = BlockFace.NORTH;
|
||||
}
|
||||
|
||||
BiomeColor type = null;
|
||||
Chroma color = null;
|
||||
try {
|
||||
type = BiomeColor.valueOf(state.get("matchBiome").toUpperCase());
|
||||
} catch (NullPointerException | IllegalArgumentException ignored) {}
|
||||
if (type != null) {
|
||||
var biomeColor = INMS.get().getBiomeColor(block.getLocation(), type);
|
||||
if (biomeColor == null) return;
|
||||
color = Chroma.of(biomeColor.getRGB());
|
||||
}
|
||||
furniture.place(block, face, yaw, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidProvider(Identifier key, boolean isItem) {
|
||||
return key.namespace().equalsIgnoreCase("crucible");
|
||||
}
|
||||
}
|
||||
@@ -1,59 +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 io.lumine.mythic.bukkit.MythicBukkit;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
|
||||
public class MythicMobsLink {
|
||||
|
||||
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) {
|
||||
return isEnabled() ? MythicBukkit.inst().getMobManager().spawnMob(mob, location).getEntity().getBukkitEntity() : null;
|
||||
}
|
||||
|
||||
public Collection<String> getMythicMobTypes() {
|
||||
return isEnabled() ? MythicBukkit.inst().getMobManager().getMobNames() : null;
|
||||
}
|
||||
}
|
||||
@@ -1,213 +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.nms.INMS;
|
||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||
import com.volmit.iris.core.service.ExternalDataSVC;
|
||||
import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
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.data.IrisBlockData;
|
||||
import com.volmit.iris.util.math.RNG;
|
||||
import com.volmit.iris.util.reflect.WrappedField;
|
||||
import io.th0rgal.oraxen.api.OraxenItems;
|
||||
import io.th0rgal.oraxen.items.ItemBuilder;
|
||||
import io.th0rgal.oraxen.mechanics.Mechanic;
|
||||
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.furniture.FurnitureFactory;
|
||||
import io.th0rgal.oraxen.mechanics.provided.gameplay.furniture.FurnitureMechanic;
|
||||
import io.th0rgal.oraxen.mechanics.provided.gameplay.noteblock.NoteBlockMechanicFactory;
|
||||
import io.th0rgal.oraxen.mechanics.provided.gameplay.stringblock.StringBlockMechanicFactory;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.MultipleFacing;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.ItemDisplay;
|
||||
import org.bukkit.entity.ItemFrame;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.PotionMeta;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class OraxenDataProvider extends ExternalDataProvider {
|
||||
|
||||
private static final String FIELD_FACTORIES_MAP = "FACTORIES_BY_MECHANIC_ID";
|
||||
|
||||
private WrappedField<MechanicsManager, Map<String, MechanicFactory>> factories;
|
||||
|
||||
public OraxenDataProvider() {
|
||||
super("Oraxen");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
Iris.info("Setting up Oraxen Link...");
|
||||
this.factories = new WrappedField<>(MechanicsManager.class, FIELD_FACTORIES_MAP);
|
||||
if (this.factories.hasFailed()) {
|
||||
Iris.error("Failed to set up Oraxen Link: Unable to fetch MechanicFactoriesMap!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData getBlockData(Identifier blockId, KMap<String, String> state) throws MissingResourceException {
|
||||
MechanicFactory factory = getFactory(blockId);
|
||||
if (factory instanceof NoteBlockMechanicFactory f)
|
||||
return f.createNoteBlockData(blockId.key());
|
||||
else if (factory instanceof BlockMechanicFactory f) {
|
||||
MultipleFacing newBlockData = (MultipleFacing) Bukkit.createBlockData(Material.MUSHROOM_STEM);
|
||||
BlockMechanic.setBlockFacing(newBlockData, ((BlockMechanic) f.getMechanic(blockId.key())).getCustomVariation());
|
||||
return newBlockData;
|
||||
} else if (factory instanceof StringBlockMechanicFactory f) {
|
||||
return f.createTripwireData(blockId.key());
|
||||
} else if (factory instanceof FurnitureFactory) {
|
||||
return new IrisBlockData(B.getAir(), ExternalDataSVC.buildState(blockId, state));
|
||||
} else
|
||||
throw new MissingResourceException("Failed to find BlockData!", blockId.namespace(), blockId.key());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack(Identifier itemId, KMap<String, Object> customNbt) throws MissingResourceException {
|
||||
Optional<ItemBuilder> opt = OraxenItems.getOptionalItemById(itemId.key());
|
||||
return opt.orElseThrow(() -> new MissingResourceException("Failed to find ItemData!", itemId.namespace(), itemId.key())).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processUpdate(Engine engine, Block block, Identifier blockId) {
|
||||
var pair = ExternalDataSVC.parseState(blockId);
|
||||
var state = pair.getB();
|
||||
blockId = pair.getA();
|
||||
Mechanic mechanic = getFactory(blockId).getMechanic(blockId.key());
|
||||
if (mechanic instanceof FurnitureMechanic f) {
|
||||
float yaw = 0;
|
||||
BlockFace face = BlockFace.NORTH;
|
||||
|
||||
long seed = engine.getSeedManager().getSeed() + Cache.key(block.getX(), block.getZ()) + block.getY();
|
||||
RNG rng = new RNG(seed);
|
||||
if ("true".equals(state.get("randomYaw"))) {
|
||||
yaw = rng.f(0, 360);
|
||||
} else if (state.containsKey("yaw")) {
|
||||
yaw = Float.parseFloat(state.get("yaw"));
|
||||
}
|
||||
if ("true".equals(state.get("randomFace"))) {
|
||||
BlockFace[] faces = BlockFace.values();
|
||||
face = faces[rng.i(0, faces.length - 1)];
|
||||
} else if (state.containsKey("face")) {
|
||||
face = BlockFace.valueOf(state.get("face").toUpperCase());
|
||||
}
|
||||
if (face == BlockFace.SELF) {
|
||||
face = BlockFace.NORTH;
|
||||
}
|
||||
ItemStack itemStack = OraxenItems.getItemById(f.getItemID()).build();
|
||||
Entity entity = f.place(block.getLocation(), itemStack, yaw, face, false);
|
||||
|
||||
Consumer<ItemStack> setter = null;
|
||||
if (entity instanceof ItemFrame frame) {
|
||||
itemStack = frame.getItem();
|
||||
setter = frame::setItem;
|
||||
} else if (entity instanceof ItemDisplay display) {
|
||||
itemStack = display.getItemStack();
|
||||
setter = display::setItemStack;
|
||||
}
|
||||
if (setter == null || itemStack == null) return;
|
||||
|
||||
BiomeColor type = null;
|
||||
try {
|
||||
type = BiomeColor.valueOf(state.get("matchBiome").toUpperCase());
|
||||
} catch (NullPointerException | IllegalArgumentException ignored) {}
|
||||
|
||||
if (type != null) {
|
||||
var biomeColor = INMS.get().getBiomeColor(block.getLocation(), type);
|
||||
if (biomeColor == null) return;
|
||||
var potionColor = Color.fromARGB(biomeColor.getAlpha(), biomeColor.getRed(), biomeColor.getGreen(), biomeColor.getBlue());
|
||||
if (itemStack.getItemMeta() instanceof PotionMeta meta) {
|
||||
meta.setColor(potionColor);
|
||||
itemStack.setItemMeta(meta);
|
||||
}
|
||||
}
|
||||
setter.accept(itemStack);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getBlockTypes() {
|
||||
KList<Identifier> names = new KList<>();
|
||||
for (String name : OraxenItems.getItemNames()) {
|
||||
try {
|
||||
Identifier key = new Identifier("oraxen", name);
|
||||
if (getBlockData(key) != null)
|
||||
names.add(key);
|
||||
} catch (MissingResourceException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return names.toArray(new Identifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier[] getItemTypes() {
|
||||
KList<Identifier> names = new KList<>();
|
||||
for (String name : OraxenItems.getItemNames()) {
|
||||
try {
|
||||
Identifier key = new Identifier("oraxen", name);
|
||||
if (getItemStack(key) != null)
|
||||
names.add(key);
|
||||
} catch (MissingResourceException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return names.toArray(new Identifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
if (super.isReady()) {
|
||||
if (factories == null) {
|
||||
this.factories = new WrappedField<>(MechanicsManager.class, FIELD_FACTORIES_MAP);
|
||||
}
|
||||
return super.isReady() && !factories.hasFailed();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidProvider(Identifier key, boolean isItem) {
|
||||
return key.namespace().equalsIgnoreCase("oraxen");
|
||||
}
|
||||
|
||||
private MechanicFactory getFactory(Identifier key) throws MissingResourceException {
|
||||
return factories.get().values().stream()
|
||||
.filter(i -> i.getItems().contains(key.key()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new MissingResourceException("Failed to find BlockData!", key.namespace(), key.key()));
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.volmit.iris.core.link;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.util.data.Cuboid;
|
||||
import com.volmit.iris.util.data.KCache;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.time.Duration;
|
||||
import java.util.UUID;
|
||||
|
||||
public class WorldEditLink {
|
||||
private static final AtomicCache<Boolean> active = new AtomicCache<>();
|
||||
|
||||
public static Cuboid getSelection(Player p) {
|
||||
if (!hasWorldEdit())
|
||||
return null;
|
||||
|
||||
try {
|
||||
Object instance = Class.forName("com.sk89q.worldedit.WorldEdit").getDeclaredMethod("getInstance").invoke(null);
|
||||
Object sessionManager = instance.getClass().getDeclaredMethod("getSessionManager").invoke(instance);
|
||||
Class<?> bukkitAdapter = Class.forName("com.sk89q.worldedit.bukkit.BukkitAdapter");
|
||||
Object world = bukkitAdapter.getDeclaredMethod("adapt", World.class).invoke(null, p.getWorld());
|
||||
Object player = bukkitAdapter.getDeclaredMethod("adapt", Player.class).invoke(null, p);
|
||||
Object localSession = sessionManager.getClass().getDeclaredMethod("getIfPresent", Class.forName("com.sk89q.worldedit.session.SessionOwner")).invoke(sessionManager, player);
|
||||
if (localSession == null) return null;
|
||||
|
||||
Object region = null;
|
||||
try {
|
||||
region = localSession.getClass().getDeclaredMethod("getSelection", Class.forName("com.sk89q.worldedit.world.World")).invoke(localSession, world);
|
||||
} catch (InvocationTargetException ignored) {}
|
||||
if (region == null) return null;
|
||||
|
||||
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("x").invoke(min),
|
||||
(int) min.getClass().getDeclaredMethod("y").invoke(min),
|
||||
(int) min.getClass().getDeclaredMethod("z").invoke(min),
|
||||
(int) min.getClass().getDeclaredMethod("x").invoke(max),
|
||||
(int) min.getClass().getDeclaredMethod("y").invoke(max),
|
||||
(int) min.getClass().getDeclaredMethod("z").invoke(max)
|
||||
);
|
||||
} catch (Throwable e) {
|
||||
Iris.error("Could not get selection");
|
||||
e.printStackTrace();
|
||||
active.reset();
|
||||
active.aquire(() -> false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean hasWorldEdit() {
|
||||
return active.aquire(() -> Bukkit.getPluginManager().isPluginEnabled("WorldEdit"));
|
||||
}
|
||||
}
|
||||
@@ -1,166 +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;
|
||||
import java.util.Set;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void getPNGFiles(File directory, Set<String> m) {
|
||||
for (File file : directory.listFiles()) {
|
||||
if (file.isFile() && file.getName().endsWith(".png")) {
|
||||
m.add(file.getName().replaceAll("\\Q.png\\E", ""));
|
||||
} else if (file.isDirectory()) {
|
||||
getPNGFiles(file, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String[] getPossibleKeys() {
|
||||
if (possibleKeys != null) {
|
||||
return possibleKeys;
|
||||
}
|
||||
|
||||
Iris.debug("Building " + resourceTypeName + " Possibility Lists");
|
||||
KSet<String> m = new KSet<>();
|
||||
|
||||
|
||||
for (File i : getFolders()) {
|
||||
getPNGFiles(i, m);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -1,501 +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.*;
|
||||
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.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
return g.substring(1).split("\\Q.\\E")[0];
|
||||
} 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;
|
||||
}
|
||||
|
||||
public void savePrefetch(Engine engine) {
|
||||
BurstExecutor b = MultiBurst.burst.burst(loaders.size());
|
||||
|
||||
for (ResourceLoader<?> i : loaders.values()) {
|
||||
b.queue(() -> {
|
||||
try {
|
||||
i.saveFirstAccess(engine);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
b.complete();
|
||||
Iris.info("Saved Prefetch Cache to speed up future world startups");
|
||||
}
|
||||
|
||||
public void loadPrefetch(Engine engine) {
|
||||
BurstExecutor b = MultiBurst.burst.burst(loaders.size());
|
||||
|
||||
for (ResourceLoader<?> i : loaders.values()) {
|
||||
b.queue(() -> {
|
||||
try {
|
||||
i.loadFirstAccess(engine);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
b.complete();
|
||||
Iris.info("Loaded Prefetch Cache to reduce generation disk use.");
|
||||
}
|
||||
}
|
||||
@@ -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.*;
|
||||
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);
|
||||
}
|
||||
@@ -1,176 +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> {
|
||||
private String[] possibleKeys;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private void findMatFiles(File dir, KSet<String> m) {
|
||||
for (File file : dir.listFiles()) {
|
||||
if (file.isFile() && file.getName().endsWith(".mat")) {
|
||||
m.add(file.getName().replaceAll("\\Q.mat\\E", ""));
|
||||
} else if (file.isDirectory()) {
|
||||
findMatFiles(file, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getPossibleKeys() {
|
||||
if (possibleKeys != null) {
|
||||
return possibleKeys;
|
||||
}
|
||||
|
||||
Iris.debug("Building " + resourceTypeName + " Possibility Lists");
|
||||
KSet<String> m = new KSet<>();
|
||||
|
||||
for (File folder : getFolders()) {
|
||||
findMatFiles(folder, m);
|
||||
}
|
||||
|
||||
KList<String> v = new KList<>(m);
|
||||
possibleKeys = v.toArray(new String[0]);
|
||||
return possibleKeys;
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -1,140 +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.setLoadKey(name);
|
||||
t.setLoader(manager);
|
||||
t.setLoadFile(j);
|
||||
t.read(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()) {
|
||||
m.addAll(getFiles(i, ".iob", true));
|
||||
}
|
||||
possibleKeys = m.toArray(new String[0]);
|
||||
return possibleKeys;
|
||||
}
|
||||
|
||||
private KList<String> getFiles(File dir, String ext, boolean skipDirName) {
|
||||
KList<String> paths = new KList<>();
|
||||
String name = skipDirName ? "" : dir.getName() + "/";
|
||||
for (File f : dir.listFiles()) {
|
||||
if (f.isFile() && f.getName().endsWith(ext)) {
|
||||
paths.add(name + f.getName().replaceAll("\\Q" + ext + "\\E", ""));
|
||||
} else if (f.isDirectory()) {
|
||||
getFiles(f, ext, false).forEach(e -> paths.add(name + e));
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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.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.Engine;
|
||||
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.CustomOutputStream;
|
||||
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.parallel.BurstExecutor;
|
||||
import com.volmit.iris.util.parallel.MultiBurst;
|
||||
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 lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.io.*;
|
||||
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;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(exclude = "manager")
|
||||
@ToString(exclude = "manager")
|
||||
public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
|
||||
public static final AtomicDouble tlt = new AtomicDouble(0);
|
||||
private static final int CACHE_SIZE = 100000;
|
||||
protected final AtomicReference<KList<File>> folderCache;
|
||||
protected KSet<String> firstAccess;
|
||||
protected File root;
|
||||
protected String folderName;
|
||||
protected String resourceTypeName;
|
||||
protected KCache<String, T> loadCache;
|
||||
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;
|
||||
firstAccess = new KSet<>();
|
||||
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> loadAllParallel(KList<String> s) {
|
||||
KList<T> m = new KList<>();
|
||||
BurstExecutor burst = MultiBurst.burst.burst(s.size());
|
||||
|
||||
for (String i : s) {
|
||||
burst.queue(() -> {
|
||||
T t = load(i);
|
||||
|
||||
if (t != null) {
|
||||
m.add(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
burst.complete();
|
||||
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;
|
||||
}
|
||||
|
||||
firstAccess.add(name);
|
||||
return loadCache.get(name);
|
||||
}
|
||||
|
||||
public void loadFirstAccess(Engine engine) throws IOException {
|
||||
String id = "DIM" + Math.abs(engine.getSeedManager().getSeed() + engine.getDimension().getVersion() + engine.getDimension().getLoadKey().hashCode());
|
||||
File file = Iris.instance.getDataFile("prefetch/" + id + "/" + Math.abs(getFolderName().hashCode()) + ".ipfch");
|
||||
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileInputStream fin = new FileInputStream(file);
|
||||
GZIPInputStream gzi = new GZIPInputStream(fin);
|
||||
DataInputStream din = new DataInputStream(gzi);
|
||||
int m = din.readInt();
|
||||
KList<String> s = new KList<>();
|
||||
|
||||
for (int i = 0; i < m; i++) {
|
||||
s.add(din.readUTF());
|
||||
}
|
||||
|
||||
din.close();
|
||||
file.deleteOnExit();
|
||||
Iris.info("Loading " + s.size() + " prefetch " + getFolderName());
|
||||
loadAllParallel(s);
|
||||
}
|
||||
|
||||
public void saveFirstAccess(Engine engine) throws IOException {
|
||||
String id = "DIM" + Math.abs(engine.getSeedManager().getSeed() + engine.getDimension().getVersion() + engine.getDimension().getLoadKey().hashCode());
|
||||
File file = Iris.instance.getDataFile("prefetch/" + id + "/" + Math.abs(getFolderName().hashCode()) + ".ipfch");
|
||||
file.getParentFile().mkdirs();
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
GZIPOutputStream gzo = new CustomOutputStream(fos, 9);
|
||||
DataOutputStream dos = new DataOutputStream(gzo);
|
||||
dos.writeInt(firstAccess.size());
|
||||
|
||||
for (String i : firstAccess) {
|
||||
dos.writeUTF(i);
|
||||
}
|
||||
|
||||
dos.flush();
|
||||
dos.close();
|
||||
}
|
||||
|
||||
public KList<File> getFolders() {
|
||||
synchronized (folderCache) {
|
||||
if (folderCache.get() == null) {
|
||||
KList<File> fc = new KList<>();
|
||||
|
||||
File[] files = root.listFiles();
|
||||
if (files == null) {
|
||||
throw new IllegalStateException("Failed to list files in " + root);
|
||||
}
|
||||
|
||||
for (File i : files) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,170 +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.data.KCache;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
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");
|
||||
Set<String> keys = new HashSet<>();
|
||||
|
||||
for (File i : getFolders()) {
|
||||
if (i.isDirectory()) {
|
||||
keys.addAll(getKeysInDirectory(i));
|
||||
}
|
||||
}
|
||||
|
||||
possibleKeys = keys.toArray(new String[0]);
|
||||
return possibleKeys;
|
||||
}
|
||||
|
||||
private Set<String> getKeysInDirectory(File directory) {
|
||||
Set<String> keys = new HashSet<>();
|
||||
for (File file : directory.listFiles()) {
|
||||
if (file.isFile() && file.getName().endsWith(".js")) {
|
||||
keys.add(file.getName().replaceAll("\\Q.js\\E", ""));
|
||||
} else if (file.isDirectory()) {
|
||||
keys.addAll(getKeysInDirectory(file));
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.volmit.iris.core.nms;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
|
||||
public interface IMemoryWorld extends Listener, AutoCloseable {
|
||||
|
||||
World getBukkit();
|
||||
|
||||
Chunk getChunk(int x, int z);
|
||||
|
||||
ChunkGenerator.ChunkData getChunkData(int x, int z);
|
||||
}
|
||||
@@ -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.nms;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class INMS {
|
||||
private static final Map<String, String> REVISION = Map.of(
|
||||
"1.20.5", "v1_20_R4",
|
||||
"1.20.6", "v1_20_R4",
|
||||
"1.21", "v1_21_R1",
|
||||
"1.21.1", "v1_21_R1"
|
||||
);
|
||||
//@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 {
|
||||
String name = Bukkit.getServer().getClass().getCanonicalName();
|
||||
if (name.equals("org.bukkit.craftbukkit.CraftServer")) {
|
||||
return REVISION.getOrDefault(Bukkit.getServer().getBukkitVersion().split("-")[0], "BUKKIT");
|
||||
} else {
|
||||
return name.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);
|
||||
|
||||
try {
|
||||
Class<?> clazz = Class.forName("com.volmit.iris.core.nms."+code+".NMSBinding");
|
||||
try {
|
||||
Object b = clazz.getConstructor().newInstance();
|
||||
if (b instanceof INMSBinding binding) {
|
||||
Iris.info("Craftbukkit " + code + " <-> " + b.getClass().getSimpleName() + " Successfully Bound");
|
||||
return binding;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (ClassNotFoundException|NoClassDefFoundError classNotFoundException) {}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,151 +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.nms.container.BiomeColor;
|
||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.math.Vector3d;
|
||||
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.*;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Dolphin;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.generator.structure.Structure;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Color;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface INMSBinding {
|
||||
boolean hasTile(Material material);
|
||||
|
||||
boolean hasTile(Location l);
|
||||
|
||||
KMap<String, Object> serializeTile(Location location);
|
||||
|
||||
void deserializeTile(KMap<String, Object> 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);
|
||||
|
||||
int getBiomeBaseIdForKey(String key);
|
||||
|
||||
String getKeyForBiomeBase(Object biomeBase);
|
||||
|
||||
Object getBiomeBase(World world, Biome biome);
|
||||
|
||||
Object getBiomeBase(Object registry, Biome biome);
|
||||
|
||||
KList<Biome> getBiomes();
|
||||
|
||||
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();
|
||||
|
||||
default boolean setBlock(World world, int x, int y, int z, BlockData data, int flag, int updateDepth) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk);
|
||||
|
||||
default boolean supportsDataPacks() {
|
||||
return false;
|
||||
}
|
||||
|
||||
MCAPaletteAccess createPalette();
|
||||
|
||||
void injectBiomesFromMantle(Chunk e, Mantle mantle);
|
||||
|
||||
ItemStack applyCustomNbt(ItemStack itemStack, KMap<String, Object> customNbt) throws IllegalArgumentException;
|
||||
|
||||
void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException;
|
||||
|
||||
Vector3d getBoundingbox(org.bukkit.entity.EntityType entity);
|
||||
|
||||
Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason);
|
||||
|
||||
Color getBiomeColor(Location location, BiomeColor type);
|
||||
|
||||
default DataVersion getDataVersion() {
|
||||
return DataVersion.V1192;
|
||||
}
|
||||
|
||||
default int getSpawnChunkCount(World world) {
|
||||
return 441;
|
||||
}
|
||||
|
||||
KList<String> getStructureKeys();
|
||||
|
||||
default BlockData getBlockData(CompoundTag tag) {
|
||||
Iris.error("Unsupported version!");
|
||||
return null;
|
||||
};
|
||||
|
||||
default IMemoryWorld createMemoryWorld(WorldCreator creator) throws IOException {
|
||||
return createMemoryWorld(switch (creator.environment()) {
|
||||
case NORMAL -> NamespacedKey.minecraft("overworld");
|
||||
case NETHER -> NamespacedKey.minecraft("the_nether");
|
||||
case THE_END -> NamespacedKey.minecraft("the_end");
|
||||
default -> throw new IllegalArgumentException("Illegal dimension (" + creator.environment() + ")");
|
||||
}, creator);
|
||||
}
|
||||
|
||||
IMemoryWorld createMemoryWorld(NamespacedKey levelType, WorldCreator creator) throws IOException;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.volmit.iris.core.nms.container;
|
||||
|
||||
public enum BiomeColor {
|
||||
FOG,
|
||||
WATER,
|
||||
WATER_FOG,
|
||||
SKY,
|
||||
FOLIAGE,
|
||||
GRASS
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.volmit.iris.core.nms.container;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class BlockPos {
|
||||
private int x;
|
||||
private int y;
|
||||
private int z;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.volmit.iris.core.nms.container;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Pair<A, B> {
|
||||
private A a;
|
||||
private B b;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.volmit.iris.core.nms.datapack;
|
||||
|
||||
import com.volmit.iris.core.nms.INMS;
|
||||
import com.volmit.iris.core.nms.datapack.v1192.DataFixerV1192;
|
||||
import com.volmit.iris.core.nms.datapack.v1206.DataFixerV1206;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
//https://minecraft.wiki/w/Pack_format
|
||||
@Getter
|
||||
public enum DataVersion {
|
||||
V1192("1.19.2", 10, DataFixerV1192::new),
|
||||
V1205("1.20.6", 41, DataFixerV1206::new);
|
||||
private static final KMap<DataVersion, IDataFixer> cache = new KMap<>();
|
||||
@Getter(AccessLevel.NONE)
|
||||
private final Supplier<IDataFixer> constructor;
|
||||
private final String version;
|
||||
private final int packFormat;
|
||||
|
||||
DataVersion(String version, int packFormat, Supplier<IDataFixer> constructor) {
|
||||
this.constructor = constructor;
|
||||
this.packFormat = packFormat;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public IDataFixer get() {
|
||||
return cache.computeIfAbsent(this, k -> constructor.get());
|
||||
}
|
||||
|
||||
public static IDataFixer getDefault() {
|
||||
return INMS.get().getDataVersion().get();
|
||||
}
|
||||
|
||||
public static DataVersion getLatest() {
|
||||
return values()[values().length - 1];
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.volmit.iris.core.nms.datapack;
|
||||
|
||||
import com.volmit.iris.engine.object.IrisBiomeCustom;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
|
||||
public interface IDataFixer {
|
||||
|
||||
JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json);
|
||||
|
||||
JSONObject fixDimension(JSONObject json);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.volmit.iris.core.nms.datapack.v1192;
|
||||
|
||||
import com.volmit.iris.core.nms.datapack.IDataFixer;
|
||||
import com.volmit.iris.engine.object.IrisBiomeCustom;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
|
||||
public class DataFixerV1192 implements IDataFixer {
|
||||
|
||||
@Override
|
||||
public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject fixDimension(JSONObject json) {
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.volmit.iris.core.nms.datapack.v1206;
|
||||
|
||||
import com.volmit.iris.core.nms.datapack.IDataFixer;
|
||||
import com.volmit.iris.engine.object.IrisBiomeCustom;
|
||||
import com.volmit.iris.engine.object.IrisBiomeCustomSpawn;
|
||||
import com.volmit.iris.engine.object.IrisBiomeCustomSpawnType;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.json.JSONArray;
|
||||
import com.volmit.iris.util.json.JSONObject;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class DataFixerV1206 implements IDataFixer {
|
||||
@Override
|
||||
public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
|
||||
int spawnRarity = biome.getSpawnRarity();
|
||||
if (spawnRarity > 0) {
|
||||
json.put("creature_spawn_probability", Math.min(spawnRarity/20d, 0.9999999));
|
||||
}
|
||||
|
||||
var spawns = biome.getSpawns();
|
||||
if (spawns != null && spawns.isNotEmpty()) {
|
||||
JSONObject spawners = new JSONObject();
|
||||
KMap<IrisBiomeCustomSpawnType, JSONArray> groups = new KMap<>();
|
||||
|
||||
for (IrisBiomeCustomSpawn i : spawns) {
|
||||
JSONArray g = groups.computeIfAbsent(i.getGroup(), (k) -> new JSONArray());
|
||||
JSONObject o = new JSONObject();
|
||||
o.put("type", "minecraft:" + i.getType().name().toLowerCase());
|
||||
o.put("weight", i.getWeight());
|
||||
o.put("minCount", Math.min(i.getMinCount()/20d, 0));
|
||||
o.put("maxCount", Math.min(i.getMaxCount()/20d, 0.9999999));
|
||||
g.put(o);
|
||||
}
|
||||
|
||||
for (IrisBiomeCustomSpawnType i : groups.k()) {
|
||||
spawners.put(i.name().toLowerCase(Locale.ROOT), groups.get(i));
|
||||
}
|
||||
|
||||
json.put("spawners", spawners);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject fixDimension(JSONObject json) {
|
||||
if (!(json.get("monster_spawn_light_level") instanceof JSONObject lightLevel))
|
||||
return json;
|
||||
var value = (JSONObject) lightLevel.remove("value");
|
||||
lightLevel.put("max_inclusive", value.get("max_inclusive"));
|
||||
lightLevel.put("min_inclusive", value.get("min_inclusive"));
|
||||
return json;
|
||||
}
|
||||
}
|
||||
@@ -1,254 +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.IMemoryWorld;
|
||||
import com.volmit.iris.core.nms.INMSBinding;
|
||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||
import com.volmit.iris.core.nms.container.BlockPos;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.util.collection.KList;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.math.Vector3d;
|
||||
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.*;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Dolphin;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.generator.structure.Structure;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Color;
|
||||
import java.io.IOException;
|
||||
|
||||
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(Material material) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTile(Location l) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMap<String, Object> serializeTile(Location location) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeTile(KMap<String, Object> s, Location newPosition) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void injectBiomesFromMantle(Chunk e, Mantle mantle) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack applyCustomNbt(ItemStack itemStack, KMap<String, Object> customNbt) throws IllegalArgumentException {
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
|
||||
|
||||
}
|
||||
|
||||
public Vector3d getBoundingbox() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason) {
|
||||
return location.getWorld().spawnEntity(location, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getBiomeColor(Location location, BiomeColor type) {
|
||||
return Color.GREEN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KList<String> getStructureKeys() {
|
||||
var list = Registry.STRUCTURE.stream()
|
||||
.map(Structure::getKey)
|
||||
.map(NamespacedKey::toString)
|
||||
.toList();
|
||||
return new KList<>(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMemoryWorld createMemoryWorld(NamespacedKey levelType, WorldCreator creator) throws IOException {
|
||||
throw new IOException("Unsupported version!");
|
||||
}
|
||||
|
||||
@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 int getBiomeBaseIdForKey(String key) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@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 KList<Biome> getBiomes() {
|
||||
return new KList<>(Biome.values()).qdel(Biome.CUSTOM);
|
||||
}
|
||||
|
||||
@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 Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@@ -1,384 +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;
|
||||
}
|
||||
}
|
||||
@@ -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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
package com.volmit.iris.core.pregenerator;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.nms.container.Pair;
|
||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||
import com.volmit.iris.engine.data.cache.Cache;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.format.Form;
|
||||
import com.volmit.iris.util.mantle.MantleFlag;
|
||||
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.profile.LoadBalancer;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class ChunkUpdater {
|
||||
private final AtomicBoolean paused = new AtomicBoolean();
|
||||
private final AtomicBoolean cancelled = new AtomicBoolean();
|
||||
private final KMap<Long, Pair<Long, AtomicInteger>> lastUse = new KMap<>();
|
||||
private final RollingSequence chunksPerSecond = new RollingSequence(5);
|
||||
private final AtomicInteger totalMaxChunks = new AtomicInteger();
|
||||
private final AtomicInteger chunksProcessed = new AtomicInteger();
|
||||
private final AtomicInteger chunksProcessedLast = new AtomicInteger();
|
||||
private final AtomicInteger chunksUpdated = new AtomicInteger();
|
||||
private final AtomicBoolean serverEmpty = new AtomicBoolean(true);
|
||||
private final AtomicLong lastCpsTime = new AtomicLong(M.ms());
|
||||
private final int coreLimit = (int) Math.max(Runtime.getRuntime().availableProcessors() * IrisSettings.get().getUpdater().getThreadMultiplier(), 1);
|
||||
private final Semaphore semaphore = new Semaphore(256);
|
||||
private final LoadBalancer loadBalancer = new LoadBalancer(semaphore, 256, IrisSettings.get().getUpdater().emptyMsRange);
|
||||
private final AtomicLong startTime = new AtomicLong();
|
||||
private final Dimensions dimensions;
|
||||
private final PregenTask task;
|
||||
private final ExecutorService executor = Executors.newFixedThreadPool(coreLimit);
|
||||
private final ExecutorService chunkExecutor = Executors.newFixedThreadPool(coreLimit);
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
private final CountDownLatch latch;
|
||||
private final Engine engine;
|
||||
private final World world;
|
||||
|
||||
public ChunkUpdater(World world) {
|
||||
this.engine = IrisToolbelt.access(world).getEngine();
|
||||
this.world = world;
|
||||
this.dimensions = calculateWorldDimensions(new File(world.getWorldFolder(), "region"));
|
||||
this.task = dimensions.task();
|
||||
this.totalMaxChunks.set(dimensions.count * 1024);
|
||||
this.latch = new CountDownLatch(totalMaxChunks.get());
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return world.getName();
|
||||
}
|
||||
|
||||
public int getChunks() {
|
||||
return totalMaxChunks.get();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
unloadAndSaveAllChunks();
|
||||
update();
|
||||
}
|
||||
|
||||
public boolean pause() {
|
||||
unloadAndSaveAllChunks();
|
||||
if (paused.get()) {
|
||||
paused.set(false);
|
||||
return false;
|
||||
} else {
|
||||
paused.set(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
unloadAndSaveAllChunks();
|
||||
cancelled.set(true);
|
||||
}
|
||||
|
||||
private void update() {
|
||||
Iris.info("Updating..");
|
||||
try {
|
||||
startTime.set(System.currentTimeMillis());
|
||||
scheduler.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
if (!paused.get()) {
|
||||
long eta = computeETA();
|
||||
int processed = chunksProcessed.get();
|
||||
double last = processed - chunksProcessedLast.getAndSet(processed);
|
||||
double cps = last / ((M.ms() - lastCpsTime.getAndSet(M.ms())) / 1000d);
|
||||
chunksPerSecond.put(cps);
|
||||
double percentage = ((double) processed / (double) totalMaxChunks.get()) * 100;
|
||||
if (!cancelled.get()) {
|
||||
Iris.info("Updated: " + Form.f(processed) + " of " + Form.f(totalMaxChunks.get()) + " (%.0f%%) " + Form.f(chunksPerSecond.getAverage()) + "/s, ETA: " + Form.duration(eta,
|
||||
2), percentage);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, 0, 3, TimeUnit.SECONDS);
|
||||
scheduler.scheduleAtFixedRate(this::unloadChunks, 0, 1, TimeUnit.SECONDS);
|
||||
scheduler.scheduleAtFixedRate(() -> {
|
||||
boolean empty = Bukkit.getOnlinePlayers().isEmpty();
|
||||
if (serverEmpty.getAndSet(empty) == empty)
|
||||
return;
|
||||
loadBalancer.setRange(empty ? IrisSettings.get().getUpdater().emptyMsRange : IrisSettings.get().getUpdater().defaultMsRange);
|
||||
}, 0, 10, TimeUnit.SECONDS);
|
||||
|
||||
var t = new Thread(() -> {
|
||||
run();
|
||||
close();
|
||||
}, "Iris Chunk Updater - " + world.getName());
|
||||
t.setPriority(Thread.MAX_PRIORITY);
|
||||
t.start();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
loadBalancer.close();
|
||||
semaphore.acquire(256);
|
||||
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
chunkExecutor.shutdown();
|
||||
chunkExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
scheduler.shutdownNow();
|
||||
unloadAndSaveAllChunks();
|
||||
} catch (Exception ignored) {}
|
||||
if (cancelled.get()) {
|
||||
Iris.info("Updated: " + Form.f(chunksUpdated.get()) + " Chunks");
|
||||
Iris.info("Irritated: " + Form.f(chunksProcessed.get()) + " of " + Form.f(totalMaxChunks.get()));
|
||||
Iris.info("Stopped updater.");
|
||||
} else {
|
||||
Iris.info("Processed: " + Form.f(chunksProcessed.get()) + " Chunks");
|
||||
Iris.info("Finished Updating: " + Form.f(chunksUpdated.get()) + " Chunks");
|
||||
}
|
||||
}
|
||||
|
||||
private void run() {
|
||||
task.iterateRegions((rX, rZ) -> {
|
||||
if (cancelled.get())
|
||||
return;
|
||||
|
||||
while (paused.get()) {
|
||||
J.sleep(50);
|
||||
}
|
||||
|
||||
if (rX < dimensions.min.getX() || rX > dimensions.max.getX() || rZ < dimensions.min.getZ() || rZ > dimensions.max.getZ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PregenTask.iterateRegion(rX, rZ, (x, z) -> {
|
||||
while (paused.get() && !cancelled.get()) {
|
||||
J.sleep(50);
|
||||
}
|
||||
|
||||
try {
|
||||
semaphore.acquire();
|
||||
} catch (InterruptedException ignored) {
|
||||
return;
|
||||
}
|
||||
chunkExecutor.submit(() -> {
|
||||
try {
|
||||
if (!cancelled.get())
|
||||
processChunk(x, z);
|
||||
} finally {
|
||||
latch.countDown();
|
||||
semaphore.release();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void processChunk(int x, int z) {
|
||||
if (!loadChunksIfGenerated(x, z)) {
|
||||
chunksProcessed.getAndIncrement();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Chunk c = world.getChunkAt(x, z);
|
||||
engine.getMantle().getMantle().getChunk(c);
|
||||
engine.updateChunk(c);
|
||||
|
||||
for (int xx = -1; xx <= 1; xx++) {
|
||||
for (int zz = -1; zz <= 1; zz++) {
|
||||
var counter = lastUse.get(Cache.key(x + xx, z + zz));
|
||||
if (counter != null) counter.getB().decrementAndGet();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
chunksUpdated.incrementAndGet();
|
||||
chunksProcessed.getAndIncrement();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean loadChunksIfGenerated(int x, int z) {
|
||||
if (engine.getMantle().getMantle().hasFlag(x, z, MantleFlag.ETCHED))
|
||||
return false;
|
||||
|
||||
for (int dx = -1; dx <= 1; dx++) {
|
||||
for (int dz = -1; dz <= 1; dz++) {
|
||||
if (!PaperLib.isChunkGenerated(world, x + dx, z + dz)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AtomicBoolean generated = new AtomicBoolean(true);
|
||||
CountDownLatch latch = new CountDownLatch(9);
|
||||
for (int dx = -1; dx <= 1; dx++) {
|
||||
for (int dz = -1; dz <= 1; dz++) {
|
||||
int xx = x + dx;
|
||||
int zz = z + dz;
|
||||
executor.submit(() -> {
|
||||
try {
|
||||
Chunk c;
|
||||
try {
|
||||
c = PaperLib.getChunkAtAsync(world, xx, zz, false, true)
|
||||
.thenApply(chunk -> {
|
||||
chunk.addPluginChunkTicket(Iris.instance);
|
||||
return chunk;
|
||||
}).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
generated.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!c.isLoaded()) {
|
||||
var future = J.sfut(() -> c.load(false));
|
||||
if (future != null) future.join();
|
||||
}
|
||||
|
||||
if (!c.isGenerated())
|
||||
generated.set(false);
|
||||
|
||||
var pair = lastUse.computeIfAbsent(Cache.key(c), k -> new Pair<>(0L, new AtomicInteger(-1)));
|
||||
pair.setA(M.ms());
|
||||
pair.getB().updateAndGet(i -> i == -1 ? 1 : ++i);
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
Iris.info("Interrupted while waiting for chunks to load");
|
||||
}
|
||||
return generated.get();
|
||||
}
|
||||
|
||||
private synchronized void unloadChunks() {
|
||||
for (var key : new ArrayList<>(lastUse.keySet())) {
|
||||
if (key == null) continue;
|
||||
var pair = lastUse.get(key);
|
||||
if (pair == null) continue;
|
||||
var lastUseTime = pair.getA();
|
||||
var counter = pair.getB();
|
||||
if (lastUseTime == null || counter == null)
|
||||
continue;
|
||||
|
||||
if (M.ms() - lastUseTime >= 5000 && counter.get() == 0) {
|
||||
int x = Cache.keyX(key);
|
||||
int z = Cache.keyZ(key);
|
||||
J.s(() -> {
|
||||
world.removePluginChunkTicket(x, z, Iris.instance);
|
||||
world.unloadChunk(x, z);
|
||||
lastUse.remove(key);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void unloadAndSaveAllChunks() {
|
||||
try {
|
||||
J.sfut(() -> {
|
||||
if (world == null) {
|
||||
Iris.warn("World was null somehow...");
|
||||
return;
|
||||
}
|
||||
|
||||
unloadChunks();
|
||||
world.save();
|
||||
}).get();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private long computeETA() {
|
||||
return (long) (totalMaxChunks.get() > 1024 ? // Generated chunks exceed 1/8th of total?
|
||||
// If yes, use smooth function (which gets more accurate over time since its less sensitive to outliers)
|
||||
((totalMaxChunks.get() - chunksProcessed.get()) * ((double) (M.ms() - startTime.get()) / (double) chunksProcessed.get())) :
|
||||
// If no, use quick function (which is less accurate over time but responds better to the initial delay)
|
||||
((totalMaxChunks.get() - chunksProcessed.get()) / chunksPerSecond.getAverage()) * 1000
|
||||
);
|
||||
}
|
||||
|
||||
private Dimensions calculateWorldDimensions(File regionDir) {
|
||||
File[] files = regionDir.listFiles((dir, name) -> name.endsWith(".mca"));
|
||||
|
||||
int minX = Integer.MAX_VALUE;
|
||||
int maxX = Integer.MIN_VALUE;
|
||||
int minZ = Integer.MAX_VALUE;
|
||||
int maxZ = Integer.MIN_VALUE;
|
||||
|
||||
for (File file : files) {
|
||||
String[] parts = file.getName().split("\\.");
|
||||
int x = Integer.parseInt(parts[1]);
|
||||
int z = Integer.parseInt(parts[2]);
|
||||
|
||||
minX = Math.min(minX, x);
|
||||
maxX = Math.max(maxX, x);
|
||||
minZ = Math.min(minZ, z);
|
||||
maxZ = Math.max(maxZ, z);
|
||||
}
|
||||
int oX = minX + ((maxX - minX) / 2);
|
||||
int oZ = minZ + ((maxZ - minZ) / 2);
|
||||
|
||||
int height = maxX - minX + 1;
|
||||
int width = maxZ - minZ + 1;
|
||||
|
||||
return new Dimensions(new Position2(minX, minZ), new Position2(maxX, maxZ), height * width, PregenTask.builder()
|
||||
.width((int) Math.ceil(width / 2d))
|
||||
.height((int) Math.ceil(height / 2d))
|
||||
.center(new Position2(oX, oZ))
|
||||
.build());
|
||||
}
|
||||
|
||||
private record Dimensions(Position2 min, Position2 max, int count, PregenTask task) { }
|
||||
}
|
||||
@@ -1,322 +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.core.pack.IrisPack;
|
||||
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
||||
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.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 KList<Integer> chunksPerSecondHistory;
|
||||
private static AtomicInteger generated;
|
||||
private final AtomicInteger generatedLast;
|
||||
private final AtomicInteger generatedLastMinute;
|
||||
private static 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;
|
||||
private final ChronoLatch saveLatch = new ChronoLatch(30000);
|
||||
|
||||
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);
|
||||
chunksPerSecondHistory = new KList<>();
|
||||
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);
|
||||
chunksPerSecondHistory.add(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()) {
|
||||
double percentage = ((double) generated.get() / (double) totalChunks.get()) * 100;
|
||||
if (!IrisPackBenchmarking.benchmarkInProgress) {
|
||||
Iris.info("Pregen: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (%.0f%%) " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration(eta, 2), percentage);
|
||||
} else {
|
||||
Iris.info("Benchmarking: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (%.0f%%) " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration(eta, 2), percentage);
|
||||
}
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private long computeETA() {
|
||||
return (long) (totalChunks.get() > 1024 ? // Generated chunks exceed 1/8th of total?
|
||||
// If yes, use smooth function (which gets more accurate over time since its less sensitive to outliers)
|
||||
((totalChunks.get() - generated.get()) * ((double) (M.ms() - startTime.get()) / (double) generated.get())) :
|
||||
// If no, use quick function (which is less accurate over time but responds better to the initial delay)
|
||||
((totalChunks.get() - generated.get()) / chunksPerSecond.getAverage()) * 1000
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
if (!IrisPackBenchmarking.benchmarkInProgress) {
|
||||
Iris.info(C.IRIS + "Pregen stopped.");
|
||||
} else {
|
||||
IrisPackBenchmarking.instance.finishedBenchmark(chunksPerSecondHistory);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
Mantle mantle = getMantle();
|
||||
if (mantle != null) {
|
||||
mantle.trim(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
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) -> {
|
||||
while (paused.get() && !shutdown.get()) {
|
||||
J.sleep(50);
|
||||
}
|
||||
|
||||
generator.generateChunk(xx, zz, listener);
|
||||
});
|
||||
}
|
||||
|
||||
if (hit) {
|
||||
listener.onRegionGenerated(x, z);
|
||||
|
||||
if (saveLatch.flip()) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,286 +0,0 @@
|
||||
package com.volmit.iris.core.pregenerator;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.volmit.iris.Iris;
|
||||
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.math.M;
|
||||
import com.volmit.iris.util.math.Position2;
|
||||
import com.volmit.iris.util.math.RollingSequence;
|
||||
import com.volmit.iris.util.math.Spiraler;
|
||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class LazyPregenerator extends Thread implements Listener {
|
||||
@Getter
|
||||
private static LazyPregenerator instance;
|
||||
private final LazyPregenJob job;
|
||||
private final File destination;
|
||||
private final int maxPosition;
|
||||
private World world;
|
||||
private final long rate;
|
||||
private final ChronoLatch latch;
|
||||
private static AtomicInteger lazyGeneratedChunks;
|
||||
private final AtomicInteger generatedLast;
|
||||
private final AtomicInteger lazyTotalChunks;
|
||||
private final AtomicLong startTime;
|
||||
private final RollingSequence chunksPerSecond;
|
||||
private final RollingSequence chunksPerMinute;
|
||||
|
||||
private static final Map<String, LazyPregenJob> jobs = new HashMap<>();
|
||||
|
||||
public LazyPregenerator(LazyPregenJob job, File destination) {
|
||||
this.job = job;
|
||||
this.destination = destination;
|
||||
this.maxPosition = new Spiraler(job.getRadiusBlocks() * 2, job.getRadiusBlocks() * 2, (x, z) -> {
|
||||
}).count();
|
||||
this.world = Bukkit.getWorld(job.getWorld());
|
||||
this.rate = Math.round((1D / (job.getChunksPerMinute() / 60D)) * 1000D);
|
||||
this.latch = new ChronoLatch(15000);
|
||||
this.startTime = new AtomicLong(M.ms());
|
||||
this.chunksPerSecond = new RollingSequence(10);
|
||||
this.chunksPerMinute = new RollingSequence(10);
|
||||
lazyGeneratedChunks = new AtomicInteger(0);
|
||||
this.generatedLast = new AtomicInteger(0);
|
||||
this.lazyTotalChunks = new AtomicInteger((int) Math.ceil(Math.pow((2.0 * job.getRadiusBlocks()) / 16, 2)));
|
||||
jobs.put(job.getWorld(), job);
|
||||
LazyPregenerator.instance = this;
|
||||
}
|
||||
|
||||
public LazyPregenerator(File file) throws IOException {
|
||||
this(new Gson().fromJson(IO.readAll(file), LazyPregenJob.class), file);
|
||||
}
|
||||
|
||||
public static void loadLazyGenerators() {
|
||||
for (World i : Bukkit.getWorlds()) {
|
||||
File lazygen = new File(i.getWorldFolder(), "lazygen.json");
|
||||
if (lazygen.exists()) {
|
||||
try {
|
||||
LazyPregenerator p = new LazyPregenerator(lazygen);
|
||||
p.start();
|
||||
Iris.info("Started Lazy Pregenerator: " + p.job);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void on(WorldUnloadEvent e) {
|
||||
if (e.getWorld().equals(world)) {
|
||||
interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (!interrupted()) {
|
||||
J.sleep(rate);
|
||||
tick();
|
||||
}
|
||||
|
||||
try {
|
||||
saveNow();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
LazyPregenJob job = jobs.get(world.getName());
|
||||
if (latch.flip() && !job.paused) {
|
||||
long eta = computeETA();
|
||||
save();
|
||||
int secondGenerated = lazyGeneratedChunks.get() - generatedLast.get();
|
||||
generatedLast.set(lazyGeneratedChunks.get());
|
||||
secondGenerated = secondGenerated / 15;
|
||||
chunksPerSecond.put(secondGenerated);
|
||||
chunksPerMinute.put(secondGenerated * 60);
|
||||
if (!job.isSilent()) {
|
||||
Iris.info("LazyGen: " + C.IRIS + world.getName() + C.RESET + " RTT: " + Form.f(lazyGeneratedChunks.get()) + " of " + Form.f(lazyTotalChunks.get()) + " " + Form.f((int) chunksPerMinute.getAverage()) + "/m ETA: " + Form.duration((double) eta, 2));
|
||||
}
|
||||
}
|
||||
|
||||
if (lazyGeneratedChunks.get() >= lazyTotalChunks.get()) {
|
||||
if (job.isHealing()) {
|
||||
int pos = (job.getHealingPosition() + 1) % maxPosition;
|
||||
job.setHealingPosition(pos);
|
||||
tickRegenerate(getChunk(pos));
|
||||
} else {
|
||||
Iris.info("Completed Lazy Gen!");
|
||||
interrupt();
|
||||
}
|
||||
} else {
|
||||
int pos = job.getPosition() + 1;
|
||||
job.setPosition(pos);
|
||||
if (!job.paused) {
|
||||
tickGenerate(getChunk(pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long computeETA() {
|
||||
return (long) ((lazyTotalChunks.get() - lazyGeneratedChunks.get()) / chunksPerMinute.getAverage()) * 1000;
|
||||
// todo broken
|
||||
}
|
||||
|
||||
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||
|
||||
private void tickGenerate(Position2 chunk) {
|
||||
executorService.submit(() -> {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
if (PaperLib.isPaper()) {
|
||||
PaperLib.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true)
|
||||
.thenAccept((i) -> {
|
||||
Iris.verbose("Generated Async " + chunk);
|
||||
latch.countDown();
|
||||
});
|
||||
} else {
|
||||
J.s(() -> {
|
||||
world.getChunkAt(chunk.getX(), chunk.getZ());
|
||||
Iris.verbose("Generated " + chunk);
|
||||
latch.countDown();
|
||||
});
|
||||
}
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException ignored) {}
|
||||
lazyGeneratedChunks.addAndGet(1);
|
||||
});
|
||||
}
|
||||
|
||||
private void tickRegenerate(Position2 chunk) {
|
||||
J.s(() -> world.regenerateChunk(chunk.getX(), chunk.getZ()));
|
||||
Iris.verbose("Regenerated " + chunk);
|
||||
}
|
||||
|
||||
public Position2 getChunk(int position) {
|
||||
int p = -1;
|
||||
AtomicInteger xx = new AtomicInteger();
|
||||
AtomicInteger zz = new AtomicInteger();
|
||||
Spiraler s = new Spiraler(job.getRadiusBlocks() * 2, job.getRadiusBlocks() * 2, (x, z) -> {
|
||||
xx.set(x);
|
||||
zz.set(z);
|
||||
});
|
||||
|
||||
while (s.hasNext() && p++ < position) {
|
||||
s.next();
|
||||
}
|
||||
|
||||
return new Position2(xx.get(), zz.get());
|
||||
}
|
||||
|
||||
public void save() {
|
||||
J.a(() -> {
|
||||
try {
|
||||
saveNow();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void setPausedLazy(World world) {
|
||||
LazyPregenJob job = jobs.get(world.getName());
|
||||
if (isPausedLazy(world)){
|
||||
job.paused = false;
|
||||
} else {
|
||||
job.paused = true;
|
||||
}
|
||||
|
||||
if ( job.paused) {
|
||||
Iris.info(C.BLUE + "LazyGen: " + C.IRIS + world.getName() + C.BLUE + " Paused");
|
||||
} else {
|
||||
Iris.info(C.BLUE + "LazyGen: " + C.IRIS + world.getName() + C.BLUE + " Resumed");
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isPausedLazy(World world) {
|
||||
LazyPregenJob job = jobs.get(world.getName());
|
||||
return job != null && job.isPaused();
|
||||
}
|
||||
|
||||
public void shutdownInstance(World world) throws IOException {
|
||||
Iris.info("LazyGen: " + C.IRIS + world.getName() + C.BLUE + " Shutting down..");
|
||||
LazyPregenJob job = jobs.get(world.getName());
|
||||
File worldDirectory = new File(Bukkit.getWorldContainer(), world.getName());
|
||||
File lazyFile = new File(worldDirectory, "lazygen.json");
|
||||
|
||||
if (job == null) {
|
||||
Iris.error("No Lazygen job found for world: " + world.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!job.isPaused()) {
|
||||
job.setPaused(true);
|
||||
}
|
||||
save();
|
||||
jobs.remove(world.getName());
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (lazyFile.exists()){
|
||||
lazyFile.delete();
|
||||
J.sleep(1000);
|
||||
}
|
||||
Iris.info("LazyGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
|
||||
}
|
||||
}.runTaskLater(Iris.instance, 20L);
|
||||
} catch (Exception e) {
|
||||
Iris.error("Failed to shutdown Lazygen for " + world.getName());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
saveNow();
|
||||
interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void saveNow() throws IOException {
|
||||
IO.writeAll(this.destination, new Gson().toJson(job));
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public static class LazyPregenJob {
|
||||
private String world;
|
||||
@Builder.Default
|
||||
private int healingPosition = 0;
|
||||
@Builder.Default
|
||||
private boolean healing = false;
|
||||
@Builder.Default
|
||||
private int chunksPerMinute = 32;
|
||||
@Builder.Default
|
||||
private int radiusBlocks = 5000;
|
||||
@Builder.Default
|
||||
private int position = 0;
|
||||
@Builder.Default
|
||||
boolean silent = false;
|
||||
@Builder.Default
|
||||
boolean paused = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,98 +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 boolean gui = false;
|
||||
@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(-(xr << 5), -(zr << 5)));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -1,172 +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.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.collection.KMap;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.math.M;
|
||||
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.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class AsyncPregenMethod implements PregeneratorMethod {
|
||||
private final World world;
|
||||
private final MultiBurst burst;
|
||||
private final KList<Future<?>> future;
|
||||
private final Map<Chunk, Long> lastUse;
|
||||
|
||||
public AsyncPregenMethod(World world, int threads) {
|
||||
if (!PaperLib.isPaper()) {
|
||||
throw new UnsupportedOperationException("Cannot use PaperAsync on non paper!");
|
||||
}
|
||||
|
||||
this.world = world;
|
||||
burst = new MultiBurst("Iris Async Pregen", Thread.MIN_PRIORITY);
|
||||
future = new KList<>(256);
|
||||
this.lastUse = new KMap<>();
|
||||
}
|
||||
|
||||
private void unloadAndSaveAllChunks() {
|
||||
try {
|
||||
J.sfut(() -> {
|
||||
if (world == null) {
|
||||
Iris.warn("World was null somehow...");
|
||||
return;
|
||||
}
|
||||
|
||||
for (Chunk i : new ArrayList<>(lastUse.keySet())) {
|
||||
Long lastUseTime = lastUse.get(i);
|
||||
if (lastUseTime != null && M.ms() - lastUseTime >= 10000) {
|
||||
i.unload();
|
||||
lastUse.remove(i);
|
||||
}
|
||||
}
|
||||
world.save();
|
||||
}).get();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void completeChunk(int x, int z, PregenListener listener) {
|
||||
try {
|
||||
PaperLib.getChunkAtAsync(world, x, z, true).thenAccept((i) -> {
|
||||
lastUse.put(i, M.ms());
|
||||
listener.onChunkGenerated(x, z);
|
||||
listener.onChunkCleaned(x, z);
|
||||
}).get();
|
||||
} catch (InterruptedException ignored) {
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForChunksPartial(int maxWaiting) {
|
||||
while (future.size() > maxWaiting) {
|
||||
try {
|
||||
Future<?> i = future.remove(0);
|
||||
|
||||
if (i == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
i.get();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForChunks() {
|
||||
for (Future<?> i : future.copy()) {
|
||||
if (i == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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();
|
||||
burst.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
waitForChunksPartial(256);
|
||||
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) {
|
||||
listener.onChunkGenerating(x, z);
|
||||
if (future.size() > 256) {
|
||||
waitForChunksPartial(256);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,74 +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 org.bukkit.World;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,138 +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.collection.KMap;
|
||||
import com.volmit.iris.util.mantle.Mantle;
|
||||
import com.volmit.iris.util.math.M;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class MedievalPregenMethod implements PregeneratorMethod {
|
||||
private final World world;
|
||||
private final KList<CompletableFuture<?>> futures;
|
||||
private final Map<Chunk, Long> lastUse;
|
||||
|
||||
public MedievalPregenMethod(World world) {
|
||||
this.world = world;
|
||||
futures = new KList<>();
|
||||
this.lastUse = new KMap<>();
|
||||
}
|
||||
|
||||
private void waitForChunks() {
|
||||
for (CompletableFuture<?> i : futures) {
|
||||
try {
|
||||
i.get();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
futures.clear();
|
||||
}
|
||||
|
||||
private void unloadAndSaveAllChunks() {
|
||||
try {
|
||||
J.sfut(() -> {
|
||||
if (world == null) {
|
||||
Iris.warn("World was null somehow...");
|
||||
return;
|
||||
}
|
||||
|
||||
for (Chunk i : new ArrayList<>(lastUse.keySet())) {
|
||||
Long lastUseTime = lastUse.get(i);
|
||||
if (lastUseTime != null && M.ms() - lastUseTime >= 10) {
|
||||
i.unload();
|
||||
lastUse.remove(i);
|
||||
}
|
||||
}
|
||||
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);
|
||||
Chunk c = Bukkit.getWorld(world.getUID()).getChunkAt(x, z);
|
||||
lastUse.put(c, M.ms());
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,656 +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.*;
|
||||
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.*;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,694 +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.framework.ListFunction;
|
||||
import com.volmit.iris.engine.object.annotations.*;
|
||||
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.*;
|
||||
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 = getEnchantTypes();
|
||||
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 getPotionTypes() {
|
||||
JSONArray a = new JSONArray();
|
||||
|
||||
for (PotionEffectType gg : PotionEffectType.values()) {
|
||||
a.put(gg.getName().toUpperCase().replaceAll("\\Q \\E", "_"));
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
private static JSONArray getEnchantTypes() {
|
||||
JSONArray array = new JSONArray();
|
||||
for (Enchantment e : Enchantment.values()) {
|
||||
array.put(e.getKey().getKey());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
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.isAnnotationPresent(RegistryListEnchantment.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.isAnnotationPresent(RegistryListFunction.class)) {
|
||||
var functionClass = k.getDeclaredAnnotation(RegistryListFunction.class).value();
|
||||
try {
|
||||
var instance = functionClass.getDeclaredConstructor().newInstance();
|
||||
String key = instance.key();
|
||||
fancyType = instance.fancyName();
|
||||
|
||||
if (!definitions.containsKey(key)) {
|
||||
JSONObject j = new JSONObject();
|
||||
j.put("enum", instance.apply(data));
|
||||
definitions.put(key, j);
|
||||
}
|
||||
|
||||
prop.put("$ref", "#/definitions/" + key);
|
||||
description.add(SYMBOL_TYPE__N + " Must be a valid " + fancyType + " (use ctrl+space for auto complete!)");
|
||||
} catch (Throwable e) {
|
||||
Iris.error("Could not execute apply method in " + functionClass.getName());
|
||||
}
|
||||
} 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.");
|
||||
}
|
||||
}
|
||||
if (t.max() > 0) {
|
||||
prop.put("maxItems", t.max());
|
||||
description.add(SYMBOL_LIMIT__N + " Maximum allowed entries are " + t.max() + ".");
|
||||
}
|
||||
|
||||
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 (k.isAnnotationPresent(RegistryListEnchantment.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 "";
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.volmit.iris.core.safeguard;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
|
||||
public class IrisSafeguard {
|
||||
public static boolean unstablemode = false;
|
||||
public static boolean warningmode = false;
|
||||
public static boolean stablemode = false;
|
||||
|
||||
public static void IrisSafeguardSystem() {
|
||||
Iris.info("Enabled Iris SafeGuard");
|
||||
ServerBootSFG.BootCheck();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
package com.volmit.iris.core.safeguard;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.util.format.C;
|
||||
|
||||
public class ModesSFG {
|
||||
public static void selectMode() {
|
||||
if (IrisSafeguard.unstablemode) {
|
||||
Iris.safeguard(C.DARK_RED + "Iris is running in Unstable Mode");
|
||||
unstable();
|
||||
}
|
||||
if (IrisSafeguard.warningmode) {
|
||||
Iris.safeguard(C.GOLD + "Iris is running in Warning Mode");
|
||||
warning();
|
||||
}
|
||||
if (IrisSafeguard.stablemode) {
|
||||
stable();
|
||||
}
|
||||
}
|
||||
|
||||
public static void stable() {
|
||||
Iris.safeguard(C.BLUE + "Iris is running Stable");
|
||||
}
|
||||
|
||||
public static void unstable() {
|
||||
|
||||
UtilsSFG.printIncompatibleWarnings();
|
||||
|
||||
if (IrisSafeguard.unstablemode) {
|
||||
Iris.info("");
|
||||
Iris.info(C.DARK_GRAY + "--==<" + C.RED + " IMPORTANT " + C.DARK_GRAY + ">==--");
|
||||
Iris.info(C.RED + "Iris is running in unstable mode which may cause the following issues:");
|
||||
Iris.info(C.DARK_RED + "Server Issues");
|
||||
Iris.info(C.RED + "- Server won't boot");
|
||||
Iris.info(C.RED + "- Data Loss");
|
||||
Iris.info(C.RED + "- Unexpected behavior.");
|
||||
Iris.info(C.RED + "- And More...");
|
||||
Iris.info(C.DARK_RED + "World Issues");
|
||||
Iris.info(C.RED + "- Worlds can't load due to corruption.");
|
||||
Iris.info(C.RED + "- Worlds may slowly corrupt until they can't load.");
|
||||
Iris.info(C.RED + "- World data loss.");
|
||||
Iris.info(C.RED + "- And More...");
|
||||
Iris.info(C.DARK_RED + "ATTENTION: " + C.RED + "While running Iris in unstable mode, you won't be eligible for support.");
|
||||
Iris.info(C.DARK_RED + "CAUSE: " + C.RED + UtilsSFG.MSGIncompatibleWarnings());
|
||||
|
||||
if (IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode) {
|
||||
Iris.info(C.DARK_RED + "Boot Unstable is set to true, continuing with the startup process.");
|
||||
} else {
|
||||
Iris.info(C.DARK_RED + "Go to plugins/iris/settings.json and set DoomsdayAnnihilationSelfDestructMode to true if you wish to proceed.");
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(Long.MAX_VALUE);
|
||||
} catch (InterruptedException e) {
|
||||
// no
|
||||
}
|
||||
}
|
||||
}
|
||||
Iris.info("");
|
||||
}
|
||||
}
|
||||
|
||||
public static void warning() {
|
||||
|
||||
UtilsSFG.printIncompatibleWarnings();
|
||||
|
||||
if (IrisSafeguard.warningmode) {
|
||||
Iris.info("");
|
||||
Iris.info(C.DARK_GRAY + "--==<" + C.GOLD + " IMPORTANT " + C.DARK_GRAY + ">==--");
|
||||
Iris.info(C.GOLD + "Iris is running in warning mode which may cause the following issues:");
|
||||
Iris.info(C.YELLOW + "- Data Loss");
|
||||
Iris.info(C.YELLOW + "- Errors");
|
||||
Iris.info(C.YELLOW + "- Broken worlds");
|
||||
Iris.info(C.YELLOW + "- Unexpected behavior.");
|
||||
Iris.info(C.YELLOW + "- And perhaps further complications.");
|
||||
Iris.info(C.GOLD + "CAUSE: " + C.YELLOW + UtilsSFG.MSGIncompatibleWarnings());
|
||||
Iris.info("");
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user