mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-05-20 08:40:26 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f48b616fe | |||
| cef185b07d |
+7
-7
@@ -8,7 +8,7 @@ indent_style = space
|
||||
insert_final_newline = false
|
||||
max_line_length = 140
|
||||
tab_width = 4
|
||||
ij_continuation_indent_size = 4
|
||||
ij_continuation_indent_size = 8
|
||||
ij_formatter_off_tag = @formatter:off
|
||||
ij_formatter_on_tag = @formatter:on
|
||||
ij_formatter_tags_enabled = false
|
||||
@@ -25,12 +25,12 @@ ij_java_align_multiline_annotation_parameters = true
|
||||
ij_java_align_multiline_array_initializer_expression = true
|
||||
ij_java_align_multiline_assignment = true
|
||||
ij_java_align_multiline_binary_operation = true
|
||||
ij_java_align_multiline_chained_methods = false
|
||||
ij_java_align_multiline_chained_methods = true
|
||||
ij_java_align_multiline_extends_list = true
|
||||
ij_java_align_multiline_for = true
|
||||
ij_java_align_multiline_method_parentheses = false
|
||||
ij_java_align_multiline_method_parentheses = true
|
||||
ij_java_align_multiline_parameters = true
|
||||
ij_java_align_multiline_parameters_in_calls = false
|
||||
ij_java_align_multiline_parameters_in_calls = true
|
||||
ij_java_align_multiline_parenthesized_expression = true
|
||||
ij_java_align_multiline_records = true
|
||||
ij_java_align_multiline_resources = true
|
||||
@@ -127,7 +127,7 @@ ij_java_keep_blank_lines_in_declarations = 2
|
||||
ij_java_keep_builder_methods_indents = true
|
||||
ij_java_keep_control_statement_in_one_line = true
|
||||
ij_java_keep_first_column_comment = false
|
||||
ij_java_keep_indents_on_empty_lines = false
|
||||
ij_java_keep_indents_on_empty_lines = true
|
||||
ij_java_keep_line_breaks = true
|
||||
ij_java_keep_multiple_expressions_in_one_line = false
|
||||
ij_java_keep_simple_blocks_in_one_line = true
|
||||
@@ -577,14 +577,14 @@ ij_properties_keep_blank_lines = false
|
||||
ij_properties_key_value_delimiter = equals
|
||||
ij_properties_spaces_around_key_value_delimiter = false
|
||||
|
||||
[{*.yml, *.yaml}]
|
||||
[{*.yaml, *.yml}]
|
||||
indent_size = 2
|
||||
ij_visual_guides = none
|
||||
ij_yaml_align_values_properties = do_not_align
|
||||
ij_yaml_autoinsert_sequence_marker = true
|
||||
ij_yaml_block_mapping_on_new_line = false
|
||||
ij_yaml_indent_sequence_value = true
|
||||
ij_yaml_keep_indents_on_empty_lines = false
|
||||
ij_yaml_keep_indents_on_empty_lines = true
|
||||
ij_yaml_keep_line_breaks = true
|
||||
ij_yaml_sequence_on_new_line = false
|
||||
ij_yaml_space_before_colon = false
|
||||
|
||||
+12
-7
@@ -1,14 +1,19 @@
|
||||
# Global owners, automatically request review when pull request is submitted
|
||||
* @dfsek @solonovamax @duplexsystem @astrsh @justaureus
|
||||
* @dfsek @solonovamax
|
||||
|
||||
# Platforms
|
||||
/platforms/ @dfsek @solonovamax @duplexsystem @justaureus
|
||||
/platforms/bukkit @dfsek @solonovamax @duplexsystem @justaureus @OakLoaf
|
||||
## dfsek wrote the majority of the platform impls
|
||||
/platforms/bukkit/ @dfsek
|
||||
/platforms/fabric/ @dfsek
|
||||
/platforms/forge/ @dfsek
|
||||
/platforms/sponge/ @dfsek
|
||||
## solonovamax is working on the region generator (unless duplexsystem takes it over)
|
||||
/platforms/region/ @solonovamax
|
||||
|
||||
# Common
|
||||
/common/ @dfsek @solonovamax @duplexsystem @astrsh
|
||||
/common/ @dfsek @solonovamax
|
||||
|
||||
# Gradle Stuff
|
||||
/buildSrc/ @dfsek @solonovamax @duplexsystem
|
||||
*.gradle.kts @dfsek @solonovamax @duplexsystem
|
||||
/gradle/ @dfsek @solonovamax @duplexsystem
|
||||
## Most gradle stuff was written by solonovamax
|
||||
/buildSrc/ @solonovamax
|
||||
*.gradle.kts @solonovamax
|
||||
@@ -21,8 +21,8 @@ assignees: ""
|
||||
- You must be on the LATEST version of Terra to receive any support. There is no support for older versions of Terra.
|
||||
- Make sure that this is not a *specific* compatibility issue with another terrain generation mod.
|
||||
Do not request *specific* compatibility with mods or plugins (e.g. "Compatibility with TechCraft v7").
|
||||
That should be implemented in an addon, **not** in the main project.
|
||||
*General* compatibility (e.g. "Ability to pull Vanilla/Modded features from parent biomes") will be considered in the main project.
|
||||
That should be implemented in an addon, **not** in the platform project.
|
||||
*General* compatibility (e.g. "Ability to pull Vanilla/Modded features from parent biomes") will be considered in the platform project.
|
||||
- Make sure that there are no already existing issues open with your problem. If you open a duplicate, it will be closed as such.
|
||||
- Make sure that it is actually Terra causing the issue, and not another mod/plugin.
|
||||
You can do this by testing to see if you can recreate the issue without Terra installed.
|
||||
@@ -43,7 +43,7 @@ assignees: ""
|
||||
is Terra that is causing the issue.
|
||||
- [ ] I have checked that this is an issue with Terra and not an issue with the
|
||||
pack I am using.
|
||||
<!-- If this is an issue with the default Terra pack, please open an issue on the pack repo: https://github.com/PolyhedralDev/TerraOverworldConfig/issues/new -->
|
||||
<!-- If this is an issue with the default Terra pack, please open an issue on the pack repo: https://github.com/PolyhedralDev/TerraDefaultConfig/issues/new -->
|
||||
- [ ] I have attached a copy of the `latest.log` file
|
||||
- [ ] I have filled out and provided all the appropriate information.
|
||||
|
||||
@@ -51,13 +51,13 @@ assignees: ""
|
||||
|
||||
<!-- You can fill out the different items by putting the correct value beside each cell. -->
|
||||
|
||||
| Name | Value |
|
||||
|------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Terra Version | <!-- Put your Terra version here. (remove the comment) -->
|
||||
| Platform / Platform Version | <!-- Put your platform and platform version here. (remove the comment) (eg. Spigot, Fabric, Paper, etc.) (If you are using the Region generator, put that here instead) -->
|
||||
| Any External Plugins or Mods | <!-- Put a list of all the plugins or mods you have installed here. (remove the comment) (Make sure to NOT include any new lines) -->
|
||||
| Terra Packs In Use | <!-- Put a list of all the Terra packs you have installed here. (remove the comment) (Make sure to NOT include any new lines) (/te packs may be used to get a list) -->
|
||||
| Terra Addons In Use | <!-- Put a list of all the Terra addons you have installed here. (remove the comment) (Make sure to NOT include any new lines) (/te addons may be used to get a list) -->
|
||||
| Name | Value |
|
||||
|------------------------------|-------|
|
||||
| Terra Version | <!-- Put your Terra version here. (remove the comment) -->
|
||||
| Platform / Platform Version | <!-- Put your platform and platform version here. (remove the comment) (eg. Spigot, Fabric, Paper, etc.) (If you are using the Region generator, put that here instead) -->
|
||||
| Any External Plugins or Mods | <!-- Put a list of all the plugins or mods you have installed here. (remove the comment) (Make sure to NOT include any new lines) -->
|
||||
| Terra Packs In Use | <!-- Put a list of all the Terra packs you have installed here. (remove the comment) (Make sure to NOT include any new lines) (/te packs may be used to get a list) -->
|
||||
| Terra Addons In Use | <!-- Put a list of all the Terra addons you have installed here. (remove the comment) (Make sure to NOT include any new lines) (/te addons may be used to get a list) -->
|
||||
|
||||
## Issue Description
|
||||
|
||||
|
||||
@@ -1,19 +1,58 @@
|
||||
# Pull Request
|
||||
|
||||
## Description
|
||||
## Brief description.
|
||||
|
||||
<!-- Include a description of the PR here -->
|
||||
<!-- Please provide a brief description of the goals of your PR -->
|
||||
|
||||
<!--
|
||||
If applicable, include 'Fixes #XXXX' or 'Closes #XXXX' for any related open issues.
|
||||
This helps us relate, track, and close the relevant issues.
|
||||
###########################################################################
|
||||
## WARNING! ##
|
||||
## IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN YOUR PR BEING CLOSED ##
|
||||
###########################################################################
|
||||
-->
|
||||
<!--
|
||||
Please go through this checklist item by item and make sure you have successfully completed each of these steps.
|
||||
- Your pull request MUST be either on the latest version of Terra, or on a branch for a future release.
|
||||
- Make sure that there are no already existing PRs that fix this. If so, it will be closed as a duplicate.
|
||||
- Make sure that this change is actually within the scope of Terra and is something a terrain generator should be doing.
|
||||
- Make sure that this is not an issue with a specific Terra *pack*, and instead applies to all of Terra.
|
||||
- Make sure that you have filled out all the required information and given descriptions of everything.
|
||||
-->
|
||||
<!-- You can erase any parts of this template not applicable to your Pull Request. -->
|
||||
|
||||
### What Issues Does This Fix?
|
||||
|
||||
<!--
|
||||
Put Fix #XXXX or Closes #XXXX here if there are any open issues that this PR fixes.
|
||||
This is to automatically close the relevant issues.
|
||||
You may remove this if there is no issue for this PR.
|
||||
But unless this is a very small change, you should make an issue for it.
|
||||
-->
|
||||
|
||||
### Changelog
|
||||
## Licensing
|
||||
|
||||
<!-- In order to be accepted, your changes must be under the GPLv3 license. Please check one of the following: -->
|
||||
|
||||
- [ ] I am the original author of this code, and I am willing to release it
|
||||
under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html).
|
||||
- [ ] I am not the original author of this code, but it is in public domain or
|
||||
released under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html) or a
|
||||
compatible license.
|
||||
<!--
|
||||
Please provide reliable evidence of this.
|
||||
NOTE: for compatible licenses, you must make sure to add the included license somewhere in the program, if so required.
|
||||
(And even if it's not required, it's still nice to do it. Also add attribution somewhere.)
|
||||
-->
|
||||
|
||||
## Goal of the PR
|
||||
|
||||
<!--
|
||||
Fill out a changelog below of what has been done, and what might be planned to be done.
|
||||
You may delete this if your PR is not adding new features, only fixing bugs or adding translations.
|
||||
What is the goal of the PR?
|
||||
Put a checklist here of what has been done
|
||||
(and what *hasn't*, but you plan to do),
|
||||
so we can easily know what was changed.
|
||||
Note: this is only required for PRs that add new features.
|
||||
If your PR is not adding new features, only fixing bugs or adding translations, then you may delete this section.
|
||||
-->
|
||||
|
||||
- [ ] <!-- First thing -->
|
||||
@@ -22,58 +61,51 @@ You may delete this if your PR is not adding new features, only fixing bugs or a
|
||||
- [ ] <!-- Second thing -->
|
||||
- [ ] <!-- etc. -->
|
||||
|
||||
## Checklist
|
||||
## Affects of the PR
|
||||
|
||||
<!--
|
||||
Select the options below that apply.
|
||||
You must put an x in all the boxes that it applies to. (Like this: [x])
|
||||
<!---
|
||||
What types of changes does your code introduce? (Select any that apply. You may select multiple.)
|
||||
You must put an x in all the boxes that it applies to. (Like this: [x])
|
||||
-->
|
||||
|
||||
#### Mandatory checks
|
||||
|
||||
- [ ] The base branch of this PR is an unreleased version branch (that has a `ver/` prefix)
|
||||
or is a branch that is intended to be merged into a version branch.
|
||||
<!--
|
||||
This is not applicable if the PR is a version branch itself.
|
||||
PRs for new versions should use the `master` branch instead.
|
||||
-->
|
||||
- [ ] There are no already existing PRs that provide the same changes.
|
||||
<!-- If this is not applicable, the PR will be removed as a duplicate. -->
|
||||
- [ ] The PR is within the scope of Terra (i.e. is something a configurable terrain generator should be doing).
|
||||
- [ ] Changes follow the code style for this project.
|
||||
<!-- There is an included `.editorconfig` file in the base of the repo. Please use a plugin for your IDE of choice that follows those settings. -->
|
||||
- [ ] I have read the [`CONTRIBUTING.md`](https://github.com/PolyhedralDev/Terra/blob/master/CONTRIBUTING.md)
|
||||
document in the root of the git repository.
|
||||
|
||||
#### Types of changes
|
||||
|
||||
- [ ] Bug Fix <!-- Changes include bug fixes. -->
|
||||
- [ ] Build system <!-- Changes the build system. -->
|
||||
- [ ] Documentation <!-- Changes add to or improve documentation. -->
|
||||
- [ ] New Feature <!-- Changes add new functionality to Terra. -->
|
||||
- [ ] Performance <!-- Changes improve the performance of Terra. -->
|
||||
- [ ] Refactoring <!-- Changes do not add any new code, only moves code around. -->
|
||||
- [ ] Repository <!-- Changes affect the repository. E.g. changes to the `README.md` file. -->
|
||||
- [ ] Revert <!-- Changes revert previous commits. -->
|
||||
- [ ] Style <!-- Changes update style, namely the .editorconfig file. -->
|
||||
- [ ] Tests <!-- Changes add or update tests. -->
|
||||
- [ ] Translation <!-- Changes include translations to other languages for Terra. -->
|
||||
- [ ] Bug Fix <!-- Anything which fixes an issue in Terra. -->
|
||||
- [ ] Build system <!-- Anything which pretain to the build system. -->
|
||||
- [ ]
|
||||
Documentation <!-- Anything which adds or improves documentation for existing features. -->
|
||||
- [ ] New Feature <!-- Anything which adds new functionality to Terra. -->
|
||||
- [ ] Performance <!-- Anything which is imrpoves the performance of Terra. -->
|
||||
- [ ]
|
||||
Refactoring <!-- Anything which does not add any new code, only moves code around. -->
|
||||
- [ ]
|
||||
Repository <!-- Anything which affects the repository. Eg. changes to the `README.md` file. -->
|
||||
- [ ] Revert <!-- Anything which reverts previous commits. -->
|
||||
- [ ] Style <!-- Anything which updates style. -->
|
||||
- [ ] Tests <!-- Anything which adds or updates tests. -->
|
||||
- [ ]
|
||||
Translation <!-- Anything which is internationalizing the Terra program to other languages. -->
|
||||
|
||||
#### Compatibility
|
||||
#### Compatiblity
|
||||
|
||||
<!-- The following options determine if the PR pertains to a major, minor, or patch version bump -->
|
||||
- [ ] Breaking
|
||||
change <!-- A fix, or a feature, that breaks some previous functionality to Terra. -->
|
||||
- [ ] Non-Breaking change.
|
||||
<!--
|
||||
A change which does not break *any* previous functionality of Terra.
|
||||
(ie. is backwards compatible and will work with *any* previously existing supported features.
|
||||
Note: if a feature is annotated with @Incubating, @Preview, @Experimental,
|
||||
or is in a package called something similar to the previous annotations,
|
||||
then you may push breaking changes to only THOSE parts of Terra.)
|
||||
-->
|
||||
|
||||
- [ ] Introduces a breaking change
|
||||
<!--
|
||||
Breaking changes are any fix or feature that breaks some previous functionality to Terra / is not backwards compatible.
|
||||
Breaking changes do not include:
|
||||
- changes that are backwards compatible and will work with *any* previously existing supported features.
|
||||
- changes to code marked as in a pre-release
|
||||
state (annotated with @Incubating, @Preview, @Experimental
|
||||
or in a package called something similar to the previous annotations)
|
||||
-->
|
||||
- [ ] Introduces new functionality in a backwards compatible way.
|
||||
- [ ] Introduces bug fixes
|
||||
#### Contribution Guidelines.
|
||||
|
||||
- [ ] I have read
|
||||
the [`CONTRIBUTING.md`](https://github.com/PolyhedralDev/Terra/blob/master/CONTRIBUTING.md)
|
||||
document in the root of the git repository.
|
||||
- [ ] My code follows the code style for this
|
||||
project. <!-- There is an included `.editorconfig` file in the base of the repo. Please use a plugin for your IDE of choice that follows those settings. -->
|
||||
|
||||
#### Documentation
|
||||
|
||||
@@ -84,21 +116,7 @@ You must put an x in all the boxes that it applies to. (Like this: [x])
|
||||
|
||||
- [ ] I have added tests to cover my changes.
|
||||
- [ ] All new and existing tests passed.
|
||||
<!--
|
||||
Tests are typically not necessary for small changes.
|
||||
Including *some* testing is recommended for large changes where applicable.
|
||||
-->
|
||||
|
||||
#### Licensing
|
||||
|
||||
<!-- In order to be accepted, your changes must be under the GPLv3 license. Please check one of the following: -->
|
||||
|
||||
- [ ] I am the original author of this code, and I am willing to
|
||||
release it under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html).
|
||||
- [ ] I am not the original author of this code, but it is in public domain or
|
||||
released under [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html) or a compatible license.
|
||||
<!--
|
||||
Please provide reliable evidence of this.
|
||||
NOTE: for compatible licenses, you must make sure to add the included license somewhere in the program, if so required.
|
||||
(And even if it's not required, it's still nice to do it. Also add attribution somewhere.)
|
||||
-->
|
||||
<!--
|
||||
If it only introduces small changes, you don't need to add tests.
|
||||
But if you add big changes, you should probably at least write *some* testing, where applicable.
|
||||
-->
|
||||
@@ -1,47 +0,0 @@
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created
|
||||
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle
|
||||
|
||||
name: Gradle Build
|
||||
|
||||
on: [ pull_request ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4.7.1
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
||||
|
||||
- uses: burrunan/gradle-cache-action@v3.0.1
|
||||
name: Build Terra
|
||||
with:
|
||||
# Specifies arguments for Gradle execution
|
||||
# If arguments is missing or empty, then Gradle is not executed
|
||||
arguments: build
|
||||
# arguments can be multi-line for better readability
|
||||
# arguments: |
|
||||
# --no-paralell
|
||||
# build
|
||||
# -x test
|
||||
# Gradle version to use for execution:
|
||||
# wrapper (default), current, rc, nightly, release-nightly, or
|
||||
# versions like 6.6 (see https://services.gradle.org/versions/all)
|
||||
gradle-version: wrapper
|
||||
# Properties are passed as -Pname=value
|
||||
properties: |
|
||||
kotlin.js.compiler=ir
|
||||
kotlin.parallel.tasks.in.project=true
|
||||
+1
-6
@@ -245,9 +245,4 @@ nbdist/
|
||||
|
||||
/run/
|
||||
|
||||
**/testDir/
|
||||
|
||||
platforms/**/run/**
|
||||
|
||||
#Vale Config File
|
||||
**/.vale.ini
|
||||
**/testDir/
|
||||
+34
-14
@@ -315,15 +315,19 @@ Terra has a global moderation team which is currently comprised of the following
|
||||
members:
|
||||
|
||||
- solonovamax
|
||||
- discord: [@solonovamax#6983](https://discord.com/channels/@me/566146322273402881)*
|
||||
-
|
||||
discord: [@solonovamax#6983](https://discord.com/channels/@me/566146322273402881)*
|
||||
- github: [@solonovamax](https://github.com/solonovamax)
|
||||
- email: [solonovamax@12oclockpoint.com](mailto:solonovamax@12oclockpoint.com)
|
||||
-
|
||||
email: [solonovamax@12oclockpoint.com](mailto:solonovamax@12oclockpoint.com)
|
||||
- dfsek
|
||||
- discord: [@dfsek#4208](https://discord.com/channels/@me/378350362236682240)*
|
||||
-
|
||||
discord: [@dfsek#4208](https://discord.com/channels/@me/378350362236682240)*
|
||||
- github: [@dfsek](https://github.com/dfsek)
|
||||
- email: [dfsek@protonmail.com](mailto:dfsek@protonmail.com)
|
||||
- duplex (duplexsystem)
|
||||
- discord: [@Duplex#0797](https://discord.com/channels/@me/356822848641171456)*
|
||||
-
|
||||
discord: [@Duplex#0797](https://discord.com/channels/@me/356822848641171456)*
|
||||
- github: [@duplexsystem](https://github.com/duplexsystem)
|
||||
- email: [duplexsys@protonmail.com](mailto:duplexsys@protonmail.com)
|
||||
|
||||
@@ -397,17 +401,32 @@ issue on this github repo, or contact a member of the global moderation team.
|
||||
## License and Attribution
|
||||
|
||||
This set of guidelines is distributed under a
|
||||
[Creative Commons Attribution-ShareAlike license](https://creativecommons.org/licenses/by-sa/3.0/).
|
||||
[Creative Commons Attribution-ShareAlike license](https://creativecommons.org/licenses/by-sa/3.0/)
|
||||
.
|
||||
|
||||
These guidelines have been adapted with modifications from the following sources:
|
||||
These guidelines have been adapted from
|
||||
[Mozilla's Community Participation Guidelines](https://www.mozilla.org/en-US/about/governance/policies/participation/)
|
||||
, which were adapted from:
|
||||
|
||||
- [Mozilla's Community Participation Guidelines](https://www.mozilla.org/en-US/about/governance/policies/participation/)
|
||||
- Mozilla's original Community Participation Guidelines
|
||||
- The [Ubuntu Code of Conduct](https://ubuntu.com/community/code-of-conduct)
|
||||
- Mozilla's [View Source Conference Code of Conduct](https://viewsourceconf.org/berlin-2016/code-of-conduct/)
|
||||
- The [Rust Language Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct)
|
||||
- The [Stumptown Syndicate's Citizen Code of Conduct](http://citizencodeofconduct.org/)
|
||||
- The [LGBTQ in Technology Code of Conduct](https://lgbtq.technology/coc.html)
|
||||
- The [WisCon code of conduct](http://wiscon.net/policies/anti-harassment/code-of-conduct/)
|
||||
-
|
||||
|
||||
Mozilla's [View Source Conference Code of Conduct](https://viewsourceconf.org/berlin-2016/code-of-conduct/)
|
||||
|
||||
- And
|
||||
the [Rust Language Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct)
|
||||
|
||||
which in turn were based
|
||||
on [Stumptown Syndicate's Citizen Code of Conduct](http://citizencodeofconduct.org/)
|
||||
, along with some adapted text from
|
||||
the [LGBTQ in Technology Code of Conduct](https://lgbtq.technology/coc.html) and
|
||||
the [WisCon code of conduct](http://wiscon.net/policies/anti-harassment/code-of-conduct/)
|
||||
.
|
||||
|
||||
It was then modified by solonovamax with various inclusions from
|
||||
the [LGBTQ in Technology Code of Conduct](https://lgbtq.technology/coc.html) and
|
||||
a few other sources.
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -424,6 +443,7 @@ people are not comfortable
|
||||
using [neopronouns](https://www.mypronouns.org/neopronouns). But if someone
|
||||
refuses to use your more common pronouns, you should report them to us.
|
||||
Additionally, you may not ask people to use unreasonable pronouns, such as '
|
||||
acab/acabself', 'that/bitch', 'ur/mom', or anything else that may be considered
|
||||
disrectful. Doing so will be considered mockery of individuals who use
|
||||
acab/acabself', 'that/bitch', 'ur/mom', or
|
||||
'dream/dreamself' (pronouns related to real people, eg. the minecraft youtuber '
|
||||
dreamwastaken'). Doing so will be considered mockery of individuals who use
|
||||
non-standard pronouns and is very disrespectful.
|
||||
+2
-5
@@ -63,8 +63,7 @@ to [Terra global moderation team](CODE_OF_CONDUCT.md#Reporting).
|
||||
|
||||
## I don't want to read this whole thing I just have a question!!!
|
||||
|
||||
> **Note:** Please don't file an issue to ask a question. You'll get faster
|
||||
> results by using the resources below.
|
||||
> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below.
|
||||
|
||||
We have an official discord server where you can request help from various users
|
||||
|
||||
@@ -104,9 +103,7 @@ you don't need to create one. When you are creating a bug report,
|
||||
please [include as many details as possible](#how-do-i-submit-a-good-bug-report)
|
||||
.
|
||||
|
||||
> **Note:** If you find a **Closed** issue that seems like it is the same thing
|
||||
> that you're experiencing, open a new issue and include a link to the original
|
||||
> issue in the body of your new one.
|
||||
> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.
|
||||
|
||||
#### Before Submitting A Bug Report
|
||||
|
||||
|
||||
Vendored
-149
@@ -1,149 +0,0 @@
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
tools {
|
||||
jdk "Temurin Java 21"
|
||||
}
|
||||
|
||||
triggers {
|
||||
githubPush()
|
||||
}
|
||||
|
||||
environment {
|
||||
DISCORD_WEBHOOK_URL = credentials('polydev-discord-webhook-url')
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
scmSkip(deleteBuild: true)
|
||||
}
|
||||
}
|
||||
|
||||
stage('Setup Gradle') {
|
||||
steps {
|
||||
sh 'chmod +x gradlew'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
steps {
|
||||
withGradle {
|
||||
sh './gradlew build --rerun-tasks -x check'
|
||||
sh './gradlew javadoc'
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
success {
|
||||
archiveArtifacts artifacts: 'platforms/fabric/build/libs/Terra-fabric*.jar,platforms/bukkit/build/libs/Terra-bukkit*-shaded.jar,platforms/allay/build/libs/Terra-allay*.jar,platforms/minestom/build/libs/Terra-minestom*.jar', fingerprint: true, onlyIfSuccessful: true
|
||||
|
||||
javadoc javadocDir: 'common/api/build/docs/javadoc', keepAll: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Tests') {
|
||||
steps {
|
||||
withGradle {
|
||||
sh './gradlew test --rerun-tasks'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stage('Deploy to snapshots repositories') {
|
||||
// when {
|
||||
// allOf {
|
||||
// not { buildingTag() }
|
||||
// not { expression { env.TAG_NAME != null && env.TAG_NAME.matches('v\\d+\\.\\d+\\.\\d+') } }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// steps {
|
||||
// withCredentials([
|
||||
// string(credentialsId: 'maven-signing-key', variable: 'ORG_GRADLE_PROJECT_signingKey'),
|
||||
// string(credentialsId: 'maven-signing-key-password', variable: 'ORG_GRADLE_PROJECT_signingPassword'),
|
||||
// usernamePassword(
|
||||
// credentialsId: 'solo-studios-maven',
|
||||
// passwordVariable: 'ORG_GRADLE_PROJECT_SoloStudiosSnapshotsPassword',
|
||||
// usernameVariable: 'ORG_GRADLE_PROJECT_SoloStudiosSnapshotsUsername'
|
||||
// )
|
||||
// ]) {
|
||||
// withGradle {
|
||||
// sh './gradlew publishAllPublicationsToSoloStudiosSnapshotsRepository'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
stage('Deploy to releases repositories') {
|
||||
// when {
|
||||
// allOf {
|
||||
// buildingTag()
|
||||
// expression { env.TAG_NAME != null && env.TAG_NAME.matches('v\\d+\\.\\d+\\.\\d+') }
|
||||
// }
|
||||
// }
|
||||
|
||||
steps {
|
||||
withCredentials([
|
||||
string(credentialsId: 'maven-signing-key', variable: 'ORG_GRADLE_PROJECT_signingKey'),
|
||||
string(credentialsId: 'maven-signing-key-password', variable: 'ORG_GRADLE_PROJECT_signingPassword'),
|
||||
usernamePassword(
|
||||
credentialsId: 'solo-studios-maven',
|
||||
passwordVariable: 'ORG_GRADLE_PROJECT_SoloStudiosReleasesPassword',
|
||||
usernameVariable: 'ORG_GRADLE_PROJECT_SoloStudiosReleasesUsername'
|
||||
),
|
||||
// TODO: does not yet exist (uncomment once added)
|
||||
// usernamePassword(
|
||||
// credentialsId: 'sonatype-maven-credentials',
|
||||
// passwordVariable: 'ORG_GRADLE_PROJECT_SonatypePassword',
|
||||
// usernameVariable: 'ORG_GRADLE_PROJECT_SonatypeUsername'
|
||||
// ),
|
||||
// usernamePassword(
|
||||
// credentialsId: 'codemc-maven-credentials',
|
||||
// passwordVariable: 'ORG_GRADLE_PROJECT_CodeMCPassword',
|
||||
// usernameVariable: 'ORG_GRADLE_PROJECT_CodeMCUsername'
|
||||
// )
|
||||
]) {
|
||||
withGradle {
|
||||
sh './gradlew publish'
|
||||
//sh './gradlew publishAllPublicationsToSoloStudiosReleasesRepository'
|
||||
// sh './gradlew publishAllPublicationsToSonatypeRepository'
|
||||
// sh './gradlew publishAllPublicationsToCodeMCRepository'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
discoverReferenceBuild()
|
||||
|
||||
// junit testResults: '**/build/test-results/*/TEST-*.xml'
|
||||
|
||||
recordIssues(
|
||||
aggregatingResults: true,
|
||||
enabledForFailure: true,
|
||||
minimumSeverity: 'ERROR',
|
||||
sourceCodeEncoding: 'UTF-8',
|
||||
checksAnnotationScope: 'ALL',
|
||||
sourceCodeRetention: 'LAST_BUILD',
|
||||
tools: [java(), javaDoc()]
|
||||
)
|
||||
|
||||
discordSend(
|
||||
title: env.JOB_NAME + ' ' + env.BUILD_DISPLAY_NAME,
|
||||
showChangeset: true,
|
||||
enableArtifactsList: true,
|
||||
link: env.BUILD_URL,
|
||||
result: currentBuild.currentResult,
|
||||
customAvatarUrl: 'https://github.com/PolyhedralDev.png',
|
||||
customUsername: 'Solo Studios Jenkins',
|
||||
webhookURL: env.DISCORD_WEBHOOK_URL,
|
||||
)
|
||||
|
||||
cleanWs()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2025 Polyhedral Development
|
||||
Copyright (c) 2020-2021 Polyhedral Development
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -47,7 +47,14 @@ JARs are produced in `platforms/<platform>/build/libs`.
|
||||
To run Minecraft with Terra in the IDE (for testing) use the following tasks:
|
||||
|
||||
* Bukkit
|
||||
* `runServer` - Run the Paper test server with Terra installed.
|
||||
* `installPaper` - Install a [Paper](https://github.com/PaperMC/Paper) test
|
||||
server. (Only needs to be run once).
|
||||
* `installPurpur` - Install a [Purpur](https://github.com/pl3xgaming/Purpur)
|
||||
test server. (Only needs to be run once).
|
||||
* `runPaper` - Run the Paper test server with Terra (`installPaper` must
|
||||
have been run previously).
|
||||
* `runPurpur` - Run the Purpur test server with Terra (`installPurpur` must
|
||||
have been run previously).
|
||||
* Fabric
|
||||
* `runClient` - Run a Minecraft Fabric client with Terra installed.
|
||||
* `runServer` - Run a Minecraft Fabric server with Terra installed.
|
||||
|
||||
+13
-20
@@ -1,59 +1,52 @@
|
||||
preRelease(true)
|
||||
|
||||
versionProjects(":common:api", version("7.0.0"))
|
||||
versionProjects(":common:implementation", version("7.0.0"))
|
||||
versionProjects(":platforms", version("7.0.0"))
|
||||
versionProjects(":common:api", version("6.0.0"))
|
||||
versionProjects(":common:implementation", version("6.0.0"))
|
||||
versionProjects(":platforms", version("6.0.0"))
|
||||
|
||||
|
||||
allprojects {
|
||||
group = "com.dfsek.terra"
|
||||
|
||||
|
||||
configureCompilation()
|
||||
configureDependencies()
|
||||
configurePublishing()
|
||||
|
||||
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
options.isFork = true
|
||||
options.isIncremental = true
|
||||
options.release.set(21)
|
||||
}
|
||||
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
useJUnitPlatform()
|
||||
|
||||
|
||||
maxHeapSize = "2G"
|
||||
ignoreFailures = false
|
||||
failFast = true
|
||||
maxParallelForks = (Runtime.getRuntime().availableProcessors() - 1).takeIf { it > 0 } ?: 1
|
||||
|
||||
|
||||
reports.html.required.set(false)
|
||||
reports.junitXml.required.set(false)
|
||||
}
|
||||
|
||||
|
||||
tasks.withType<Copy>().configureEach {
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
|
||||
|
||||
tasks.withType<Jar>().configureEach {
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
forImmediateSubProjects(":platforms") {
|
||||
forSubProjects(":platforms") {
|
||||
configureDistribution()
|
||||
}
|
||||
project(":platforms:bukkit:common").configureDistribution()
|
||||
project(":platforms:minestom:example").configureDistribution()
|
||||
forSubProjects(":common:addons") {
|
||||
apply(plugin = "com.gradleup.shadow")
|
||||
|
||||
tasks.named("build") {
|
||||
finalizedBy(tasks.named("shadowJar"))
|
||||
}
|
||||
|
||||
dependencies {
|
||||
"compileOnly"(project(":common:api"))
|
||||
"shadedImplementation"("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
|
||||
"testImplementation"("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
|
||||
"testImplementation"(project(":common:api"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,27 +6,13 @@ plugins {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
maven("https://maven.solo-studios.ca/releases") {
|
||||
name = "Solo Studios"
|
||||
}
|
||||
maven("https://maven.solo-studios.ca/snapshots") {
|
||||
name = "Solo Studios"
|
||||
}
|
||||
maven("https://repo.codemc.org/repository/maven-public") {
|
||||
name = "CodeMC"
|
||||
}
|
||||
maven("https://repo.papermc.io/repository/maven-public/") {
|
||||
name = "PaperMC"
|
||||
}
|
||||
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
//TODO Allow pulling from Versions.kt
|
||||
implementation("com.gradleup.shadow", "shadow-gradle-plugin", "8.3.9")
|
||||
|
||||
implementation("io.papermc.paperweight.userdev", "io.papermc.paperweight.userdev.gradle.plugin", "2.0.0-beta.18")
|
||||
implementation("org.ow2.asm", "asm", "9.9")
|
||||
implementation("org.ow2.asm", "asm-tree", "9.9")
|
||||
implementation("com.dfsek.tectonic", "common", "4.3.1")
|
||||
implementation("org.yaml", "snakeyaml", "2.5")
|
||||
implementation("gradle.plugin.com.github.jengelman.gradle.plugins:shadow:+")
|
||||
implementation("org.ow2.asm:asm:9.2")
|
||||
implementation("org.ow2.asm:asm-tree:9.2")
|
||||
implementation("com.dfsek.tectonic:common:4.2.0")
|
||||
implementation("org.yaml:snakeyaml:1.27")
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import java.io.File
|
||||
import java.util.function.Predicate
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
import org.gradle.kotlin.dsl.extra
|
||||
import kotlin.streams.asStream
|
||||
|
||||
@@ -11,33 +12,31 @@ import kotlin.streams.asStream
|
||||
* Configures a directory where addons will be put.
|
||||
*/
|
||||
fun Project.addonDir(dir: File, task: Task) {
|
||||
val moveAddons = tasks.register("moveAddons" + task.name) {
|
||||
dependsOn("compileAddons")
|
||||
doLast {
|
||||
dir.parentFile.mkdirs()
|
||||
matchingAddons(dir) {
|
||||
it.name.startsWith("Terra-") // Assume everything that starts with Terra- is a core addon.
|
||||
}.forEach {
|
||||
logger.info("Deleting old addon: " + it.absolutePath)
|
||||
it.delete()
|
||||
}
|
||||
forSubProjects(":common:addons") {
|
||||
val jar = tasks.named("shadowJar").get() as ShadowJar
|
||||
|
||||
val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else ""
|
||||
val target = File(dir, boot + jar.archiveFileName.get())
|
||||
|
||||
val base = "${jar.archiveBaseName.get()}-${version}"
|
||||
|
||||
logger.info("Copying addon ${jar.archiveFileName.get()} to ${target.absolutePath}. Base name: $base")
|
||||
|
||||
jar.archiveFile.orNull?.asFile?.copyTo(target)
|
||||
}
|
||||
task.doFirst {
|
||||
dir.parentFile.mkdirs()
|
||||
matchingAddons(dir) {
|
||||
it.name.startsWith("Terra-") // Assume everything that starts with Terra- is a core addon.
|
||||
}.forEach {
|
||||
println("Deleting old addon: " + it.absolutePath)
|
||||
it.delete()
|
||||
}
|
||||
forSubProjects(":common:addons") {
|
||||
val jar = if (tasks.findByName("shadowJar") != null) {
|
||||
(tasks.named("shadowJar").get() as ShadowJar)
|
||||
} else {
|
||||
(tasks.named("jar").get() as Jar)
|
||||
}
|
||||
|
||||
val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else ""
|
||||
val target = File(dir, boot + jar.archiveFileName.get())
|
||||
|
||||
val base = "${jar.archiveBaseName.get()}-${version}"
|
||||
|
||||
println("Copying addon ${jar.archiveFileName.get()} to ${target.absolutePath}. Base name: $base")
|
||||
|
||||
jar.archiveFile.orNull?.asFile?.copyTo(target)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
task.dependsOn(moveAddons)
|
||||
}
|
||||
|
||||
fun matchingAddons(dir: File, matcher: Predicate<File>): Set<File> {
|
||||
|
||||
@@ -13,7 +13,6 @@ import org.gradle.kotlin.dsl.getByName
|
||||
import org.gradle.kotlin.dsl.register
|
||||
import org.gradle.kotlin.dsl.withType
|
||||
import org.gradle.language.jvm.tasks.ProcessResources
|
||||
import org.gradle.plugins.ide.idea.model.IdeaModel
|
||||
|
||||
fun Project.configureCompilation() {
|
||||
apply(plugin = "maven-publish")
|
||||
@@ -22,16 +21,9 @@ fun Project.configureCompilation() {
|
||||
apply(plugin = "idea")
|
||||
apply<TectonicDocPlugin>()
|
||||
|
||||
configure<IdeaModel> {
|
||||
module {
|
||||
isDownloadJavadoc = true
|
||||
isDownloadSources = true
|
||||
}
|
||||
}
|
||||
|
||||
configure<JavaPluginExtension> {
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
|
||||
@@ -3,15 +3,13 @@ import org.gradle.kotlin.dsl.creating
|
||||
import org.gradle.kotlin.dsl.dependencies
|
||||
import org.gradle.kotlin.dsl.getValue
|
||||
import org.gradle.kotlin.dsl.getting
|
||||
import org.gradle.kotlin.dsl.maven
|
||||
import org.gradle.kotlin.dsl.repositories
|
||||
|
||||
fun Project.configureDependencies() {
|
||||
val testImplementation by configurations.getting
|
||||
val compileOnly by configurations.getting
|
||||
|
||||
val api by configurations.getting
|
||||
val implementation by configurations.getting
|
||||
val testImplementation by configurations.getting
|
||||
val compileOnly by configurations.getting
|
||||
|
||||
val shaded by configurations.creating
|
||||
|
||||
@@ -30,44 +28,17 @@ fun Project.configureDependencies() {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
maven("https://maven.solo-studios.ca/releases") {
|
||||
name = "Solo Studios"
|
||||
}
|
||||
maven("https://maven.solo-studios.ca/snapshots") {
|
||||
name = "Solo Studios"
|
||||
}
|
||||
maven("https://maven.fabricmc.net/") {
|
||||
name = "FabricMC"
|
||||
}
|
||||
maven("https://repo.codemc.org/repository/maven-public") {
|
||||
name = "CodeMC"
|
||||
}
|
||||
maven("https://repo.papermc.io/repository/maven-public/") {
|
||||
name = "PaperMC"
|
||||
}
|
||||
maven("https://files.minecraftforge.net/maven/") {
|
||||
name = "Forge"
|
||||
}
|
||||
maven("https://maven.quiltmc.org/repository/release/") {
|
||||
name = "Quilt"
|
||||
}
|
||||
maven("https://jitpack.io") {
|
||||
name = "JitPack"
|
||||
}
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") {
|
||||
name = "Sonatype Snapshots"
|
||||
}
|
||||
maven("https://repo.onarandombox.com/multiverse-releases") {
|
||||
name = "onarandombox"
|
||||
}
|
||||
maven { url = uri("https://maven.fabricmc.net/") }
|
||||
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
|
||||
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation("org.junit.jupiter", "junit-jupiter", Versions.Libraries.Internal.junit)
|
||||
"testRuntimeOnly"("org.junit.platform", "junit-platform-launcher")
|
||||
compileOnly("org.jetbrains", "annotations", Versions.Libraries.Internal.jetBrainsAnnotations)
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.7.0")
|
||||
compileOnly("org.jetbrains:annotations:23.0.0")
|
||||
|
||||
compileOnly("com.google.guava", "guava", Versions.Libraries.Internal.guava)
|
||||
testImplementation("com.google.guava", "guava", Versions.Libraries.Internal.guava)
|
||||
compileOnly("com.google.guava:guava:30.0-jre")
|
||||
testImplementation("com.google.guava:guava:30.0-jre")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import io.papermc.paperweight.util.path
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.FileWriter
|
||||
import java.net.URL
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.Path
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.BasePluginExtension
|
||||
@@ -16,88 +17,63 @@ import org.gradle.kotlin.dsl.get
|
||||
import org.gradle.kotlin.dsl.named
|
||||
import org.yaml.snakeyaml.DumperOptions
|
||||
import org.yaml.snakeyaml.Yaml
|
||||
import kotlin.io.path.copyTo
|
||||
import kotlin.io.path.createDirectories
|
||||
import kotlin.io.path.createFile
|
||||
import kotlin.io.path.exists
|
||||
|
||||
private fun Project.installAddonsInto(dest: Path) {
|
||||
FileSystems.newFileSystem(dest, mapOf("create" to "false"), null).use { fs ->
|
||||
forSubProjects(":common:addons") {
|
||||
val jar = getJarTask()
|
||||
|
||||
logger.info("Packaging addon ${jar.archiveFileName.get()} to $dest. size: ${jar.archiveFile.get().asFile.length() / 1024}KB")
|
||||
|
||||
val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else ""
|
||||
val addonPath = fs.getPath("/addons/$boot${jar.archiveFileName.get()}")
|
||||
|
||||
if (!addonPath.exists()) {
|
||||
addonPath.parent.createDirectories()
|
||||
addonPath.createFile()
|
||||
jar.archiveFile.get().asFile.toPath().copyTo(addonPath, overwrite = true)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.configureDistribution() {
|
||||
apply(plugin = "com.gradleup.shadow")
|
||||
apply(plugin = "com.github.johnrengelman.shadow")
|
||||
|
||||
val downloadDefaultPacks = tasks.create("downloadDefaultPacks") {
|
||||
group = "terra"
|
||||
doFirst {
|
||||
try {
|
||||
file("${buildDir}/resources/main/packs/").deleteRecursively()
|
||||
file("${buildDir}/resources/main/metapacks/").deleteRecursively()
|
||||
val overworldPackUrl =
|
||||
URL("https://github.com/PolyhedralDev/TerraOverworldConfig/releases/download/" + Versions.Terra.overworldConfig + "/Overworld.zip")
|
||||
val reimagENDPackUrl =
|
||||
URL("https://github.com/PolyhedralDev/ReimagEND/releases/download/" + Versions.Terra.reimagENDConfig + "/ReimagEND.zip")
|
||||
val tartarusPackUrl =
|
||||
URL("https://github.com/PolyhedralDev/Tartarus/releases/download/" + Versions.Terra.tartarusConfig + "/Tartarus.zip")
|
||||
val defaultPackUrl =
|
||||
URL("https://github.com/PolyhedralDev/DefaultMetapack/releases/download/" + Versions.Terra.defaultConfig + "/default.zip")
|
||||
downloadPack(overworldPackUrl, project)
|
||||
downloadPack(reimagENDPackUrl, project)
|
||||
downloadPack(tartarusPackUrl, project)
|
||||
downloadPack(defaultPackUrl, project, true)
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val compileAddons = tasks.create("compileAddons") {
|
||||
forSubProjects(":common:addons") {
|
||||
afterEvaluate {
|
||||
dependsOn(getJarTask())
|
||||
}
|
||||
file("${buildDir}/resources/main/packs/").deleteRecursively()
|
||||
val defaultPackUrl = URL("https://github.com/PolyhedralDev/TerraOverworldConfig/releases/download/latest/default.zip")
|
||||
downloadPack(defaultPackUrl, project)
|
||||
}
|
||||
}
|
||||
|
||||
val installAddons = tasks.create("installAddons") {
|
||||
group = "terra"
|
||||
dependsOn(compileAddons)
|
||||
|
||||
doLast {
|
||||
// https://github.com/johnrengelman/shadow/issues/111
|
||||
val dest = tasks.named<ShadowJar>("shadowJar").get().archiveFile.get().path
|
||||
installAddonsInto(dest)
|
||||
forSubProjects(":common:addons") {
|
||||
afterEvaluate {
|
||||
dependsOn(getJarTask())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.create("installAddonsIntoDefaultJar") {
|
||||
group = "terra"
|
||||
dependsOn(compileAddons)
|
||||
|
||||
doLast {
|
||||
val dest = tasks.named<Jar>("jar").get().archiveFile.get().path
|
||||
installAddonsInto(dest)
|
||||
// The addons are copied into a JAR because of a ShadowJar bug
|
||||
// which expands *all* JARs, even resource ones, into the fat JAR.
|
||||
// To get around this, we copy all addon JARs into a *new* JAR,
|
||||
// then, ShadowJar expands the newly created JAR, putting the original
|
||||
// JARs where they should go.
|
||||
//
|
||||
// https://github.com/johnrengelman/shadow/issues/111
|
||||
val dest = File(buildDir, "/resources/main/addons.jar")
|
||||
dest.parentFile.mkdirs()
|
||||
|
||||
val zip = ZipOutputStream(FileOutputStream(dest))
|
||||
|
||||
forSubProjects(":common:addons") {
|
||||
val jar = getJarTask()
|
||||
|
||||
println("Packaging addon ${jar.archiveFileName.get()} to ${dest.absolutePath}. size: ${jar.archiveFile.get().asFile.length() / 1024}KB")
|
||||
|
||||
val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else ""
|
||||
|
||||
val entry = ZipEntry("addons/$boot${jar.archiveFileName.get()}")
|
||||
zip.putNextEntry(entry)
|
||||
FileInputStream(jar.archiveFile.get().asFile).run {
|
||||
copyTo(zip)
|
||||
close()
|
||||
}
|
||||
zip.closeEntry()
|
||||
}
|
||||
zip.close()
|
||||
}
|
||||
}
|
||||
|
||||
val generateResourceManifest = tasks.create("generateResourceManifest") {
|
||||
group = "terra"
|
||||
dependsOn(downloadDefaultPacks)
|
||||
dependsOn(installAddons)
|
||||
doLast {
|
||||
val resources = HashMap<String, MutableList<String>>()
|
||||
val packsDir = File("${project.buildDir}/resources/main/packs/")
|
||||
@@ -107,13 +83,6 @@ fun Project.configureDistribution() {
|
||||
resources.computeIfAbsent("packs") { ArrayList() }.add(it.name)
|
||||
}
|
||||
|
||||
val metaPacksDir = File("${project.buildDir}/resources/main/metapacks/")
|
||||
|
||||
metaPacksDir.walkTopDown().forEach {
|
||||
if (it.isDirectory || !it.name.endsWith(".zip")) return@forEach
|
||||
resources.computeIfAbsent("metapacks") { ArrayList() }.add(it.name)
|
||||
}
|
||||
|
||||
val langDir = File("${project(":common:implementation").buildDir}/resources/main/lang/")
|
||||
|
||||
langDir.walkTopDown().forEach {
|
||||
@@ -142,34 +111,25 @@ fun Project.configureDistribution() {
|
||||
val manifest = File("${project.buildDir}/resources/main/resources.yml")
|
||||
|
||||
if (manifest.exists()) manifest.delete()
|
||||
manifest.parentFile.mkdirs()
|
||||
manifest.createNewFile()
|
||||
FileWriter(manifest).use {
|
||||
yaml.dump(resources, it)
|
||||
}
|
||||
|
||||
yaml.dump(resources, FileWriter(manifest))
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("processResources") {
|
||||
generateResourceManifest.mustRunAfter(downloadDefaultPacks)
|
||||
finalizedBy(downloadDefaultPacks)
|
||||
finalizedBy(generateResourceManifest)
|
||||
}
|
||||
|
||||
tasks["processResources"].dependsOn(generateResourceManifest)
|
||||
|
||||
tasks.named<ShadowJar>("shadowJar") {
|
||||
// Tell shadow to download the packs
|
||||
dependsOn(downloadDefaultPacks)
|
||||
|
||||
configurations = listOf(project.configurations["shaded"])
|
||||
|
||||
archiveClassifier.set("shaded")
|
||||
version = project.version
|
||||
setVersion(project.version)
|
||||
relocate("org.apache.commons", "com.dfsek.terra.lib.commons")
|
||||
relocate("org.objectweb.asm", "com.dfsek.terra.lib.asm")
|
||||
relocate("org.json", "com.dfsek.terra.lib.json")
|
||||
relocate("org.yaml", "com.dfsek.terra.lib.yaml")
|
||||
|
||||
finalizedBy(installAddons)
|
||||
}
|
||||
|
||||
configure<BasePluginExtension> {
|
||||
@@ -181,12 +141,17 @@ fun Project.configureDistribution() {
|
||||
}
|
||||
}
|
||||
|
||||
fun downloadPack(packUrl: URL, project: Project, metapack: Boolean = false) {
|
||||
fun downloadPack(packUrl: URL, project: Project) {
|
||||
val fileName = packUrl.file.substring(packUrl.file.lastIndexOf("/"))
|
||||
val resourceType = if (metapack) "metapacks" else "packs"
|
||||
val file = File("${project.buildDir}/resources/main/${resourceType}/${fileName}")
|
||||
val file = File("${project.buildDir}/resources/main/packs/${fileName}")
|
||||
file.parentFile.mkdirs()
|
||||
file.outputStream().write(packUrl.readBytes())
|
||||
}
|
||||
|
||||
fun Project.getJarTask() = tasks.named("shadowJar").get() as ShadowJar
|
||||
fun Project.getJarTask(): Jar {
|
||||
return if (tasks.findByName("shadowJar") != null) {
|
||||
(tasks.named("shadowJar").get() as ShadowJar)
|
||||
} else {
|
||||
(tasks.named("jar").get() as Jar)
|
||||
}
|
||||
}
|
||||
@@ -16,17 +16,16 @@ fun Project.configurePublishing() {
|
||||
}
|
||||
|
||||
repositories {
|
||||
val mavenUrl = "https://maven.solo-studios.ca/releases/"
|
||||
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
|
||||
//val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/"
|
||||
|
||||
maven(mavenUrl) {
|
||||
val SoloStudiosReleasesUsername: String? by project
|
||||
val SoloStudiosReleasesPassword: String? by project
|
||||
|
||||
if (SoloStudiosReleasesUsername != null && SoloStudiosReleasesPassword != null) {
|
||||
val mavenUsername: String? by project
|
||||
val mavenPassword: String? by project
|
||||
if (mavenUsername != null && mavenPassword != null) {
|
||||
credentials {
|
||||
username = SoloStudiosReleasesUsername
|
||||
password = SoloStudiosReleasesPassword
|
||||
username = mavenUsername
|
||||
password = mavenPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,12 +29,6 @@ fun Project.forSubProjects(project: String, action: Action<Project>) {
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.forImmediateSubProjects(project: String, action: Action<Project>) {
|
||||
project(project).childProjects.forEach {
|
||||
action.execute(it.value)
|
||||
}
|
||||
}
|
||||
|
||||
fun preRelease(preRelease: Boolean) {
|
||||
isPrerelease = preRelease
|
||||
}
|
||||
@@ -42,10 +36,10 @@ fun preRelease(preRelease: Boolean) {
|
||||
fun Project.versionProjects(project: String, version: String) {
|
||||
forSubProjects(project) {
|
||||
this.version = version
|
||||
logger.info("Setting version of $path to $version")
|
||||
println("Setting version of $path to $version")
|
||||
}
|
||||
project(project).version = version
|
||||
logger.info("Setting version of $project to $version")
|
||||
println("Setting version of $project to $version")
|
||||
}
|
||||
|
||||
fun Project.version(version: String): String {
|
||||
|
||||
@@ -1,101 +1,39 @@
|
||||
object Versions {
|
||||
object Terra {
|
||||
const val overworldConfig = "latest"
|
||||
const val reimagENDConfig = "latest"
|
||||
const val tartarusConfig = "latest"
|
||||
const val defaultConfig = "latest"
|
||||
}
|
||||
|
||||
object Libraries {
|
||||
const val tectonic = "4.3.1"
|
||||
const val paralithic = "2.0.1"
|
||||
const val strata = "1.3.2"
|
||||
const val seismic = "2.5.7"
|
||||
const val tectonic = "4.2.0"
|
||||
const val paralithic = "0.6.0"
|
||||
const val strata = "1.1.1"
|
||||
|
||||
const val cloud = "2.0.0"
|
||||
const val cloud = "1.6.2"
|
||||
|
||||
const val caffeine = "3.2.2"
|
||||
const val slf4j = "1.7.36"
|
||||
const val log4j_slf4j_impl = "2.14.1"
|
||||
|
||||
const val slf4j = "2.0.17"
|
||||
|
||||
object Internal {
|
||||
const val shadow = "8.3.9"
|
||||
const val apacheText = "1.14.0"
|
||||
const val apacheIO = "2.20.0"
|
||||
const val guava = "33.5.0-jre"
|
||||
const val asm = "9.9"
|
||||
const val snakeYml = "2.5"
|
||||
const val jetBrainsAnnotations = "26.0.2-1"
|
||||
const val junit = "6.0.0"
|
||||
const val nbt = "6.1"
|
||||
const val apacheText = "1.9"
|
||||
const val jafama = "2.3.2"
|
||||
const val apacheIO = "2.6"
|
||||
const val asm = "9.2"
|
||||
const val fastutil = "8.5.6"
|
||||
}
|
||||
}
|
||||
|
||||
object Fabric {
|
||||
const val fabricAPI = "0.134.1+${Mod.minecraft}"
|
||||
const val cloud = "2.0.0-beta.13"
|
||||
const val fabricLoader = "0.14.2"
|
||||
const val fabricAPI = "0.51.1+1.18.2"
|
||||
const val minecraft = "1.18.2"
|
||||
const val yarn = "$minecraft+build.3"
|
||||
const val permissionsAPI = "0.1-SNAPSHOT"
|
||||
}
|
||||
//
|
||||
// object Quilt {
|
||||
// const val quiltLoader = "0.20.2"
|
||||
// const val fabricApi = "7.3.1+0.89.3-1.20.1"
|
||||
// }
|
||||
|
||||
object Mod {
|
||||
const val mixin = "0.16.4+mixin.0.8.7"
|
||||
const val mixinExtras = "0.5.0"
|
||||
|
||||
const val minecraft = "1.21.10"
|
||||
const val yarn = "$minecraft+build.1"
|
||||
const val fabricLoader = "0.18.2"
|
||||
|
||||
const val architecuryLoom = "1.11.451"
|
||||
const val architecturyPlugin = "3.4.162"
|
||||
|
||||
}
|
||||
//
|
||||
// object Forge {
|
||||
// const val forge = "${Mod.minecraft}-48.0.13"
|
||||
// const val burningwave = "12.63.0"
|
||||
// }
|
||||
|
||||
object Bukkit {
|
||||
const val minecraft = "1.21.10"
|
||||
const val nms = "$minecraft-R0.1"
|
||||
const val paperBuild = "$nms-20251012.013929-7"
|
||||
const val paper = paperBuild
|
||||
const val paperLib = "1.0.8"
|
||||
const val reflectionRemapper = "0.1.3"
|
||||
const val paperDevBundle = paperBuild
|
||||
const val runPaper = "2.3.1"
|
||||
const val paperWeight = "2.0.0-beta.19"
|
||||
const val cloud = "2.0.0-beta.12"
|
||||
const val multiverse = "5.3.0"
|
||||
const val paper = "1.18-R0.1-SNAPSHOT"
|
||||
const val paperLib = "1.0.5"
|
||||
}
|
||||
|
||||
//
|
||||
// object Sponge {
|
||||
// const val sponge = "9.0.0-SNAPSHOT"
|
||||
// const val mixin = "0.8.2"
|
||||
// const val minecraft = "1.17.1"
|
||||
// }
|
||||
//
|
||||
object CLI {
|
||||
const val logback = "1.5.19"
|
||||
const val picocli = "4.7.7"
|
||||
object Sponge {
|
||||
const val sponge = "9.0.0-SNAPSHOT"
|
||||
const val mixin = "0.8.2"
|
||||
const val minecraft = "1.17.1"
|
||||
}
|
||||
|
||||
object Allay {
|
||||
const val api = "0.13.0"
|
||||
const val gson = "2.13.2"
|
||||
|
||||
const val mappings = "15398c1"
|
||||
const val mappingsGenerator = "8fa6058"
|
||||
|
||||
const val mcmeta = "e85a17c"
|
||||
}
|
||||
|
||||
object Minestom {
|
||||
const val minestom = "2025.10.04-1.21.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,7 @@ abstract class GenerateDocsTask : DefaultTask() {
|
||||
}
|
||||
|
||||
template.add(keyName.toString(), description.toString().ifBlank {
|
||||
logger.info("No description provided for field " + field.name + " in class " + name)
|
||||
println("No description provided for field " + field.name + " in class " + name)
|
||||
"*No description provided.*"
|
||||
})
|
||||
}
|
||||
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
package com.dfsek.terra.addon.loader;
|
||||
|
||||
import ca.solostudios.strata.version.Version;
|
||||
|
||||
import com.dfsek.terra.api.addon.BaseAddon;
|
||||
|
||||
|
||||
public class ApiAddon implements BaseAddon {
|
||||
private final Version version;
|
||||
private final String id;
|
||||
|
||||
public ApiAddon(Version version, String id) {
|
||||
this.version = version;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2025 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addon.loader;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
|
||||
public class ApiAddonClassLoader extends URLClassLoader {
|
||||
static {
|
||||
ClassLoader.registerAsParallelCapable();
|
||||
}
|
||||
|
||||
public ApiAddonClassLoader(URL[] urls, ClassLoader parent) {
|
||||
super(urls, parent);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2025 Polyhedral Development
|
||||
Copyright (c) 2020-2021 Polyhedral Development
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
+6
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2025 Polyhedral Development
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
@@ -14,26 +14,24 @@ import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.dfsek.terra.api.addon.BaseAddon;
|
||||
import com.dfsek.terra.api.addon.bootstrap.BootstrapAddonClassLoader;
|
||||
import com.dfsek.terra.api.addon.bootstrap.BootstrapBaseAddon;
|
||||
|
||||
|
||||
public class ApiAddonLoader implements BootstrapBaseAddon<BaseAddon> {
|
||||
private static final Version VERSION = Versions.getVersion(1, 0, 0);
|
||||
|
||||
|
||||
@Override
|
||||
public Iterable<BaseAddon> loadAddons(Path addonsFolder, BootstrapAddonClassLoader parent) {
|
||||
|
||||
public Iterable<BaseAddon> loadAddons(Path addonsFolder, ClassLoader parent) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return "API";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
public Version getVersion() {
|
||||
return VERSION;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
# Biome Query API
|
||||
|
||||
This addon contains an API to allow other addons to quickly query
|
||||
Biome data, by baking queries and using Contexts on biomes.
|
||||
@@ -1,5 +0,0 @@
|
||||
version = version("1.0.0")
|
||||
|
||||
dependencies {
|
||||
compileOnlyApi(project(":common:addons:addon-loader-manifest"))
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.query;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.dfsek.terra.addons.biome.query.impl.BiomeTagFlattener;
|
||||
import com.dfsek.terra.addons.biome.query.impl.BiomeTagHolder;
|
||||
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.addon.BaseAddon;
|
||||
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent;
|
||||
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||
import com.dfsek.terra.api.properties.Context;
|
||||
import com.dfsek.terra.api.properties.PropertyKey;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
public class BiomeQueryAPIAddon implements AddonInitializer {
|
||||
public static PropertyKey<BiomeTagHolder> BIOME_TAG_KEY = Context.create(BiomeTagHolder.class);
|
||||
@Inject
|
||||
private Platform platform;
|
||||
@Inject
|
||||
private BaseAddon addon;
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
|
||||
platform.getEventManager()
|
||||
.getHandler(FunctionalEventHandler.class)
|
||||
.register(addon, ConfigPackPostLoadEvent.class)
|
||||
.then(event -> {
|
||||
Collection<Biome> biomes = event
|
||||
.getPack()
|
||||
.getRegistry(Biome.class)
|
||||
.entries();
|
||||
|
||||
BiomeTagFlattener flattener = new BiomeTagFlattener(biomes
|
||||
.stream()
|
||||
.flatMap(biome -> biome.getTags().stream())
|
||||
.toList());
|
||||
|
||||
biomes.forEach(biome -> biome.getContext().put(BIOME_TAG_KEY, new BiomeTagHolder(biome, flattener)));
|
||||
})
|
||||
.global();
|
||||
}
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.query.api;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.dfsek.terra.addons.biome.query.impl.SingleTagQuery;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
public final class BiomeQueries {
|
||||
private BiomeQueries() {
|
||||
|
||||
}
|
||||
|
||||
public static Predicate<Biome> has(String tag) {
|
||||
return new SingleTagQuery(tag);
|
||||
}
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.query.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class BiomeTagFlattener {
|
||||
private final List<String> tags;
|
||||
|
||||
public BiomeTagFlattener(List<String> tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
public int index(String tag) {
|
||||
return tags.indexOf(tag);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return tags.size();
|
||||
}
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.query.impl;
|
||||
|
||||
import com.dfsek.terra.api.properties.Properties;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
public class BiomeTagHolder implements Properties {
|
||||
private final boolean[] tags;
|
||||
private final BiomeTagFlattener flattener;
|
||||
|
||||
public BiomeTagHolder(Biome biome, BiomeTagFlattener flattener) {
|
||||
this.tags = new boolean[flattener.size()];
|
||||
this.flattener = flattener;
|
||||
for(String tag : biome.getTags()) {
|
||||
tags[flattener.index(tag)] = true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean get(int index) {
|
||||
return tags[index];
|
||||
}
|
||||
|
||||
public BiomeTagFlattener getFlattener() {
|
||||
return flattener;
|
||||
}
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.query.impl;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.dfsek.terra.addons.biome.query.BiomeQueryAPIAddon;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
public class SingleTagQuery implements Predicate<Biome> {
|
||||
private final String tag;
|
||||
private int tagIndex = -1;
|
||||
|
||||
public SingleTagQuery(String tag) {
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Biome biome) {
|
||||
if(tagIndex < 0) {
|
||||
tagIndex = biome
|
||||
.getContext()
|
||||
.get(BiomeQueryAPIAddon.BIOME_TAG_KEY)
|
||||
.getFlattener()
|
||||
.index(tag);
|
||||
}
|
||||
return biome
|
||||
.getContext()
|
||||
.get(BiomeQueryAPIAddon.BIOME_TAG_KEY)
|
||||
.get(tagIndex);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
schema-version: 1
|
||||
contributors:
|
||||
- Terra contributors
|
||||
id: api-biome-query
|
||||
version: @VERSION@
|
||||
entrypoints:
|
||||
- "com.dfsek.terra.addons.biome.query.BiomeQueryAPIAddon"
|
||||
website:
|
||||
issues: https://github.com/PolyhedralDev/Terra/issues
|
||||
source: https://github.com/PolyhedralDev/Terra
|
||||
docs: https://terra.polydev.org
|
||||
license: MIT License
|
||||
@@ -1,7 +0,0 @@
|
||||
version = version("1.1.0")
|
||||
|
||||
dependencies {
|
||||
compileOnlyApi(project(":common:addons:addon-loader-manifest"))
|
||||
|
||||
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
package com.dfsek.terra.addons.image;
|
||||
|
||||
import com.dfsek.seismic.type.sampler.Sampler;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.config.ColorLoader;
|
||||
import com.dfsek.terra.addons.image.config.ColorLoader.ColorString;
|
||||
import com.dfsek.terra.addons.image.config.ImageLibraryPackConfigTemplate;
|
||||
import com.dfsek.terra.addons.image.config.colorsampler.ConstantColorSamplerTemplate;
|
||||
import com.dfsek.terra.addons.image.config.colorsampler.image.SingleImageColorSamplerTemplate;
|
||||
import com.dfsek.terra.addons.image.config.colorsampler.image.TileImageColorSamplerTemplate;
|
||||
import com.dfsek.terra.addons.image.config.colorsampler.mutate.RotateColorSamplerTemplate;
|
||||
import com.dfsek.terra.addons.image.config.colorsampler.mutate.TranslateColorSamplerTemplate;
|
||||
import com.dfsek.terra.addons.image.config.image.ImageTemplate;
|
||||
import com.dfsek.terra.addons.image.config.image.StitchedImageTemplate;
|
||||
import com.dfsek.terra.addons.image.config.sampler.ChannelSamplerTemplate;
|
||||
import com.dfsek.terra.addons.image.config.sampler.DistanceTransformSamplerTemplate;
|
||||
import com.dfsek.terra.addons.image.image.Image;
|
||||
import com.dfsek.terra.addons.image.operator.DistanceTransform;
|
||||
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.addon.BaseAddon;
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
|
||||
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||
import com.dfsek.terra.api.registry.CheckedRegistry;
|
||||
import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
|
||||
|
||||
public class ImageLibraryAddon implements AddonInitializer {
|
||||
|
||||
public static final TypeKey<Supplier<ObjectTemplate<Image>>> IMAGE_REGISTRY_KEY = new TypeKey<>() {
|
||||
};
|
||||
|
||||
public static final TypeKey<Supplier<ObjectTemplate<ColorSampler>>> COLOR_PICKER_REGISTRY_KEY = new TypeKey<>() {
|
||||
};
|
||||
|
||||
public static final TypeKey<Supplier<ObjectTemplate<Sampler>>> NOISE_SAMPLER_TOKEN = new TypeKey<>() {
|
||||
};
|
||||
@Inject
|
||||
private Platform platform;
|
||||
|
||||
@Inject
|
||||
private BaseAddon addon;
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
platform.getEventManager()
|
||||
.getHandler(FunctionalEventHandler.class)
|
||||
.register(addon, ConfigPackPreLoadEvent.class)
|
||||
.priority(10)
|
||||
.then(event -> {
|
||||
ImageLibraryPackConfigTemplate config = event.loadTemplate(new ImageLibraryPackConfigTemplate());
|
||||
event.getPack().getContext().put(config);
|
||||
})
|
||||
.then(event -> {
|
||||
ConfigPack pack = event.getPack();
|
||||
CheckedRegistry<Supplier<ObjectTemplate<Image>>> imageRegistry = pack.getOrCreateRegistry(IMAGE_REGISTRY_KEY);
|
||||
imageRegistry.register(addon.key("BITMAP"), () -> new ImageTemplate(pack));
|
||||
imageRegistry.register(addon.key("STITCHED_BITMAP"), () -> new StitchedImageTemplate(pack));
|
||||
})
|
||||
.then(event -> {
|
||||
event.getPack()
|
||||
.applyLoader(DistanceTransform.CostFunction.class,
|
||||
(type, o, loader, depthTracker) -> DistanceTransform.CostFunction.valueOf((String) o))
|
||||
.applyLoader(DistanceTransform.Normalization.class,
|
||||
(type, o, loader, depthTracker) -> DistanceTransform.Normalization.valueOf((String) o))
|
||||
.applyLoader(ColorString.class, new ColorLoader());
|
||||
|
||||
CheckedRegistry<Supplier<ObjectTemplate<Sampler>>> noiseRegistry = event.getPack().getOrCreateRegistry(
|
||||
NOISE_SAMPLER_TOKEN);
|
||||
noiseRegistry.register(addon.key("DISTANCE_TRANSFORM"), DistanceTransformSamplerTemplate::new);
|
||||
noiseRegistry.register(addon.key("CHANNEL"), ChannelSamplerTemplate::new);
|
||||
})
|
||||
.then(event -> {
|
||||
CheckedRegistry<Supplier<ObjectTemplate<ColorSampler>>> colorSamplerRegistry = event.getPack().getOrCreateRegistry(
|
||||
COLOR_PICKER_REGISTRY_KEY);
|
||||
colorSamplerRegistry.register(addon.key("SINGLE_IMAGE"), SingleImageColorSamplerTemplate::new);
|
||||
colorSamplerRegistry.register(addon.key("TILED_IMAGE"), TileImageColorSamplerTemplate::new);
|
||||
colorSamplerRegistry.register(addon.key("COLOR"), ConstantColorSamplerTemplate::new);
|
||||
colorSamplerRegistry.register(addon.key("ROTATE"), RotateColorSamplerTemplate::new);
|
||||
colorSamplerRegistry.register(addon.key("TRANSLATE"), TranslateColorSamplerTemplate::new);
|
||||
});
|
||||
}
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.colorsampler;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ColorSampler {
|
||||
|
||||
/**
|
||||
* @param x World x coordinate
|
||||
* @param z World z coordinate
|
||||
*
|
||||
* @return Integer representing a web color
|
||||
*/
|
||||
int apply(int x, int z);
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.colorsampler.image;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.colorsampler.image.transform.ImageTransformation;
|
||||
import com.dfsek.terra.addons.image.image.Image;
|
||||
|
||||
|
||||
public class SingleImageColorSampler implements ColorSampler {
|
||||
|
||||
private final Image image;
|
||||
|
||||
private final ColorSampler fallback;
|
||||
|
||||
private final ImageTransformation transformation;
|
||||
|
||||
public SingleImageColorSampler(Image image, ColorSampler fallback, ImageTransformation transformation) {
|
||||
this.image = image;
|
||||
this.fallback = fallback;
|
||||
this.transformation = transformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int apply(int x, int z) {
|
||||
var nx = transformation.transformX(image, x);
|
||||
var nz = transformation.transformZ(image, z);
|
||||
if(nx < 0 || nz < 0 || nx >= image.getWidth() || nz >= image.getHeight()) return fallback.apply(x, z);
|
||||
return image.getRGB(nx, nz);
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.colorsampler.image;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.colorsampler.image.transform.ImageTransformation;
|
||||
import com.dfsek.terra.addons.image.image.Image;
|
||||
|
||||
|
||||
public class TileImageColorSampler implements ColorSampler {
|
||||
|
||||
private final Image image;
|
||||
|
||||
private final ImageTransformation transformation;
|
||||
|
||||
public TileImageColorSampler(Image image, ImageTransformation transformation) {
|
||||
this.image = image;
|
||||
this.transformation = transformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int apply(int x, int z) {
|
||||
x = transformation.transformX(image, x);
|
||||
z = transformation.transformZ(image, z);
|
||||
return image.getRGB(Math.floorMod(x, image.getWidth()), Math.floorMod(z, image.getHeight()));
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.colorsampler.image.transform;
|
||||
|
||||
import com.dfsek.terra.addons.image.image.Image;
|
||||
|
||||
|
||||
public enum Alignment implements ImageTransformation {
|
||||
|
||||
NONE() {
|
||||
@Override
|
||||
public int transformX(Image image, int x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int transformZ(Image image, int z) {
|
||||
return z;
|
||||
}
|
||||
},
|
||||
CENTER {
|
||||
@Override
|
||||
public int transformX(Image image, int x) {
|
||||
return x + image.getWidth() / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int transformZ(Image image, int z) {
|
||||
return z + image.getHeight() / 2;
|
||||
}
|
||||
};
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.colorsampler.image.transform;
|
||||
|
||||
import com.dfsek.terra.addons.image.image.Image;
|
||||
|
||||
|
||||
public interface ImageTransformation {
|
||||
|
||||
int transformX(Image image, int x);
|
||||
|
||||
int transformZ(Image image, int z);
|
||||
}
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.colorsampler.mutate;
|
||||
|
||||
import com.dfsek.seismic.math.trigonometry.TrigonometryFunctions;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
|
||||
|
||||
public class RotateColorSampler implements ColorSampler {
|
||||
|
||||
private final ColorSampler sampler;
|
||||
|
||||
private final double radians;
|
||||
|
||||
private final RotationMethod rotationMethod;
|
||||
|
||||
public RotateColorSampler(ColorSampler sampler, double degrees) {
|
||||
this.sampler = sampler;
|
||||
|
||||
double normalizedDegrees = degrees % 360.0;
|
||||
if(normalizedDegrees < 0) normalizedDegrees += 360.0;
|
||||
|
||||
if(normalizedDegrees == 0.0)
|
||||
rotationMethod = RotationMethod.DEG_0;
|
||||
else if(normalizedDegrees == 90.0)
|
||||
rotationMethod = RotationMethod.DEG_90;
|
||||
else if(normalizedDegrees == 180.0)
|
||||
rotationMethod = RotationMethod.DEG_180;
|
||||
else if(normalizedDegrees == 270.0)
|
||||
rotationMethod = RotationMethod.DEG_270;
|
||||
else
|
||||
rotationMethod = RotationMethod.RAD_ANY;
|
||||
|
||||
this.radians = Math.toRadians(degrees);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int apply(int x, int z) {
|
||||
int rx = switch(rotationMethod) {
|
||||
case DEG_0 -> x;
|
||||
case DEG_90 -> -z;
|
||||
case DEG_180 -> -x;
|
||||
case DEG_270 -> z;
|
||||
case RAD_ANY -> (int) (x * TrigonometryFunctions.cos(radians) - z * TrigonometryFunctions.sin(radians));
|
||||
};
|
||||
int rz = switch(rotationMethod) {
|
||||
case DEG_0 -> z;
|
||||
case DEG_90 -> x;
|
||||
case DEG_180 -> -z;
|
||||
case DEG_270 -> -x;
|
||||
case RAD_ANY -> (int) (z * TrigonometryFunctions.cos(radians) + x * TrigonometryFunctions.sin(radians));
|
||||
};
|
||||
return sampler.apply(rx, rz);
|
||||
}
|
||||
|
||||
private enum RotationMethod {
|
||||
DEG_0,
|
||||
DEG_90,
|
||||
DEG_180,
|
||||
DEG_270,
|
||||
RAD_ANY,
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.colorsampler.mutate;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
|
||||
|
||||
public class TranslateColorSampler implements ColorSampler {
|
||||
|
||||
private final ColorSampler sampler;
|
||||
private final int translateX, translateZ;
|
||||
|
||||
public TranslateColorSampler(ColorSampler sampler, int translateX, int translateZ) {
|
||||
this.sampler = sampler;
|
||||
this.translateX = translateX;
|
||||
this.translateZ = translateZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int apply(int x, int z) {
|
||||
return sampler.apply(x - translateX, z - translateZ);
|
||||
}
|
||||
}
|
||||
-92
@@ -1,92 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config;
|
||||
|
||||
import com.dfsek.tectonic.api.depth.DepthTracker;
|
||||
import com.dfsek.tectonic.api.exception.LoadException;
|
||||
import com.dfsek.tectonic.api.loader.ConfigLoader;
|
||||
import com.dfsek.tectonic.api.loader.type.TypeLoader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
|
||||
import com.dfsek.terra.addons.image.config.ColorLoader.ColorString;
|
||||
import com.dfsek.terra.addons.image.util.ColorUtil;
|
||||
|
||||
|
||||
public class ColorLoader implements TypeLoader<ColorString> {
|
||||
|
||||
@Override
|
||||
public ColorString load(@NotNull AnnotatedType annotatedType, @NotNull Object o, @NotNull ConfigLoader configLoader,
|
||||
DepthTracker depthTracker) throws LoadException {
|
||||
return new ColorString((String) o);
|
||||
}
|
||||
|
||||
public static class ColorString {
|
||||
|
||||
private final int argb;
|
||||
|
||||
public ColorString(String string) throws IllegalArgumentException {
|
||||
this.argb = parse(string);
|
||||
}
|
||||
|
||||
private static int parse(String string) throws IllegalArgumentException {
|
||||
if(string.length() == 0)
|
||||
throw new IllegalArgumentException("Empty string cannot be parsed as a valid color");
|
||||
|
||||
String[] split = string.split(",");
|
||||
|
||||
if(split.length == 1)
|
||||
return parseHex(string);
|
||||
else if(split.length == 3)
|
||||
return parseChannels("255", split[0], split[1], split[2]);
|
||||
else if(split.length == 4)
|
||||
return parseChannels(split[0], split[1], split[2], split[3]);
|
||||
else
|
||||
throw new IllegalArgumentException("Invalid channels provided, required format RED,GREEN,BLUE or ALPHA,RED,GREEN,BLUE");
|
||||
}
|
||||
|
||||
private static int parseHex(String hex) throws IllegalArgumentException {
|
||||
if(hex.startsWith("#"))
|
||||
hex = hex.substring(1);
|
||||
|
||||
int alpha = 255;
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
|
||||
try {
|
||||
if(hex.length() == 8) {
|
||||
alpha = Integer.parseInt(hex.substring(0, 2), 16);
|
||||
hex = hex.substring(2);
|
||||
}
|
||||
|
||||
if(hex.length() != 6)
|
||||
throw new IllegalArgumentException("Invalid color channels, required format AARRGGBB or RRGGBB");
|
||||
|
||||
red = Integer.parseInt(hex.substring(0, 2), 16);
|
||||
green = Integer.parseInt(hex.substring(2, 4), 16);
|
||||
blue = Integer.parseInt(hex.substring(4, 6), 16);
|
||||
|
||||
return ColorUtil.argbValidated(alpha, red, green, blue);
|
||||
} catch(NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Failed to parse hex color", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static int parseChannels(String alpha, String red, String green, String blue) throws IllegalArgumentException {
|
||||
try {
|
||||
int a = Integer.decode(alpha);
|
||||
int r = Integer.decode(red);
|
||||
int g = Integer.decode(green);
|
||||
int b = Integer.decode(blue);
|
||||
|
||||
return ColorUtil.argbValidated(a, r, g, b);
|
||||
} catch(NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Invalid channel value", e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return argb;
|
||||
}
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.ConfigTemplate;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Description;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
|
||||
import com.dfsek.terra.api.properties.Properties;
|
||||
|
||||
|
||||
public class ImageLibraryPackConfigTemplate implements ConfigTemplate, Properties {
|
||||
// TODO - These would be better as plugin wide config parameters in config.yml
|
||||
|
||||
@Value("images.cache.load-on-use")
|
||||
@Description("If set to true, images will load into memory upon use rather than on pack load.")
|
||||
@Default
|
||||
private boolean loadOnUse = false;
|
||||
|
||||
@Value("images.cache.timeout")
|
||||
@Description("How many seconds to keep images loaded in the image cache for. " +
|
||||
"If set to a number greater than 0, images will be removed from memory if not used after the timeout, otherwise images " +
|
||||
"will stay loaded in memory. " +
|
||||
"Setting the timeout to greater than 0 will trade decreased memory consumption when not performing any image reads for a" +
|
||||
" period of time for extra processing time required to perform cache lookups.")
|
||||
@Default
|
||||
private int cacheTimeout = 0;
|
||||
|
||||
public boolean loadOnUse() {
|
||||
return loadOnUse;
|
||||
}
|
||||
|
||||
public boolean unloadOnTimeout() {
|
||||
return cacheTimeout > 0;
|
||||
}
|
||||
|
||||
public int getCacheTimeout() {
|
||||
return cacheTimeout;
|
||||
}
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.colorsampler;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.config.ColorLoader.ColorString;
|
||||
|
||||
|
||||
public class ConstantColorSamplerTemplate implements ObjectTemplate<ColorSampler> {
|
||||
|
||||
@Value("color")
|
||||
private ColorString color;
|
||||
|
||||
@Override
|
||||
public ColorSampler get() {
|
||||
return ((x, z) -> color.getColor());
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.colorsampler.image;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.colorsampler.image.transform.Alignment;
|
||||
import com.dfsek.terra.addons.image.image.Image;
|
||||
|
||||
|
||||
public abstract class ImageColorSamplerTemplate implements ObjectTemplate<ColorSampler> {
|
||||
|
||||
@Value("image")
|
||||
protected Image image;
|
||||
|
||||
@Value("align")
|
||||
@Default
|
||||
protected Alignment alignment = Alignment.NONE;
|
||||
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.colorsampler.image;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.colorsampler.image.SingleImageColorSampler;
|
||||
|
||||
|
||||
public class SingleImageColorSamplerTemplate extends ImageColorSamplerTemplate {
|
||||
@Value("outside-sampler")
|
||||
private ColorSampler fallback;
|
||||
|
||||
@Override
|
||||
public ColorSampler get() {
|
||||
return new SingleImageColorSampler(image, fallback, alignment);
|
||||
}
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.colorsampler.image;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.colorsampler.image.TileImageColorSampler;
|
||||
|
||||
|
||||
public class TileImageColorSamplerTemplate extends ImageColorSamplerTemplate {
|
||||
|
||||
@Override
|
||||
public ColorSampler get() {
|
||||
return new TileImageColorSampler(image, alignment);
|
||||
}
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.colorsampler.mutate;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
|
||||
|
||||
public abstract class MutateColorSamplerTemplate implements ObjectTemplate<ColorSampler> {
|
||||
|
||||
@Value("color-sampler")
|
||||
protected ColorSampler sampler;
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.colorsampler.mutate;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.colorsampler.mutate.RotateColorSampler;
|
||||
|
||||
|
||||
public class RotateColorSamplerTemplate extends MutateColorSamplerTemplate {
|
||||
|
||||
@Value("angle")
|
||||
private double degrees;
|
||||
|
||||
@Override
|
||||
public ColorSampler get() {
|
||||
return new RotateColorSampler(sampler, degrees);
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.colorsampler.mutate;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.colorsampler.mutate.TranslateColorSampler;
|
||||
|
||||
|
||||
public class TranslateColorSamplerTemplate extends MutateColorSamplerTemplate {
|
||||
|
||||
@Value("x")
|
||||
private int translateX;
|
||||
|
||||
@Value("z")
|
||||
private int translateZ;
|
||||
|
||||
@Override
|
||||
public ColorSampler get() {
|
||||
return new TranslateColorSampler(sampler, translateX, translateZ);
|
||||
}
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.converter;
|
||||
|
||||
import com.dfsek.terra.addons.image.converter.ClosestMatchColorConverter;
|
||||
import com.dfsek.terra.addons.image.converter.ColorConverter;
|
||||
import com.dfsek.terra.addons.image.converter.mapping.ColorMapping;
|
||||
|
||||
|
||||
public abstract class ClosestColorConverterTemplate<T> implements ColorConverterTemplate<T> {
|
||||
|
||||
protected abstract ColorMapping<T> getMapping();
|
||||
|
||||
@Override
|
||||
public ColorConverter<T> get() {
|
||||
return new ClosestMatchColorConverter<T>(getMapping().get());
|
||||
}
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.converter;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import com.dfsek.terra.addons.image.converter.ColorConverter;
|
||||
|
||||
|
||||
public interface ColorConverterTemplate<T> extends ObjectTemplate<ColorConverter<T>> {
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.converter;
|
||||
|
||||
import com.dfsek.terra.addons.image.converter.ColorConverter;
|
||||
import com.dfsek.terra.addons.image.converter.ExactColorConverter;
|
||||
import com.dfsek.terra.addons.image.converter.mapping.ColorMapping;
|
||||
|
||||
|
||||
public abstract class ExactColorConverterTemplate<T> implements ColorConverterTemplate<T> {
|
||||
|
||||
protected abstract ColorMapping<T> getMapping();
|
||||
|
||||
protected abstract T getFallback();
|
||||
|
||||
protected abstract boolean ignoreAlpha();
|
||||
|
||||
@Override
|
||||
public ColorConverter<T> get() {
|
||||
return new ExactColorConverter<T>(getMapping().get(), getFallback(), ignoreAlpha());
|
||||
}
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.image;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.github.benmanes.caffeine.cache.Scheduler;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.dfsek.terra.addons.image.config.ImageLibraryPackConfigTemplate;
|
||||
import com.dfsek.terra.addons.image.image.BufferedImageWrapper;
|
||||
import com.dfsek.terra.addons.image.image.Image;
|
||||
import com.dfsek.terra.addons.image.image.SuppliedImage;
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.api.properties.Properties;
|
||||
import com.dfsek.terra.api.util.generic.Memo;
|
||||
|
||||
import static com.dfsek.terra.api.util.cache.CacheUtils.CACHE_EXECUTOR;
|
||||
|
||||
|
||||
/*
|
||||
* Cache prevents configs from loading the same image multiple times into memory
|
||||
*/
|
||||
record ImageCache(LoadingCache<String, Image> cache) implements Properties {
|
||||
public static Image load(String path, ConfigPack pack) throws IOException {
|
||||
ImageLibraryPackConfigTemplate config = pack.getContext().get(ImageLibraryPackConfigTemplate.class);
|
||||
ImageCache images;
|
||||
if(!pack.getContext().has(ImageCache.class)) {
|
||||
var cacheBuilder = Caffeine.newBuilder().executor(CACHE_EXECUTOR).scheduler(Scheduler.systemScheduler());
|
||||
if(config.unloadOnTimeout()) cacheBuilder.expireAfterAccess(config.getCacheTimeout(), TimeUnit.SECONDS);
|
||||
images = new ImageCache(cacheBuilder.build(s -> loadImage(s, pack.getRootPath())));
|
||||
pack.getContext().put(images);
|
||||
} else images = pack.getContext().get(ImageCache.class);
|
||||
|
||||
if(config.loadOnUse()) {
|
||||
if(config.unloadOnTimeout()) { // Grab directly from cache if images are to unload on timeout
|
||||
return new SuppliedImage(() -> images.cache.get(path));
|
||||
} else {
|
||||
// If images do not time out, image can be lazily loaded once instead of performing cache lookups for each image operation
|
||||
Memo<Image> lazyImage = Memo.lazy(() -> images.cache.get(path));
|
||||
return new SuppliedImage(lazyImage::value);
|
||||
}
|
||||
}
|
||||
|
||||
return images.cache.get(path);
|
||||
}
|
||||
|
||||
private static Image loadImage(String path, Path directory) throws IOException {
|
||||
InputStream is = Files.newInputStream(directory.resolve(path));
|
||||
return new BufferedImageWrapper(ImageIO.read(is));
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.image;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.dfsek.terra.addons.image.image.Image;
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
|
||||
|
||||
public class ImageTemplate implements ObjectTemplate<Image> {
|
||||
|
||||
private final ConfigPack pack;
|
||||
@Value("path")
|
||||
private String path;
|
||||
|
||||
public ImageTemplate(ConfigPack pack) {
|
||||
this.pack = pack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image get() {
|
||||
try {
|
||||
return ImageCache.load(path, pack);
|
||||
} catch(IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.image;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.ValidatedConfigTemplate;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
import com.dfsek.tectonic.api.exception.ValidationException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.dfsek.terra.addons.image.image.Image;
|
||||
import com.dfsek.terra.addons.image.image.StitchedImage;
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
|
||||
|
||||
public class StitchedImageTemplate implements ObjectTemplate<Image>, ValidatedConfigTemplate {
|
||||
|
||||
private final ConfigPack pack;
|
||||
@Value("path-format")
|
||||
private String path;
|
||||
@Value("rows")
|
||||
private int rows;
|
||||
@Value("columns")
|
||||
private int cols;
|
||||
@Value("zero-indexed")
|
||||
@Default
|
||||
private boolean zeroIndexed = false;
|
||||
|
||||
public StitchedImageTemplate(ConfigPack pack) {
|
||||
this.pack = pack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image get() {
|
||||
Image[][] grid = new Image[rows][cols];
|
||||
for(int i = 0; i < rows; i++) {
|
||||
for(int j = 0; j < cols; j++) {
|
||||
try {
|
||||
grid[i][j] = ImageCache.load(getFormattedPath(i, j), pack);
|
||||
} catch(IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new StitchedImage(grid, zeroIndexed);
|
||||
}
|
||||
|
||||
private String getFormattedPath(int row, int column) {
|
||||
if(!zeroIndexed) {
|
||||
row++;
|
||||
column++;
|
||||
}
|
||||
return path.replaceFirst("\\{row}", String.valueOf(row)).replaceFirst("\\{column}", String.valueOf(column));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate() throws ValidationException {
|
||||
if(!path.contains("{row}"))
|
||||
throw new ValidationException("Path format does not contain sequence '{row}'");
|
||||
if(!path.contains("{column}"))
|
||||
throw new ValidationException("Path format does not contain sequence '{column}'");
|
||||
if(rows < 1)
|
||||
throw new ValidationException("Must have at least one row");
|
||||
if(cols < 1)
|
||||
throw new ValidationException("Must have at least one column");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.sampler;
|
||||
|
||||
import com.dfsek.seismic.type.sampler.Sampler;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.sampler.ChannelSampler;
|
||||
import com.dfsek.terra.addons.image.util.ColorUtil.Channel;
|
||||
|
||||
|
||||
public class ChannelSamplerTemplate implements ObjectTemplate<Sampler> {
|
||||
|
||||
@Value("color-sampler")
|
||||
private ColorSampler colorSampler;
|
||||
|
||||
@Value("channel")
|
||||
private Channel channel;
|
||||
|
||||
/*
|
||||
* If the channel should be normalized to range [-1, 1] or not
|
||||
*/
|
||||
@Value("normalize")
|
||||
@Default
|
||||
private boolean normalize = true;
|
||||
|
||||
/*
|
||||
* Whether to multiply color channels by the alpha channel or not. If users
|
||||
* are expecting pixel transparency to reduce the output value then this should
|
||||
* be set to true.
|
||||
*/
|
||||
@Value("premultiply")
|
||||
@Default
|
||||
private boolean premultiply = false;
|
||||
|
||||
@Override
|
||||
public Sampler get() {
|
||||
return new ChannelSampler(colorSampler, channel, normalize, premultiply);
|
||||
}
|
||||
}
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.config.sampler;
|
||||
|
||||
import com.dfsek.seismic.type.sampler.Sampler;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import com.dfsek.terra.addons.image.image.Image;
|
||||
import com.dfsek.terra.addons.image.operator.DistanceTransform;
|
||||
import com.dfsek.terra.addons.image.operator.DistanceTransform.CostFunction;
|
||||
import com.dfsek.terra.addons.image.operator.DistanceTransform.Normalization;
|
||||
import com.dfsek.terra.addons.image.util.ColorUtil.Channel;
|
||||
|
||||
|
||||
public class DistanceTransformSamplerTemplate implements ObjectTemplate<Sampler> {
|
||||
|
||||
@Value("image")
|
||||
private Image image;
|
||||
|
||||
/**
|
||||
* The threshold value applied to the channel specified in the 'channel' parameter that splits
|
||||
* the image into a binary image. This parameter is only used for cost functions that utilize
|
||||
* a binary image.
|
||||
*/
|
||||
@Value("threshold")
|
||||
@Default
|
||||
private int threshold = 127;
|
||||
|
||||
/**
|
||||
* If set to true, distances calculated will be clamped to stay above the largest
|
||||
* distance calculated on the edges of the image. This ensures output values do not
|
||||
* appear to be cut off at the image boundaries. It is recommended to leave padding
|
||||
* around the image if this is in use, such that larger evaluated distances do not
|
||||
* get cut out by smaller evaluated distances close to borders. Doing so will yield
|
||||
* better results.
|
||||
*/
|
||||
@Value("clamp-to-max-edge")
|
||||
@Default
|
||||
private boolean clampToEdge = false;
|
||||
|
||||
/**
|
||||
* The target channel to run distance calculations on.
|
||||
*/
|
||||
@Value("channel")
|
||||
@Default
|
||||
private Channel channel = Channel.GRAYSCALE;
|
||||
|
||||
/**
|
||||
* The method of image processing applied to the specified image prior to calculating
|
||||
* distances.
|
||||
*/
|
||||
@Value("cost-function")
|
||||
@Default
|
||||
private CostFunction costFunction = CostFunction.Channel;
|
||||
|
||||
/**
|
||||
* Inverts the resulting binary image that may be used as a cost function.
|
||||
*/
|
||||
@Value("invert-threshold")
|
||||
@Default
|
||||
private boolean invertThreshold = false;
|
||||
|
||||
/**
|
||||
* How the final distance calculation should be redistributed.
|
||||
*/
|
||||
@Value("normalization")
|
||||
@Default
|
||||
private Normalization normalization = Normalization.None;
|
||||
|
||||
@Override
|
||||
public Sampler get() {
|
||||
return new DistanceTransform.Noise(new DistanceTransform(image, channel, threshold, clampToEdge, costFunction, invertThreshold),
|
||||
normalization);
|
||||
}
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.converter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.dfsek.terra.addons.image.util.ColorUtil;
|
||||
|
||||
|
||||
public class ClosestMatchColorConverter<T> implements ColorConverter<T> {
|
||||
|
||||
private final Map<Integer, T> map;
|
||||
|
||||
private final Integer[] colors;
|
||||
|
||||
public ClosestMatchColorConverter(Map<Integer, T> map) {
|
||||
this.map = map;
|
||||
this.colors = map.keySet().toArray(new Integer[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T apply(int color) {
|
||||
int closest = 0;
|
||||
int smallestDistance = Integer.MAX_VALUE;
|
||||
for(int compare : colors) {
|
||||
if(color == compare) {
|
||||
closest = compare;
|
||||
break;
|
||||
}
|
||||
int distance = ColorUtil.distance(color, compare);
|
||||
if(distance < smallestDistance) {
|
||||
smallestDistance = distance;
|
||||
closest = compare;
|
||||
}
|
||||
}
|
||||
return map.get(closest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<T> getEntries() {
|
||||
return map.values();
|
||||
}
|
||||
}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.converter;
|
||||
|
||||
public interface ColorConverter<T> {
|
||||
|
||||
T apply(int color);
|
||||
|
||||
Iterable<T> getEntries();
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.converter;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.dfsek.terra.addons.image.util.ColorUtil;
|
||||
import com.dfsek.terra.addons.image.util.MapUtil;
|
||||
|
||||
|
||||
public class ExactColorConverter<T> implements ColorConverter<T> {
|
||||
private final Map<Integer, T> map;
|
||||
|
||||
private final T fallback;
|
||||
|
||||
private final boolean ignoreAlpha;
|
||||
|
||||
public ExactColorConverter(Map<Integer, T> map, T fallback, boolean ignoreAlpha) {
|
||||
if(ignoreAlpha) {
|
||||
map = MapUtil.mapKeys(map, ColorUtil::zeroAlpha);
|
||||
}
|
||||
this.map = map;
|
||||
this.fallback = fallback;
|
||||
this.ignoreAlpha = ignoreAlpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T apply(int color) {
|
||||
if(ignoreAlpha) {
|
||||
color = ColorUtil.zeroAlpha(color);
|
||||
}
|
||||
T lookup = map.get(color);
|
||||
return lookup != null ? lookup : fallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<T> getEntries() {
|
||||
Set<T> entries = new HashSet<>(map.values());
|
||||
entries.add(fallback);
|
||||
return entries;
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.converter.mapping;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.dfsek.terra.api.registry.Registry;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
public class BiomeDefinedColorMapping<T> implements ColorMapping<T> {
|
||||
|
||||
Registry<Biome> biomeRegistry;
|
||||
|
||||
Function<Biome, T> converter;
|
||||
|
||||
public BiomeDefinedColorMapping(Registry<Biome> biomeRegistry, Function<Biome, T> converter) {
|
||||
this.biomeRegistry = biomeRegistry;
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, T> get() {
|
||||
Map<Biome, Integer> colorMap = new HashSet<>(biomeRegistry.entries()).stream().collect(Collectors.toMap(b -> b, Biome::getColor));
|
||||
Map<Integer, Biome> output = new HashMap<>();
|
||||
colorMap.forEach(((biome, color) -> {
|
||||
if(!output.containsKey(color)) {
|
||||
output.put(color, biome);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Biome %s has same color as %s: %x", biome.getID(), output.get(color).getID(), color));
|
||||
}
|
||||
}));
|
||||
return output.entrySet().stream().collect(Collectors.toMap(Entry::getKey, e -> converter.apply(e.getValue())));
|
||||
}
|
||||
}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.converter.mapping;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
public interface ColorMapping<T> extends Supplier<Map<Integer, T>> {
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.image;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
|
||||
public class BufferedImageWrapper implements Image {
|
||||
|
||||
private final BufferedImage image;
|
||||
|
||||
public BufferedImageWrapper(BufferedImage image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRGB(int x, int y) {
|
||||
return image.getRGB(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return image.getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return image.getHeight();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.image;
|
||||
|
||||
public interface Image {
|
||||
int getRGB(int x, int y);
|
||||
|
||||
int getWidth();
|
||||
|
||||
int getHeight();
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.image;
|
||||
|
||||
public class StitchedImage implements Image {
|
||||
|
||||
private final Image[][] images;
|
||||
|
||||
private final int[] rowOffsets, columnOffsets;
|
||||
|
||||
private final int width, height;
|
||||
|
||||
public StitchedImage(Image[][] images, boolean zeroIndexed) throws IllegalArgumentException {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int rows = images.length;
|
||||
int columns = images[0].length;
|
||||
this.rowOffsets = new int[rows];
|
||||
this.columnOffsets = new int[columns];
|
||||
for(int i = 0; i < rows; i++) {
|
||||
int rowHeight = images[i][0].getHeight();
|
||||
rowOffsets[i] = height;
|
||||
height += rowHeight;
|
||||
for(int j = 1; j < columns; j++) {
|
||||
if(images[i][j].getHeight() != rowHeight)
|
||||
throw new IllegalArgumentException("Image heights in row " + (i + (zeroIndexed ? 0 : 1)) + " do not match");
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < columns; i++) {
|
||||
int columnWidth = images[0][i].getWidth();
|
||||
columnOffsets[i] = width;
|
||||
width += columnWidth;
|
||||
for(int j = 1; j < rows; j++) {
|
||||
if(images[i][j].getWidth() != columnWidth)
|
||||
throw new IllegalArgumentException("Image widths in column " + (i + (zeroIndexed ? 0 : 1)) + " do not match");
|
||||
}
|
||||
}
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.images = images;
|
||||
}
|
||||
|
||||
private int getColumn(int x) {
|
||||
for(int i = columnOffsets.length - 1; i > 0; i--) {
|
||||
if(x >= columnOffsets[i])
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int getRow(int y) {
|
||||
for(int i = rowOffsets.length - 1; i > 0; i--) {
|
||||
if(y >= rowOffsets[i])
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRGB(int x, int y) {
|
||||
int row = getRow(y);
|
||||
int column = getColumn(x);
|
||||
return images[row][column].getRGB(x - columnOffsets[column], y - rowOffsets[row]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.image;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
public class SuppliedImage implements Image {
|
||||
|
||||
private final Supplier<Image> imageSupplier;
|
||||
|
||||
public SuppliedImage(Supplier<Image> imageSupplier) {
|
||||
this.imageSupplier = imageSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRGB(int x, int y) {
|
||||
return imageSupplier.get().getRGB(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return imageSupplier.get().getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return imageSupplier.get().getHeight();
|
||||
}
|
||||
}
|
||||
-245
@@ -1,245 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.operator;
|
||||
|
||||
import com.dfsek.seismic.math.floatingpoint.FloatingPointFunctions;
|
||||
import com.dfsek.seismic.type.sampler.Sampler;
|
||||
|
||||
import com.dfsek.terra.addons.image.image.Image;
|
||||
import com.dfsek.terra.addons.image.util.ColorUtil;
|
||||
import com.dfsek.terra.addons.image.util.ColorUtil.Channel;
|
||||
|
||||
import static com.dfsek.terra.addons.image.util.MathUtil.lerp;
|
||||
|
||||
|
||||
/**
|
||||
* Computes a 2D distance transform of a given image and stores the result in a 2D array of distances.
|
||||
* Implementation based on the algorithm described in the paper
|
||||
* <a href="https://cs.brown.edu/people/pfelzens/papers/dt-final.pdf">Distance Transforms of Sampled Functions</a>
|
||||
* by Pedro F. Felzenszwalb and Daniel P. Huttenlocher.
|
||||
*/
|
||||
public class DistanceTransform {
|
||||
|
||||
private static final double MAX_DISTANCE_CAP = 10_000_000; // Arbitrarily large value, doubtful someone would
|
||||
private final double[][] distances;
|
||||
/**
|
||||
* Size bounds matching the provided image.
|
||||
*/
|
||||
private final int width, height;
|
||||
/**
|
||||
* Min and max distances of the distance computation. These may change after {@link #normalize(Normalization)} calls.
|
||||
*/
|
||||
private double minDistance, maxDistance;
|
||||
|
||||
// ever use an image large enough to exceed this.
|
||||
public DistanceTransform(Image image, Channel channel, int threshold, boolean clampToMaxEdgeDistance, CostFunction costFunction,
|
||||
boolean invertThreshold) {
|
||||
// Construct binary image based on threshold value
|
||||
boolean[][] binaryImage = new boolean[image.getWidth()][image.getHeight()];
|
||||
for(int x = 0; x < image.getWidth(); x++) {
|
||||
for(int y = 0; y < image.getHeight(); y++) {
|
||||
binaryImage[x][y] = ColorUtil.getChannel(image.getRGB(x, y), channel) > threshold ^ invertThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
// Get edges of binary image
|
||||
boolean[][] binaryImageEdge = new boolean[image.getWidth()][image.getHeight()];
|
||||
for(int x = 0; x < image.getWidth(); x++) {
|
||||
for(int y = 0; y < image.getHeight(); y++) {
|
||||
if(!binaryImage[x][y])
|
||||
binaryImageEdge[x][y] = false;
|
||||
else
|
||||
// If cell borders any false cell
|
||||
binaryImageEdge[x][y] = x > 0 && !binaryImage[x - 1][y] ||
|
||||
y > 0 && !binaryImage[x][y - 1] ||
|
||||
x < image.getWidth() - 1 && !binaryImage[x + 1][y] ||
|
||||
y < image.getHeight() - 1 && !binaryImage[x][y + 1];
|
||||
}
|
||||
}
|
||||
|
||||
double[][] function = new double[image.getWidth()][image.getHeight()];
|
||||
for(int x = 0; x < image.getWidth(); x++) {
|
||||
for(int y = 0; y < image.getHeight(); y++) {
|
||||
function[x][y] = switch(costFunction) {
|
||||
case Channel -> ColorUtil.getChannel(image.getRGB(x, y), channel);
|
||||
case Threshold -> binaryImage[x][y] ? MAX_DISTANCE_CAP : 0;
|
||||
case ThresholdEdge, ThresholdEdgeSigned -> binaryImageEdge[x][y] ? 0 : MAX_DISTANCE_CAP;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
distances = calculateDistance2D(function);
|
||||
|
||||
if(costFunction == CostFunction.ThresholdEdgeSigned) {
|
||||
for(int x = 0; x < image.getWidth(); x++) {
|
||||
for(int y = 0; y < image.getHeight(); y++) {
|
||||
distances[x][y] *= binaryImage[x][y] ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(clampToMaxEdgeDistance) {
|
||||
// Find the largest value on the edge of the image
|
||||
double max = Double.NEGATIVE_INFINITY;
|
||||
for(int x = 0; x < image.getWidth(); x++) {
|
||||
max = Math.max(max, distances[x][0]);
|
||||
max = Math.max(max, distances[x][image.getHeight() - 1]);
|
||||
}
|
||||
for(int y = 0; y < image.getHeight(); y++) {
|
||||
max = Math.max(max, distances[0][y]);
|
||||
max = Math.max(max, distances[image.getWidth() - 1][y]);
|
||||
}
|
||||
// Clamp to that largest value
|
||||
for(int x = 0; x < image.getWidth(); x++) {
|
||||
for(int y = 0; y < image.getHeight(); y++) {
|
||||
distances[x][y] = Math.max(max, distances[x][y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.width = image.getWidth();
|
||||
this.height = image.getHeight();
|
||||
|
||||
setOutputRange();
|
||||
}
|
||||
|
||||
private double[][] calculateDistance2D(double[][] f) {
|
||||
double[][] d = new double[f.length][f[0].length];
|
||||
// Distance pass for each column
|
||||
for(int x = 0; x < f.length; x++) {
|
||||
d[x] = calculateDistance1D(f[x]);
|
||||
}
|
||||
// Distance pass for each row
|
||||
double[] row = new double[f.length];
|
||||
for(int y = 0; y < f[0].length; y++) {
|
||||
for(int x = 0; x < f[0].length; x++)
|
||||
row[x] = d[x][y];
|
||||
row = calculateDistance1D(row);
|
||||
for(int x = 0; x < f[0].length; x++) {
|
||||
d[x][y] = Math.sqrt(row[x]);
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
private double[] calculateDistance1D(double[] f) {
|
||||
double[] d = new double[f.length];
|
||||
int[] v = new int[f.length];
|
||||
double[] z = new double[f.length + 1];
|
||||
int k = 0;
|
||||
v[0] = 0;
|
||||
z[0] = Integer.MIN_VALUE;
|
||||
z[1] = Integer.MAX_VALUE;
|
||||
for(int q = 1; q <= f.length - 1; q++) {
|
||||
double fqPlusQ2 = (f[q] + Math.pow(q, 2));
|
||||
double twoQ = 2 * q;
|
||||
double s = (fqPlusQ2 - (f[v[k]] + Math.pow(v[k], 2))) / (twoQ - 2 * v[k]);
|
||||
while(s <= z[k]) {
|
||||
k--;
|
||||
s = (fqPlusQ2 - (f[v[k]] + Math.pow(v[k], 2))) / (twoQ - 2 * v[k]);
|
||||
}
|
||||
k++;
|
||||
v[k] = q;
|
||||
z[k] = s;
|
||||
z[k + 1] = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
k = 0;
|
||||
for(int q = 0; q <= f.length - 1; q++) {
|
||||
while(z[k + 1] < q)
|
||||
k++;
|
||||
d[q] = Math.pow(q - v[k], 2) + f[v[k]];
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redistributes the stored distance computation according to the provided {@link Normalization} method.
|
||||
*/
|
||||
private void normalize(Normalization normalization) {
|
||||
for(int x = 0; x < width; x++) {
|
||||
for(int y = 0; y < height; y++) {
|
||||
double d = distances[x][y];
|
||||
distances[x][y] = switch(normalization) {
|
||||
case None -> distances[x][y];
|
||||
case Linear -> lerp(d, minDistance, -1, maxDistance, 1);
|
||||
case SmoothPreserveZero -> {
|
||||
if(minDistance > 0 || maxDistance < 0) {
|
||||
// Can't preserve zero if it is not contained in range so just lerp
|
||||
yield lerp(distances[x][y], minDistance, -1, maxDistance, 1);
|
||||
} else {
|
||||
if(d > 0) {
|
||||
yield Math.pow(d / maxDistance, 2);
|
||||
} else if(d < 0) {
|
||||
yield -Math.pow(d / minDistance, 2);
|
||||
} else {
|
||||
yield 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
setOutputRange();
|
||||
}
|
||||
|
||||
private void setOutputRange() {
|
||||
double minDistance = Double.POSITIVE_INFINITY;
|
||||
double maxDistance = Double.NEGATIVE_INFINITY;
|
||||
for(int x = 0; x < width; x++) {
|
||||
for(int y = 0; y < height; y++) {
|
||||
minDistance = Math.min(minDistance, distances[x][y]);
|
||||
maxDistance = Math.max(maxDistance, distances[x][y]);
|
||||
}
|
||||
}
|
||||
this.minDistance = minDistance;
|
||||
this.maxDistance = maxDistance;
|
||||
}
|
||||
|
||||
public enum CostFunction {
|
||||
Channel,
|
||||
Threshold,
|
||||
ThresholdEdge,
|
||||
ThresholdEdgeSigned,
|
||||
}
|
||||
|
||||
|
||||
public enum Normalization {
|
||||
/**
|
||||
* Return the raw calculated distances.
|
||||
*/
|
||||
None,
|
||||
|
||||
/**
|
||||
* Redistribute the output values to fit in the range [-1, 1]
|
||||
*/
|
||||
Linear,
|
||||
|
||||
/**
|
||||
* Redistributes smoothly to the range [-1, 1], such that areas where distance = 0 stay 0.
|
||||
* This is only really applicable to signed distance calculations, and will fall back to linear
|
||||
* redistribution if the input range does not contain both positive and negative values.
|
||||
*/
|
||||
SmoothPreserveZero,
|
||||
}
|
||||
|
||||
|
||||
public static class Noise implements Sampler {
|
||||
|
||||
private final DistanceTransform transform;
|
||||
|
||||
public Noise(DistanceTransform transform, Normalization normalization) {
|
||||
this.transform = transform;
|
||||
transform.normalize(normalization);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSample(long seed, double x, double y) {
|
||||
if(x < 0 || y < 0 || x >= transform.width || y >= transform.height) return transform.minDistance;
|
||||
return transform.distances[FloatingPointFunctions.floor(x)][FloatingPointFunctions.floor(y)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSample(long seed, double x, double y, double z) {
|
||||
return getSample(seed, x, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.sampler;
|
||||
|
||||
import com.dfsek.seismic.type.sampler.Sampler;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.util.ColorUtil;
|
||||
import com.dfsek.terra.addons.image.util.ColorUtil.Channel;
|
||||
|
||||
import static com.dfsek.terra.addons.image.util.MathUtil.lerp;
|
||||
|
||||
|
||||
public class ChannelSampler implements Sampler {
|
||||
|
||||
private final ColorSampler colorSampler;
|
||||
|
||||
private final Channel channel;
|
||||
|
||||
private final boolean normalize;
|
||||
|
||||
private final boolean premultiply;
|
||||
|
||||
public ChannelSampler(ColorSampler colorSampler, Channel channel, boolean normalize, boolean premultiply) {
|
||||
this.colorSampler = colorSampler;
|
||||
this.channel = channel;
|
||||
this.normalize = normalize;
|
||||
this.premultiply = premultiply;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSample(long seed, double x, double y) {
|
||||
int sample = colorSampler.apply((int) x, (int) y);
|
||||
int premultiplied = premultiply ? ColorUtil.premultiply(sample) : sample;
|
||||
double channelValue = channel.from(premultiplied);
|
||||
return normalize ? lerp(channelValue, 0, -1, 255, 1) : channelValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSample(long seed, double x, double y, double z) {
|
||||
return getSample(seed, x, z);
|
||||
}
|
||||
}
|
||||
-340
@@ -1,340 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.util;
|
||||
|
||||
/**
|
||||
* Utility class for manipulating 8 bit ARGB colors
|
||||
*/
|
||||
public class ColorUtil {
|
||||
|
||||
private ColorUtil() { }
|
||||
|
||||
public static int distance(int a, int b) {
|
||||
return Math.abs(getRed(a) - getRed(b)) +
|
||||
Math.abs(getGreen(a) - getGreen(b)) +
|
||||
Math.abs(getBlue(a) - getBlue(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the red channel value of a given ARGB color value.
|
||||
*
|
||||
* @param argb the ARGB color value to extract the red channel value from
|
||||
*
|
||||
* @return the red channel value of the given ARGB color value, in the range 0-255
|
||||
*/
|
||||
public static int getRed(int argb) {
|
||||
return argb >> 16 & 255;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the green channel value of a given ARGB color value.
|
||||
*
|
||||
* @param argb the ARGB color value to extract the green channel value from
|
||||
*
|
||||
* @return the green channel value of the given ARGB color value, in the range 0-255
|
||||
*/
|
||||
public static int getGreen(int argb) {
|
||||
return argb >> 8 & 255;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the blue channel value of a given ARGB color value.
|
||||
*
|
||||
* @param argb the ARGB color value to extract the blue channel value from
|
||||
*
|
||||
* @return the blue channel value of the given ARGB color value, in the range 0-255
|
||||
*/
|
||||
public static int getBlue(int argb) {
|
||||
return argb & 255;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alpha channel value of a given ARGB color value.
|
||||
*
|
||||
* @param argb the ARGB color value to extract the blue channel value from
|
||||
*
|
||||
* @return the alpha channel value of the given ARGB color value, in the range 0-255
|
||||
*/
|
||||
public static int getAlpha(int argb) {
|
||||
return argb >> 24 & 255;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the grayscale value of a given ARGB color value.
|
||||
*
|
||||
* @param argb the ARGB color value to convert to grayscale
|
||||
*
|
||||
* @return the grayscale value of the given ARGB color value, in the range 0-255
|
||||
*/
|
||||
public static int getGrayscale(int argb) {
|
||||
return (getRed(argb) + getGreen(argb) + getBlue(argb)) / 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the specified channel for a given ARGB color value.
|
||||
*
|
||||
* @param argb the ARGB color value to extract the channel value from
|
||||
* @param channel the channel to extract the value from
|
||||
*
|
||||
* @return the value of the specified channel for the given ARGB color value, in the range 0-255
|
||||
*/
|
||||
public static int getChannel(int argb, Channel channel) {
|
||||
return channel.from(argb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the red channel value of a given ARGB color value to zero.
|
||||
*
|
||||
* @param argb the ARGB color value to zero the red channel of
|
||||
*
|
||||
* @return the resulting ARGB color value with the red channel set to zero
|
||||
*/
|
||||
public static int zeroRed(int argb) {
|
||||
return argb & ~0x00FF0000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the green channel value of a given ARGB color value to zero.
|
||||
*
|
||||
* @param argb the ARGB color value to zero the green channel of
|
||||
*
|
||||
* @return the resulting ARGB color value with the green channel set to zero
|
||||
*/
|
||||
public static int zeroGreen(int argb) {
|
||||
return argb & ~0x0000FF00;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the blue channel value of a given ARGB color value to zero.
|
||||
*
|
||||
* @param argb the ARGB color value to zero the blue channel of
|
||||
*
|
||||
* @return the resulting ARGB color value with the blue channel set to zero
|
||||
*/
|
||||
public static int zeroBlue(int argb) {
|
||||
return argb & ~0x000000FF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alpha channel value of a given ARGB color value to zero.
|
||||
* This is the same as setting the color to fully transparent.
|
||||
*
|
||||
* @param argb the ARGB color value to zero the alpha channel of
|
||||
*
|
||||
* @return the resulting ARGB color value with the alpha channel set to zero
|
||||
*/
|
||||
public static int zeroAlpha(int argb) {
|
||||
return argb & ~0xFF000000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color channels of a given ARGB color value to zero.
|
||||
* This is the same as setting the color to black, while preserving the alpha.
|
||||
*
|
||||
* @param argb the ARGB color value to zero the color channel of
|
||||
*
|
||||
* @return the resulting ARGB color value with the color channels set to zero
|
||||
*/
|
||||
public static int zeroGrayscale(int argb) {
|
||||
return argb & ~0x00FFFFFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified channel value of a given ARGB color value to zero.
|
||||
*
|
||||
* @param argb the ARGB color value to zero the specified channel of
|
||||
* @param channel the channel to zero the value of
|
||||
*
|
||||
* @return the resulting ARGB color value with the specified channel value set to zero
|
||||
*/
|
||||
public static int zeroChannel(int argb, Channel channel) {
|
||||
return channel.zero(argb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply the RGB channels of a given ARGB color value by its alpha channel value.
|
||||
*
|
||||
* @param argb the ARGB color value to premultiply the RGB channels of
|
||||
*
|
||||
* @return the resulting premultiplied ARGB color value
|
||||
*/
|
||||
public static int premultiply(int argb) {
|
||||
int alpha = getAlpha(argb);
|
||||
int red = (getRed(argb) * alpha + 127) / 255;
|
||||
int green = (getGreen(argb) * alpha + 127) / 255;
|
||||
int blue = (getBlue(argb) * alpha + 127) / 255;
|
||||
return argb(alpha, red, green, blue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ARGB color value with the specified values for alpha, red, green, and blue channels.
|
||||
*
|
||||
* @param alpha the alpha value, between 0 and 255, to set in the ARGB color value
|
||||
* @param red the red value, between 0 and 255, to set in the ARGB color value
|
||||
* @param green the green value, between 0 and 255, to set in the ARGB color value
|
||||
* @param blue the blue value, between 0 and 255, to set in the ARGB color value
|
||||
*
|
||||
* @return the resulting ARGB color value with the specified values for alpha, red, green, and blue channels
|
||||
*/
|
||||
public static int argb(int alpha, int red, int green, int blue) {
|
||||
return argbAlpha(alpha) | argbRed(red) | argbGreen(green) | argbBlue(blue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ARGB color value with the specified values for alpha, red, green, and blue channels,
|
||||
* after validating that each channel value is in the range 0-255.
|
||||
*
|
||||
* @param alpha the alpha value, between 0 and 255, to set in the ARGB color value
|
||||
* @param red the red value, between 0 and 255, to set in the ARGB color value
|
||||
* @param green the green value, between 0 and 255, to set in the ARGB color value
|
||||
* @param blue the blue value, between 0 and 255, to set in the ARGB color value
|
||||
*
|
||||
* @return the resulting ARGB color value with the specified values for alpha, red, green, and blue channels
|
||||
*
|
||||
* @throws IllegalArgumentException if any channel value is outside the range 0-255
|
||||
*/
|
||||
public static int argbValidated(int alpha, int red, int green, int blue) throws IllegalArgumentException {
|
||||
if(alpha < 0 || alpha > 255 ||
|
||||
red < 0 || red > 255 ||
|
||||
green < 0 || green > 255 ||
|
||||
blue < 0 || blue > 255
|
||||
) throw new IllegalArgumentException("Channel values must be in range 0-255");
|
||||
return argb(alpha, red, green, blue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ARGB color value with the specified alpha channel value and zero
|
||||
* for the red, green, and blue channels.
|
||||
*
|
||||
* @param alpha the alpha channel value to set in the ARGB color value
|
||||
*
|
||||
* @return the resulting ARGB color value
|
||||
*/
|
||||
public static int argbAlpha(int alpha) { return alpha << 24; }
|
||||
|
||||
/**
|
||||
* Returns the ARGB color value with the specified red channel value and zero
|
||||
* for the alpha, green, and blue channels.
|
||||
*
|
||||
* @param red the red channel value to set in the ARGB color value
|
||||
*
|
||||
* @return the resulting ARGB color value
|
||||
*/
|
||||
public static int argbRed(int red) { return red << 16; }
|
||||
|
||||
/**
|
||||
* Returns the ARGB color value with the specified red channel value and zero
|
||||
* for the alpha, red, and blue channels.
|
||||
*
|
||||
* @param green the green channel value to set in the ARGB color value
|
||||
*
|
||||
* @return the resulting ARGB color value
|
||||
*/
|
||||
public static int argbGreen(int green) { return green << 8; }
|
||||
|
||||
/**
|
||||
* Returns the ARGB color value with the specified blue channel value and zero
|
||||
* for the alpha, red, and green channels.
|
||||
*
|
||||
* @param blue the blue channel value to set in the ARGB color value
|
||||
*
|
||||
* @return the resulting ARGB color value
|
||||
*/
|
||||
public static int argbBlue(int blue) { return blue; }
|
||||
|
||||
/**
|
||||
* Returns an ARGB color value with the specified grayscale value for all four channels.
|
||||
*
|
||||
* @param value the grayscale value to set in all four channels of the ARGB color value
|
||||
*
|
||||
* @return the resulting ARGB color value with the specified grayscale value for all four channels
|
||||
*/
|
||||
public static int argbGrayscale(int value) { return argb(value, value, value, value); }
|
||||
|
||||
public enum Channel {
|
||||
RED {
|
||||
@Override
|
||||
public int from(int argb) {
|
||||
return getRed(argb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int zero(int argb) {
|
||||
return zeroRed(argb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int argb(int value) {
|
||||
return argbRed(value);
|
||||
}
|
||||
},
|
||||
GREEN {
|
||||
@Override
|
||||
public int from(int argb) {
|
||||
return getGreen(argb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int zero(int argb) {
|
||||
return zeroGreen(argb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int argb(int value) {
|
||||
return argbGreen(value);
|
||||
}
|
||||
},
|
||||
BLUE {
|
||||
@Override
|
||||
public int from(int argb) {
|
||||
return getBlue(argb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int zero(int argb) {
|
||||
return zeroBlue(argb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int argb(int value) {
|
||||
return argbBlue(value);
|
||||
}
|
||||
},
|
||||
GRAYSCALE {
|
||||
@Override
|
||||
public int from(int argb) {
|
||||
return getGrayscale(argb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int zero(int argb) {
|
||||
return zeroGrayscale(argb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int argb(int value) {
|
||||
return argbAlpha(value);
|
||||
}
|
||||
},
|
||||
ALPHA {
|
||||
@Override
|
||||
public int from(int argb) {
|
||||
return getAlpha(argb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int zero(int argb) {
|
||||
return zeroAlpha(argb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int argb(int value) {
|
||||
return argbAlpha(value);
|
||||
}
|
||||
};
|
||||
|
||||
public abstract int from(int argb);
|
||||
|
||||
public abstract int zero(int argb);
|
||||
|
||||
public abstract int argb(int value);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class MapUtil {
|
||||
|
||||
private MapUtil() { }
|
||||
|
||||
/**
|
||||
* Utility method for applying transformations on a map's keys.
|
||||
*/
|
||||
public static <O, N, T> Map<N, T> mapKeys(Map<O, T> map, Function<O, N> mappingFunction) {
|
||||
return map
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(
|
||||
e -> mappingFunction.apply(e.getKey()),
|
||||
Entry::getValue
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.dfsek.terra.addons.image.util;
|
||||
|
||||
public class MathUtil {
|
||||
private MathUtil() { }
|
||||
|
||||
public static double lerp(double x, double x1, double y1, double x2, double y2) {
|
||||
return (((y1 - y2) * (x - x1)) / (x1 - x2)) + y1;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
schema-version: 1
|
||||
contributors:
|
||||
- Terra contributors
|
||||
id: api-image
|
||||
version: @VERSION@
|
||||
entrypoints:
|
||||
- "com.dfsek.terra.addons.image.ImageLibraryAddon"
|
||||
website:
|
||||
issues: https://github.com/PolyhedralDev/Terra/issues
|
||||
source: https://github.com/PolyhedralDev/Terra
|
||||
docs: https://terra.polydev.org
|
||||
license: MIT License
|
||||
@@ -1,6 +0,0 @@
|
||||
version = version("1.0.0")
|
||||
|
||||
dependencies {
|
||||
compileOnlyApi(project(":common:addons:addon-loader-manifest"))
|
||||
compileOnlyApi(project(":common:addons:api-biome-query"))
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion;
|
||||
|
||||
import com.dfsek.terra.api.util.Column;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
class BaseBiomeColumn implements Column<Biome> {
|
||||
private final BiomeExtrusionProvider biomeProvider;
|
||||
private final Biome base;
|
||||
private final int min;
|
||||
private final int max;
|
||||
|
||||
private final int x;
|
||||
private final int z;
|
||||
private final long seed;
|
||||
|
||||
protected BaseBiomeColumn(BiomeExtrusionProvider biomeProvider, Biome base, int min, int max, int x, int z, long seed) {
|
||||
this.biomeProvider = biomeProvider;
|
||||
this.base = base;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return min;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY() {
|
||||
return max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome get(int y) {
|
||||
return biomeProvider.pipeline.extrude(base, x, y, z, seed);
|
||||
}
|
||||
}
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
|
||||
import com.dfsek.terra.addons.biome.extrusion.config.BiomeExtrusionTemplate;
|
||||
import com.dfsek.terra.addons.biome.extrusion.config.ReplaceableBiomeLoader;
|
||||
import com.dfsek.terra.addons.biome.extrusion.config.extrusions.ReplaceExtrusionTemplate;
|
||||
import com.dfsek.terra.addons.biome.extrusion.config.extrusions.SetExtrusionTemplate;
|
||||
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.addon.BaseAddon;
|
||||
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent;
|
||||
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
|
||||
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||
import com.dfsek.terra.api.registry.CheckedRegistry;
|
||||
import com.dfsek.terra.api.registry.Registry;
|
||||
import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
|
||||
|
||||
public class BiomeExtrusionAddon implements AddonInitializer {
|
||||
public static final TypeKey<Supplier<ObjectTemplate<Extrusion>>> EXTRUSION_REGISTRY_KEY = new TypeKey<>() {
|
||||
};
|
||||
|
||||
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
|
||||
};
|
||||
|
||||
@Inject
|
||||
private Platform platform;
|
||||
|
||||
@Inject
|
||||
private BaseAddon addon;
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
platform.getEventManager()
|
||||
.getHandler(FunctionalEventHandler.class)
|
||||
.register(addon, ConfigPackPreLoadEvent.class)
|
||||
.then(event -> {
|
||||
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry =
|
||||
event.getPack()
|
||||
.getOrCreateRegistry(PROVIDER_REGISTRY_KEY);
|
||||
providerRegistry.register(addon.key("EXTRUSION"), BiomeExtrusionTemplate::new);
|
||||
})
|
||||
.then(event -> {
|
||||
CheckedRegistry<Supplier<ObjectTemplate<Extrusion>>> extrusionRegistry = event.getPack().getOrCreateRegistry(
|
||||
EXTRUSION_REGISTRY_KEY);
|
||||
extrusionRegistry.register(addon.key("SET"), SetExtrusionTemplate::new);
|
||||
extrusionRegistry.register(addon.key("REPLACE"), ReplaceExtrusionTemplate::new);
|
||||
})
|
||||
.failThrough();
|
||||
|
||||
platform.getEventManager()
|
||||
.getHandler(FunctionalEventHandler.class)
|
||||
.register(addon, ConfigPackPostLoadEvent.class)
|
||||
.then(event -> {
|
||||
Registry<Biome> biomeRegistry = event.getPack().getRegistry(Biome.class);
|
||||
event.getPack().applyLoader(ReplaceableBiome.class, new ReplaceableBiomeLoader(biomeRegistry));
|
||||
});
|
||||
}
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
|
||||
import com.dfsek.terra.addons.biome.extrusion.utils.ExtrusionPipeline;
|
||||
import com.dfsek.terra.addons.biome.extrusion.utils.ExtrusionPipelineFactory;
|
||||
import com.dfsek.terra.api.util.Column;
|
||||
import com.dfsek.terra.api.util.generic.data.types.Maybe;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
|
||||
|
||||
public class BiomeExtrusionProvider implements BiomeProvider {
|
||||
public final ExtrusionPipeline pipeline;
|
||||
private final BiomeProvider delegate;
|
||||
private final Set<Biome> biomes;
|
||||
private final int resolution;
|
||||
|
||||
public BiomeExtrusionProvider(BiomeProvider delegate, List<Extrusion> extrusions, int resolution) {
|
||||
this.delegate = delegate;
|
||||
this.biomes = delegate.stream().collect(Collectors.toSet());
|
||||
extrusions.forEach(e -> biomes.addAll(e.getBiomes()));
|
||||
|
||||
this.pipeline = ExtrusionPipelineFactory.create(extrusions);
|
||||
|
||||
this.resolution = resolution;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int y, int z, long seed) {
|
||||
Biome delegated = delegate.getBiome(x, y, z, seed);
|
||||
return pipeline.extrude(delegated, x, y, z, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Column<Biome> getColumn(int x, int z, long seed, int min, int max) {
|
||||
return delegate.getBaseBiome(x, z, seed)
|
||||
.map(base -> (Column<Biome>) new BaseBiomeColumn(this, base, min, max, x, z, seed))
|
||||
.get(() -> BiomeProvider.super.getColumn(x, z, seed, min, max));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<Biome> getBaseBiome(int x, int z, long seed) {
|
||||
return delegate.getBaseBiome(x, z, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Biome> getBiomes() {
|
||||
return biomes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int resolution() {
|
||||
return resolution;
|
||||
}
|
||||
|
||||
public BiomeProvider getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.api;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
public interface Extrusion {
|
||||
Biome extrude(Biome original, int x, int y, int z, long seed);
|
||||
|
||||
Collection<Biome> getBiomes();
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.api;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
final class PresentBiome implements ReplaceableBiome {
|
||||
private final Biome biome;
|
||||
|
||||
PresentBiome(Biome biome) {
|
||||
this.biome = biome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome get(Biome existing) {
|
||||
return biome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelf() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.api;
|
||||
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
/**
|
||||
* Basically just a specialised implementation of {@link Optional} for biomes where a biome may be a "self" reference.
|
||||
*/
|
||||
public sealed interface ReplaceableBiome permits PresentBiome, SelfBiome {
|
||||
static ReplaceableBiome of(Biome biome) {
|
||||
return new PresentBiome(biome);
|
||||
}
|
||||
|
||||
static ReplaceableBiome self() {
|
||||
return SelfBiome.INSTANCE;
|
||||
}
|
||||
|
||||
Biome get(Biome existing);
|
||||
|
||||
default Biome get() {
|
||||
if(isSelf()) {
|
||||
throw new IllegalStateException("Cannot get() self biome!");
|
||||
}
|
||||
return get(null);
|
||||
}
|
||||
|
||||
boolean isSelf();
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.api;
|
||||
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
final class SelfBiome implements ReplaceableBiome {
|
||||
public static final SelfBiome INSTANCE = new SelfBiome();
|
||||
|
||||
@Override
|
||||
public Biome get(Biome existing) {
|
||||
return Objects.requireNonNull(existing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelf() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.biome.extrusion.BiomeExtrusionProvider;
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
|
||||
import com.dfsek.terra.api.config.meta.Meta;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
|
||||
|
||||
public class BiomeExtrusionTemplate implements ObjectTemplate<BiomeProvider> {
|
||||
@Value("provider")
|
||||
private @Meta BiomeProvider provider;
|
||||
|
||||
@Value("resolution")
|
||||
@Default
|
||||
private @Meta int resolution = 4;
|
||||
|
||||
@Value("extrusions")
|
||||
private @Meta List<@Meta Extrusion> extrusions;
|
||||
|
||||
@Override
|
||||
public BiomeProvider get() {
|
||||
return new BiomeExtrusionProvider(provider, extrusions, resolution);
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.config;
|
||||
|
||||
import com.dfsek.tectonic.api.depth.DepthTracker;
|
||||
import com.dfsek.tectonic.api.exception.LoadException;
|
||||
import com.dfsek.tectonic.api.loader.ConfigLoader;
|
||||
import com.dfsek.tectonic.api.loader.type.TypeLoader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
|
||||
import com.dfsek.terra.api.registry.Registry;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
public class ReplaceableBiomeLoader implements TypeLoader<ReplaceableBiome> {
|
||||
private final Registry<Biome> biomeRegistry;
|
||||
|
||||
public ReplaceableBiomeLoader(Registry<Biome> biomeRegistry) {
|
||||
this.biomeRegistry = biomeRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplaceableBiome load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker)
|
||||
throws LoadException {
|
||||
if(c.equals("SELF")) return ReplaceableBiome.self();
|
||||
return biomeRegistry
|
||||
.getByID((String) c)
|
||||
.map(ReplaceableBiome::of)
|
||||
.collectThrow(left -> new LoadException("No such biome: " + c + ": " + left, depthTracker));
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.config.extrusions;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
|
||||
import com.dfsek.terra.addons.biome.extrusion.extrusions.ReplaceExtrusion;
|
||||
import com.dfsek.terra.api.config.meta.Meta;
|
||||
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
|
||||
|
||||
|
||||
public class ReplaceExtrusionTemplate extends SamplerExtrusionTemplate {
|
||||
@Value("to")
|
||||
private @Meta ProbabilityCollection<@Meta ReplaceableBiome> biomes;
|
||||
|
||||
@Value("from")
|
||||
private @Meta String fromTag;
|
||||
|
||||
@Override
|
||||
public Extrusion get() {
|
||||
return new ReplaceExtrusion(sampler, range, biomes, fromTag);
|
||||
}
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.config.extrusions;
|
||||
|
||||
import com.dfsek.seismic.type.sampler.Sampler;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
|
||||
import com.dfsek.terra.api.config.meta.Meta;
|
||||
import com.dfsek.terra.api.util.range.Range;
|
||||
|
||||
|
||||
public abstract class SamplerExtrusionTemplate implements ObjectTemplate<Extrusion> {
|
||||
@Value("sampler")
|
||||
protected @Meta Sampler sampler;
|
||||
|
||||
@Value("range")
|
||||
protected @Meta Range range;
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.config.extrusions;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
|
||||
import com.dfsek.terra.addons.biome.extrusion.extrusions.SetExtrusion;
|
||||
import com.dfsek.terra.api.config.meta.Meta;
|
||||
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
|
||||
|
||||
|
||||
public class SetExtrusionTemplate extends SamplerExtrusionTemplate {
|
||||
@Value("to")
|
||||
private @Meta ProbabilityCollection<@Meta ReplaceableBiome> biomes;
|
||||
|
||||
@Override
|
||||
public Extrusion get() {
|
||||
return new SetExtrusion(sampler, range, biomes);
|
||||
}
|
||||
}
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.extrusions;
|
||||
|
||||
import com.dfsek.seismic.type.sampler.Sampler;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
|
||||
import com.dfsek.terra.addons.biome.query.api.BiomeQueries;
|
||||
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.util.collection.TriStateIntCache;
|
||||
import com.dfsek.terra.api.util.range.Range;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
/**
|
||||
* Sets biomes at locations based on a sampler.
|
||||
*/
|
||||
public class ReplaceExtrusion implements Extrusion {
|
||||
private final Sampler sampler;
|
||||
private final Range range;
|
||||
private final ProbabilityCollection<ReplaceableBiome> biomes;
|
||||
private final Predicate<Biome> hasTag;
|
||||
private final TriStateIntCache cache;
|
||||
|
||||
public ReplaceExtrusion(Sampler sampler, Range range, ProbabilityCollection<ReplaceableBiome> biomes, String tag) {
|
||||
this.sampler = sampler;
|
||||
this.range = range;
|
||||
this.biomes = biomes;
|
||||
this.hasTag = BiomeQueries.has(tag);
|
||||
this.cache = new TriStateIntCache(Biome.INT_ID_COUNTER.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome extrude(Biome original, int x, int y, int z, long seed) {
|
||||
int id = original.getIntID();
|
||||
|
||||
long state = cache.get(id);
|
||||
boolean passes;
|
||||
|
||||
if(state == TriStateIntCache.STATE_UNSET) {
|
||||
// Only run the test if unset in cache
|
||||
passes = hasTag.test(original);
|
||||
cache.set(id, passes);
|
||||
} else {
|
||||
// Read the primitive long directly
|
||||
passes = (state == TriStateIntCache.STATE_TRUE);
|
||||
}
|
||||
|
||||
if(passes) {
|
||||
if(range.isInRange(y)) {
|
||||
return biomes.get(sampler, x, y, z, seed).get(original);
|
||||
}
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Biome> getBiomes() {
|
||||
return biomes
|
||||
.getContents()
|
||||
.stream()
|
||||
.filter(Predicate.not(ReplaceableBiome::isSelf))
|
||||
.map(ReplaceableBiome::get)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.extrusions;
|
||||
|
||||
import com.dfsek.seismic.type.sampler.Sampler;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
|
||||
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.util.range.Range;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
/**
|
||||
* Sets biomes at locations based on a sampler.
|
||||
*/
|
||||
public class SetExtrusion implements Extrusion {
|
||||
private final Sampler sampler;
|
||||
|
||||
private final Range range;
|
||||
|
||||
private final ProbabilityCollection<ReplaceableBiome> biomes;
|
||||
|
||||
public SetExtrusion(Sampler sampler, Range range, ProbabilityCollection<ReplaceableBiome> biomes) {
|
||||
this.sampler = sampler;
|
||||
this.range = range;
|
||||
this.biomes = biomes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome extrude(Biome original, int x, int y, int z, long seed) {
|
||||
return range.ifInRange(y, () -> biomes.get(sampler, x, y, z, seed).get(original), original);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Biome> getBiomes() {
|
||||
return biomes
|
||||
.getContents()
|
||||
.stream()
|
||||
.filter(Predicate.not(ReplaceableBiome::isSelf))
|
||||
.map(ReplaceableBiome::get)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.utils;
|
||||
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
|
||||
public interface ExtrusionPipeline {
|
||||
Biome extrude(Biome original, int x, int y, int z, long seed);
|
||||
}
|
||||
-158
@@ -1,158 +0,0 @@
|
||||
package com.dfsek.terra.addons.biome.extrusion.utils;
|
||||
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.AALOAD;
|
||||
import static org.objectweb.asm.Opcodes.ACC_FINAL;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
import static org.objectweb.asm.Opcodes.ALOAD;
|
||||
import static org.objectweb.asm.Opcodes.ARETURN;
|
||||
import static org.objectweb.asm.Opcodes.GETFIELD;
|
||||
import static org.objectweb.asm.Opcodes.ILOAD;
|
||||
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
|
||||
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
|
||||
import static org.objectweb.asm.Opcodes.LLOAD;
|
||||
import static org.objectweb.asm.Opcodes.PUTFIELD;
|
||||
import static org.objectweb.asm.Opcodes.RETURN;
|
||||
import static org.objectweb.asm.Opcodes.SIPUSH;
|
||||
import static org.objectweb.asm.Opcodes.SWAP;
|
||||
import static org.objectweb.asm.Opcodes.V1_8;
|
||||
|
||||
|
||||
public class ExtrusionPipelineFactory {
|
||||
private static final AtomicInteger ID_COUNTER = new AtomicInteger(0);
|
||||
|
||||
// Type Descriptors
|
||||
private static final String EXTRUSION_TYPE = Type.getInternalName(Extrusion.class);
|
||||
private static final String EXTRUSION_DESC = Type.getDescriptor(Extrusion.class);
|
||||
private static final String BIOME_DESC = Type.getDescriptor(Biome.class);
|
||||
private static final String PIPELINE_INTERFACE = Type.getInternalName(ExtrusionPipeline.class);
|
||||
|
||||
// Method Signature: (Biome, int, int, int, long) -> Biome
|
||||
private static final String EXTRUDE_SIG = "(" + BIOME_DESC + "IIIJ)" + BIOME_DESC;
|
||||
|
||||
public static ExtrusionPipeline create(List<Extrusion> extrusions) {
|
||||
// Optimization: If empty, return identity
|
||||
if(extrusions.isEmpty()) {
|
||||
return (original, x, y, z, seed) -> original;
|
||||
}
|
||||
|
||||
String className = "com/dfsek/terra/addons/biome/extrusion/GeneratedExtrusionPipeline_" + ID_COUNTER.getAndIncrement();
|
||||
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
|
||||
// 1. Define Class
|
||||
cw.visit(V1_8, ACC_PUBLIC | ACC_FINAL, className, null, "java/lang/Object", new String[]{ PIPELINE_INTERFACE });
|
||||
|
||||
// 2. Define Fields (e0, e1, e2...)
|
||||
for(int i = 0; i < extrusions.size(); i++) {
|
||||
FieldVisitor fv = cw.visitField(ACC_PRIVATE | ACC_FINAL, "e" + i, EXTRUSION_DESC, null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
|
||||
// 3. Generate Constructor(Extrusion[])
|
||||
generateConstructor(cw, className, extrusions.size());
|
||||
|
||||
// 4. Generate extrude() method
|
||||
generateExtrudeMethod(cw, className, extrusions.size());
|
||||
|
||||
cw.visitEnd();
|
||||
|
||||
// 5. Load and Instantiate
|
||||
byte[] bytecode = cw.toByteArray();
|
||||
try {
|
||||
Class<?> generatedClass = new PipelineClassLoader(ExtrusionPipelineFactory.class.getClassLoader())
|
||||
.defineClass(className.replace('/', '.'), bytecode);
|
||||
|
||||
return (ExtrusionPipeline) generatedClass.getConstructor(Extrusion[].class)
|
||||
.newInstance((Object) extrusions.toArray(new Extrusion[0]));
|
||||
} catch(Exception e) {
|
||||
throw new RuntimeException("Failed to generate ExtrusionPipeline", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void generateConstructor(ClassWriter cw, String className, int count) {
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "([L" + EXTRUSION_TYPE + ";)V", null, null);
|
||||
mv.visitCode();
|
||||
|
||||
// super()
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
|
||||
// Assign array elements to fields
|
||||
for(int i = 0; i < count; i++) {
|
||||
mv.visitVarInsn(ALOAD, 0); // Load this
|
||||
mv.visitVarInsn(ALOAD, 1); // Load array argument
|
||||
mv.visitIntInsn(SIPUSH, i); // Load index
|
||||
mv.visitInsn(AALOAD); // Load array[i]
|
||||
mv.visitFieldInsn(PUTFIELD, className, "e" + i, EXTRUSION_DESC);
|
||||
}
|
||||
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 0); // Computed automatically
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private static void generateExtrudeMethod(ClassWriter cw, String className, int count) {
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "extrude", EXTRUDE_SIG, null, null);
|
||||
mv.visitCode();
|
||||
|
||||
// Helper var indices:
|
||||
// 0: this
|
||||
// 1: Biome original (We will update this or chain it on stack)
|
||||
// 2: int x
|
||||
// 3: int y
|
||||
// 4: int z
|
||||
// 5: long seed
|
||||
|
||||
mv.visitVarInsn(ALOAD, 1); // Load 'original' Biome onto stack initially
|
||||
|
||||
for(int i = 0; i < count; i++) {
|
||||
// Stack contains: [CurrentBiome]
|
||||
|
||||
mv.visitVarInsn(ALOAD, 0); // Load 'this'
|
||||
mv.visitFieldInsn(GETFIELD, className, "e" + i, EXTRUSION_DESC); // Load Extrusion field
|
||||
|
||||
// Stack: [CurrentBiome, Extrusion]
|
||||
// We need: [Extrusion, CurrentBiome, x, y, z, seed]
|
||||
|
||||
mv.visitInsn(SWAP); // Swap to get [Extrusion, CurrentBiome]
|
||||
|
||||
mv.visitVarInsn(ILOAD, 2); // x
|
||||
mv.visitVarInsn(ILOAD, 3); // y
|
||||
mv.visitVarInsn(ILOAD, 4); // z
|
||||
mv.visitVarInsn(LLOAD, 5); // seed
|
||||
|
||||
// Invoke Extrusion.extrude(Biome, x, y, z, seed)
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, EXTRUSION_TYPE, "extrude", EXTRUDE_SIG, true);
|
||||
|
||||
// Stack now contains: [NewBiome]
|
||||
// Loop continues using this result as input for the next one
|
||||
}
|
||||
|
||||
mv.visitInsn(ARETURN); // Return the final Biome
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
// Custom ClassLoader to inject the bytes
|
||||
private static class PipelineClassLoader extends ClassLoader {
|
||||
public PipelineClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
public Class<?> defineClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
schema-version: 1
|
||||
contributors:
|
||||
- Terra contributors
|
||||
id: biome-provider-extrusion
|
||||
version: @VERSION@
|
||||
entrypoints:
|
||||
- "com.dfsek.terra.addons.biome.extrusion.BiomeExtrusionAddon"
|
||||
website:
|
||||
issues: https://github.com/PolyhedralDev/Terra/issues
|
||||
source: https://github.com/PolyhedralDev/Terra
|
||||
docs: https://terra.polydev.org
|
||||
license: MIT License
|
||||
depends:
|
||||
api-biome-query: "1.+"
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2025 Polyhedral Development
|
||||
Copyright (c) 2020-2021 Polyhedral Development
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# biome-provider-image-v2
|
||||
# biome-provider-image
|
||||
|
||||
Implements and registers the `IMAGE` biome provider, which
|
||||
utilizes various config types provided by the `api-image` addon to
|
||||
distribute biomes based on images.
|
||||
Implements and registers the `IMAGE` biome provider, a biome provider which
|
||||
generates biomes from an image, using the `color` attribute of biomes.
|
||||
|
||||
This addon registers the provider type, and all associated config options.
|
||||
@@ -1,8 +1,5 @@
|
||||
version = version("2.0.0")
|
||||
version = version("0.1.0")
|
||||
|
||||
dependencies {
|
||||
compileOnlyApi(project(":common:addons:addon-loader-manifest"))
|
||||
compileOnlyApi(project(":common:addons:api-image"))
|
||||
|
||||
|
||||
shadedApi(project(":common:addons:manifest-addon-loader"))
|
||||
}
|
||||
|
||||
+51
-27
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2025 Polyhedral Development
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
@@ -7,46 +7,70 @@
|
||||
|
||||
package com.dfsek.terra.addons.biome.image;
|
||||
|
||||
import java.util.Optional;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.converter.ColorConverter;
|
||||
import com.dfsek.terra.api.util.generic.data.types.Maybe;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
|
||||
|
||||
public class ImageBiomeProvider implements BiomeProvider {
|
||||
private final Map<Color, Biome> colorBiomeMap = new HashMap<>();
|
||||
private final BufferedImage image;
|
||||
private final int resolution;
|
||||
|
||||
private final ColorConverter<Biome> colorConverter;
|
||||
|
||||
private final ColorSampler colorSampler;
|
||||
|
||||
public ImageBiomeProvider(ColorConverter<Biome> colorConverter, ColorSampler colorSampler, int resolution) {
|
||||
private final Align align;
|
||||
|
||||
public ImageBiomeProvider(Set<Biome> registry, BufferedImage image, int resolution, Align align) {
|
||||
this.image = image;
|
||||
this.resolution = resolution;
|
||||
this.colorConverter = colorConverter;
|
||||
this.colorSampler = colorSampler;
|
||||
this.align = align;
|
||||
registry.forEach(biome -> colorBiomeMap.put(new Color(biome.getColor()), biome));
|
||||
}
|
||||
|
||||
|
||||
private static int distance(Color a, Color b) {
|
||||
return FastMath.abs(a.getRed() - b.getRed()) + FastMath.abs(a.getGreen() - b.getGreen()) + FastMath.abs(a.getBlue() - b.getBlue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int y, int z, long seed) {
|
||||
return getBiome(x, z);
|
||||
}
|
||||
|
||||
public Biome getBiome(int x, int z) {
|
||||
public Biome getBiome(int x, int z, long seed) {
|
||||
x /= resolution;
|
||||
z /= resolution;
|
||||
return colorConverter.apply(colorSampler.apply(x, z));
|
||||
Color color = align.getColor(image, x, z);
|
||||
return colorBiomeMap.get(colorBiomeMap.keySet()
|
||||
.stream()
|
||||
.reduce(colorBiomeMap.keySet().stream().findAny().orElseThrow(IllegalStateException::new),
|
||||
(running, element) -> {
|
||||
int d1 = distance(color, running);
|
||||
int d2 = distance(color, element);
|
||||
return d1 < d2 ? running : element;
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Maybe<Biome> getBaseBiome(int x, int z, long seed) {
|
||||
return Maybe.just(getBiome(x, z));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterable<Biome> getBiomes() {
|
||||
return colorConverter.getEntries();
|
||||
return colorBiomeMap.values();
|
||||
}
|
||||
|
||||
public enum Align {
|
||||
CENTER {
|
||||
@Override
|
||||
public Color getColor(BufferedImage image, int x, int z) {
|
||||
return new Color(image.getRGB(FastMath.floorMod(x - image.getWidth() / 2, image.getWidth()),
|
||||
FastMath.floorMod(z - image.getHeight() / 2, image.getHeight())));
|
||||
}
|
||||
},
|
||||
NONE {
|
||||
@Override
|
||||
public Color getColor(BufferedImage image, int x, int z) {
|
||||
return new Color(image.getRGB(FastMath.floorMod(x, image.getWidth()), FastMath.floorMod(z, image.getHeight())));
|
||||
}
|
||||
};
|
||||
|
||||
public abstract Color getColor(BufferedImage image, int x, int z);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-42
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2025 Polyhedral Development
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
@@ -11,13 +11,6 @@ import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.dfsek.terra.addons.biome.image.config.ImageProviderTemplate;
|
||||
import com.dfsek.terra.addons.biome.image.config.converter.ClosestBiomeColorConverterTemplate;
|
||||
import com.dfsek.terra.addons.biome.image.config.converter.ExactBiomeColorConverterTemplate;
|
||||
import com.dfsek.terra.addons.biome.image.config.converter.mapping.DefinedBiomeColorMappingTemplate;
|
||||
import com.dfsek.terra.addons.image.converter.ColorConverter;
|
||||
import com.dfsek.terra.addons.image.converter.mapping.BiomeDefinedColorMapping;
|
||||
import com.dfsek.terra.addons.image.converter.mapping.ColorMapping;
|
||||
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.addon.BaseAddon;
|
||||
@@ -33,46 +26,24 @@ import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
public class ImageBiomeProviderAddon implements AddonInitializer {
|
||||
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
|
||||
};
|
||||
|
||||
public static final TypeKey<Supplier<ObjectTemplate<ColorConverter<Biome>>>> BIOME_COLOR_CONVERTER_REGISTRY_KEY = new TypeKey<>() {
|
||||
};
|
||||
|
||||
public static final TypeKey<Supplier<ObjectTemplate<ColorMapping<Biome>>>> BIOME_COLOR_MAPPING_REGISTRY_KEY = new TypeKey<>() {
|
||||
};
|
||||
|
||||
|
||||
@Inject
|
||||
private Platform platform;
|
||||
|
||||
|
||||
@Inject
|
||||
private BaseAddon addon;
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
platform.getEventManager()
|
||||
.getHandler(FunctionalEventHandler.class)
|
||||
.register(addon, ConfigPackPreLoadEvent.class)
|
||||
.priority(501)
|
||||
.then(event -> {
|
||||
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(
|
||||
PROVIDER_REGISTRY_KEY);
|
||||
providerRegistry.register(addon.key("IMAGE"), ImageProviderTemplate::new);
|
||||
})
|
||||
.then(event -> {
|
||||
CheckedRegistry<Supplier<ObjectTemplate<ColorConverter<Biome>>>> biomeColorConverterRegistry =
|
||||
event.getPack().getOrCreateRegistry(
|
||||
BIOME_COLOR_CONVERTER_REGISTRY_KEY);
|
||||
biomeColorConverterRegistry.register(addon.key("EXACT"), ExactBiomeColorConverterTemplate::new);
|
||||
biomeColorConverterRegistry.register(addon.key("CLOSEST"), ClosestBiomeColorConverterTemplate::new);
|
||||
})
|
||||
.then(event -> {
|
||||
CheckedRegistry<Supplier<ObjectTemplate<ColorMapping<Biome>>>> biomeColorMappingRegistry =
|
||||
event.getPack().getOrCreateRegistry(
|
||||
BIOME_COLOR_MAPPING_REGISTRY_KEY);
|
||||
biomeColorMappingRegistry.register(addon.key("USE_BIOME_COLORS"),
|
||||
() -> () -> new BiomeDefinedColorMapping<>(event.getPack().getRegistry(Biome.class),
|
||||
b -> b));
|
||||
biomeColorMappingRegistry.register(addon.key("MAP"), DefinedBiomeColorMappingTemplate::new);
|
||||
})
|
||||
.failThrough();
|
||||
.getHandler(FunctionalEventHandler.class)
|
||||
.register(addon, ConfigPackPreLoadEvent.class)
|
||||
.then(event -> {
|
||||
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(
|
||||
PROVIDER_REGISTRY_KEY);
|
||||
providerRegistry.register(addon.key("IMAGE"),
|
||||
() -> new ImageProviderTemplate(event.getPack().getRegistry(Biome.class)));
|
||||
})
|
||||
.failThrough();
|
||||
}
|
||||
}
|
||||
|
||||
+19
-14
@@ -1,40 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2025 Polyhedral Development
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.biome.image.config;
|
||||
package com.dfsek.terra.addons.biome.image;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Description;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import com.dfsek.terra.addons.biome.image.ImageBiomeProvider;
|
||||
import com.dfsek.terra.addons.image.colorsampler.ColorSampler;
|
||||
import com.dfsek.terra.addons.image.converter.ColorConverter;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.dfsek.terra.api.registry.Registry;
|
||||
import com.dfsek.terra.api.world.biome.Biome;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
|
||||
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
public class ImageProviderTemplate implements ObjectTemplate<BiomeProvider> {
|
||||
|
||||
private final Registry<Biome> biomes;
|
||||
@Value("resolution")
|
||||
@Default
|
||||
@Description("Sets the resolution at which to sample the image.")
|
||||
private int resolution = 1;
|
||||
|
||||
@Value("color-sampler")
|
||||
private ColorSampler colorSampler;
|
||||
|
||||
@Value("color-conversion")
|
||||
private ColorConverter<Biome> colorConverter;
|
||||
|
||||
@Value("image.name")
|
||||
@Description("Sets the location of the image on the filesystem, relative to the pack root.")
|
||||
private BufferedImage image;
|
||||
@Value("image.align")
|
||||
@Description("Sets the alignment style to use for the image.")
|
||||
private ImageBiomeProvider.Align align;
|
||||
|
||||
public ImageProviderTemplate(Registry<Biome> set) {
|
||||
this.biomes = set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeProvider get() {
|
||||
return new ImageBiomeProvider(colorConverter, colorSampler, resolution);
|
||||
return new ImageBiomeProvider(new HashSet<>(biomes.entries()), image, resolution, align);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user