Reformat all code

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
This commit is contained in:
solonovamax 2021-08-30 17:34:44 -04:00
parent 1655381413
commit c445a0434d
No known key found for this signature in database
GPG Key ID: ED0FC2D44CD76482
753 changed files with 10461 additions and 8783 deletions

View File

@ -2,32 +2,41 @@
# TL;DR # TL;DR
Polyhedral Development is dedicated to providing a harassment-free experience for everyone, regardless of gender, gender identity and Polyhedral Development is dedicated to providing a harassment-free experience
expression, preferred pronouns, sexual orientation, disability, physical appearance, age, race, religion, etc. We do not tolerate harassment for everyone, regardless of gender, gender identity and expression, preferred
of participants in any form. pronouns, sexual orientation, disability, physical appearance, age, race,
religion, etc. We do not tolerate harassment of participants in any form.
This code of conduct applies to all Terra community spaces, including the github discussions tab, our This code of conduct applies to all Terra community spaces, including the github
[community discord server](https://discord.gg/PXUEbbF), the [community subreddit](https://reddit.com/r/TerraGenerator), or any other Terra discussions tab, our [community discord server](https://discord.gg/PXUEbbF),
space, both online and off. Anyone in violation of this code, as determined by the applicable moderators, may be subject to verbal warning, the [community subreddit](https://reddit.com/r/TerraGenerator), or any other
expulsion from these spaces, or future events and activities for an undetermined amount of time. Terra space, both online and off. Anyone in violation of this code, as
determined by the applicable moderators, may be subject to verbal warning,
expulsion from these spaces, or future events and activities for an undetermined
amount of time.
Some Terra community spaces may have additional rules in place, which will be made clearly available to all participants. Participants are Some Terra community spaces may have additional rules in place, which will be
responsible for knowing and abiding by these rules. made clearly available to all participants. Participants are responsible for
knowing and abiding by these rules.
# Longer version # Longer version
Polyhedral Development is dedicated to providing a harassment-free experience for everyone. We do not tolerate harassment of participants in Polyhedral Development is dedicated to providing a harassment-free experience
any form. for everyone. We do not tolerate harassment of participants in any form.
## When and How to Use These Guidelines ## When and How to Use These Guidelines
This code of conduct applies to all Terra community spaces, both online and off. This applies to the github discussion tab, This code of conduct applies to all Terra community spaces, both online and off.
the [Polyhedral Development community discord server](https://discord.gg/PXUEbbF), and any other Terra community. In addition, we may choose This applies to the github discussion tab, the
to invoke them in instances of harassment outside the Terra communities, and we will punish the responsible individuals appropriately. We [Polyhedral Development community discord server](https://discord.gg/PXUEbbF),
will not tolerate harassment in any form, even outside of Terra. and any other Terra community. In addition, we may choose to invoke them in
instances of harassment outside the Terra communities, and we will punish the
responsible individuals appropriately. We will not tolerate harassment in any
form, even outside of Terra.
Some Terra spaces may have additional rules in place, which will be made clearly available to participants. Participants are responsible for Some Terra spaces may have additional rules in place, which will be made clearly
knowing and abiding by these rules, in addition to this code of conduct. available to participants. Participants are responsible for knowing and abiding
by these rules, in addition to this code of conduct.
## Expected Behavior ## Expected Behavior
@ -35,33 +44,43 @@ The following behaviors are expected of all members of the Terra community:
### Be Respectful ### Be Respectful
Value each other's ideas, styles and viewpoints. We may not always agree, but disagreement is no excuse for poor manners. Be open to Value each other's ideas, styles and viewpoints. We may not always agree, but
different possibilities and to being wrong. Be respectful in all interactions and communications, especially when debating the merits of disagreement is no excuse for poor manners. Be open to different possibilities
different options. Be aware of your impact and how intense interactions may be affecting people. Be direct, constructive and positive. Take and to being wrong. Be respectful in all interactions and communications,
responsibility for your impact, and your mistakes if someone says they have been harmed through your words or actions, listen carefully, especially when debating the merits of different options. Be aware of your
apologize sincerely, and correct the behavior going forward. impact and how intense interactions may be affecting people. Be direct,
constructive and positive. Take responsibility for your impact, and your
mistakes if someone says they have been harmed through your words or actions,
listen carefully, apologize sincerely, and correct the behavior going forward.
#### Be Prepared to Admit When You are Wrong #### Be Prepared to Admit When You are Wrong
Any member of the Terra community should always be open to new ideas and must always be open to the possibility of being wrong. Nobody can Any member of the Terra community should always be open to new ideas and must
always be right, and we are only human; we are [fallible](https://www.merriam-webster.com/dictionary/fallible) by nature. It is okay to make always be open to the possibility of being wrong. Nobody can always be right,
mistakes, but we must be willing to admit when we make one. and we are only human; we are
[fallible](https://www.merriam-webster.com/dictionary/fallible) by nature.
It is okay to make mistakes, but we must be willing to admit when we make one.
### Be Direct but Professional ### Be Direct but Professional
We are likely to have some discussions about if and when criticism is respectful and when it's not. We must be able to speak directly when We are likely to have some discussions about if and when criticism is respectful
we disagree and when we think we need to improve. We cannot withhold hard truths. Doing so respectfully is hard, doing so when others don't and when it's not. We must be able to speak directly when we disagree and when
seem to be listening is harder, and hearing such comments when one is the recipient can be even harder still. We need to be honest and we think we need to improve. We cannot withhold hard truths. Doing so
direct, as well as respectful. respectfully is hard, doing so when others don't seem to be listening is harder,
and hearing such comments when one is the recipient can be even harder still. We
need to be honest and direct, as well as respectful.
### Be Inclusive ### Be Inclusive
Seek diverse perspectives. Diversity of views and of people on teams powers innovation, even if it is not always comfortable. Encourage all Seek diverse perspectives. Diversity of views and of people on teams powers
voices. Help new perspectives be heard and listen actively. If you find yourself dominating a discussion, it is especially important to step innovation, even if it is not always comfortable. Encourage all voices. Help new
back and encourage other voices to join in. Be aware of how much time is taken up by dominant members of the group. Provide alternative ways perspectives be heard and listen actively. If you find yourself dominating a
to contribute or participate when possible. discussion, it is especially important to step back and encourage other voices
to join in. Be aware of how much time is taken up by dominant members of the
group. Provide alternative ways to contribute or participate when possible.
Be inclusive of everyone in an interaction, respecting and facilitating people's participation whether they are: Be inclusive of everyone in an interaction, respecting and facilitating people's
participation whether they are:
- Not native language speakers - Not native language speakers
- Coming from a different culture - Coming from a different culture
@ -70,47 +89,60 @@ Be inclusive of everyone in an interaction, respecting and facilitating people's
- Facing other challenges to participate - Facing other challenges to participate
- Or anything else. Be respectful of *everyone* at *all times*. - Or anything else. Be respectful of *everyone* at *all times*.
Think about how you might facilitate alternative ways to contribute or participate. If you find yourself dominating a discussion, step back. Think about how you might facilitate alternative ways to contribute or
Make way for other voices and listen actively to them. participate. If you find yourself dominating a discussion, step back. Make way
for other voices and listen actively to them.
### Understand Different Perspectives ### Understand Different Perspectives
Our goal should not be to "win" every disagreement or argument. A more productive goal is to be open to ideas that make our own ideas Our goal should not be to "win" every disagreement or argument. A more
better. Strive to be an example for inclusive thinking. "Winning" is when different perspectives make our work richer and stronger. That productive goal is to be open to ideas that make our own ideas better. Strive to
means, you must pay attention to all ideas proposed. Don't disregard one without giving it the attention it deserves. be an example for inclusive thinking. "Winning" is when different perspectives
make our work richer and stronger. That means, you must pay attention to all
ideas proposed. Don't disregard one without giving it the attention it deserves.
### Appreciate and Accommodate Our Similarities and Differences ### Appreciate and Accommodate Our Similarities and Differences
People come from many cultures and backgrounds. Cultural differences can encompass everything from official religious observances to People come from many cultures and backgrounds. Cultural differences can
personal habits to clothing. Be respectful of anyone with different cultural practices, attitudes and beliefs. Work to eliminate your own encompass everything from official religious observances to personal habits to
biases, prejudices and discriminatory practices. Think of others' needs from their point of view. Use preferred titles (including clothing. Be respectful of anyone with different cultural practices, attitudes
pronouns<sup>[\[1\]](#1)</sup>) and the appropriate tone of voice. Respect people's right to privacy and confidentiality. Be open to and beliefs. Work to eliminate your own biases, prejudices and discriminatory
learning from and educating others as well as educating yourself; it is unrealistic to expect someone to know the cultural practices of practices. Think of others' needs from their point of view. Use preferred
every ethnic and cultural group. Therefore we must be ready to correct someone if they make a mistake, and must be ready ourselves to change titles (including pronouns<sup>[\[1\]](#1)</sup>) and the appropriate tone of
and learn if we make a mistake. voice. Respect people's right to privacy and confidentiality. Be open to
learning from and educating others as well as educating yourself; it is
unrealistic to expect someone to know the cultural practices of every ethnic and
cultural group. Therefore we must be ready to correct someone if they make a
mistake, and must be ready ourselves to change and learn if we make a mistake.
### Lead by Example ### Lead by Example
By matching your actions with your words, you become a person others want to follow. Your actions influence others to behave and respond in By matching your actions with your words, you become a person others want to
ways that are valuable and appropriate for our organizational outcomes. Design your community and your work for inclusion. Hold yourself and follow. Your actions influence others to behave and respond in ways that are
others accountable for inclusive behaviors. valuable and appropriate for our organizational outcomes. Design your community
and your work for inclusion. Hold yourself and others accountable for inclusive
behaviors.
## Behavior That Will Not Be Tolerated ## Behavior That Will Not Be Tolerated
The following behaviors are considered to be unacceptable and will not be tolerated: The following behaviors are considered to be unacceptable and will not be
tolerated:
### Violence and Threats of Violence ### Violence and Threats of Violence
Violence and threats of violence are not acceptable - online or offline. This includes incitement of violence toward any individual, Violence and threats of violence are not acceptable - online or offline. This
including encouraging a person to commit self-harm, engage in self-harm, or put themselves in a negative position (e.g. one which can lead includes incitement of violence toward any individual, including encouraging a
to an increase of depression, etc.). person to commit self-harm, engage in self-harm, or put themselves in a negative
position (e.g. one which can lead to an increase of depression, etc.).
### Personal Attacks ### Personal Attacks
Conflicts will inevitably arise, but frustration should never turn into a personal attack. It is not okay to insult, demean or belittle Conflicts will inevitably arise, but frustration should never turn into a
others. Attacking someone for their opinions, beliefs and ideas is not acceptable. It is important to speak directly when we disagree and personal attack. It is not okay to insult, demean or belittle others. Attacking
when we think we need to improve, but such discussions must be conducted respectfully and professionally, remaining focused on the issue at someone for their opinions, beliefs and ideas is not acceptable. It is important
hand. to speak directly when we disagree and when we think we need to improve, but
such discussions must be conducted respectfully and professionally, remaining
focused on the issue at hand.
### Derogatory Language ### Derogatory Language
@ -135,30 +167,40 @@ Offensive, unwelcome, or hurtful comments related to:
- Socioeconomic status - Socioeconomic status
- Religion - Religion
- Employment - Employment
- Or anything really. Just don't be offensive towards people, insult them, or make unwanted comments. - Or anything really. Just don't be offensive towards people, insult them, or
make unwanted comments.
is not acceptable. This includes deliberately referring to someone by a gender that they do not identify with, and/or questioning the is not acceptable. This includes deliberately referring to someone by a gender
legitimacy of an individual's gender identity. If you're unsure if a word is derogatory, don't use it. This also includes repeated subtle that they do not identify with, and/or questioning the legitimacy of an
and/or indirect discrimination; when asked to stop, stop the behavior in question. individual's gender identity. If you're unsure if a word is derogatory, don't
use it. This also includes repeated subtle and/or indirect discrimination; when
asked to stop, stop the behavior in question.
### Unwelcome Sexual Attention or Physical Contact ### Unwelcome Sexual Attention or Physical Contact
Unwelcome sexual attention or unwelcome physical contact is not acceptable. This includes sexualized comments, jokes or imagery in Unwelcome sexual attention or unwelcome physical contact is not acceptable. This
interactions, communications or presentation materials, as well as inappropriate touching, groping, or sexual advances. Additionally, includes sexualized comments, jokes or imagery in interactions, communications
touching a person without permission, including sensitive areas such as their hair, pregnant stomach, mobility device (wheelchair, scooter, or presentation materials, as well as inappropriate touching, groping, or sexual
etc) or tattoos is unacceptable. This includes physically blocking or intimidating another person. Physical contact or simulated physical advances. Additionally, touching a person without permission, including
contact (e.g. emojis like ":&#8203;kiss:", ":hug:", or ":kiss_mark:", textual descriptions like "\*hug\*", "\*backrub\*", or "\*kisses sensitive areas such as their hair, pregnant stomach, mobility device (
you\*", etc.) without affirmative consent or after a request to stop will not be accepted. wheelchair, scooter, etc) or tattoos is unacceptable. This includes physically
blocking or intimidating another person. Physical contact or simulated physical
contact (e.g. emojis like ":&#8203;kiss:", ":hug:", or ":kiss_mark:", textual
descriptions like "\*hug\*", "\*backrub\*", or "\*kisses you\*", etc.) without
affirmative consent or after a request to stop will not be accepted.
### Sexual Behaviour Where it is Not Appropriate ### Sexual Behaviour Where it is Not Appropriate
Uninvited or off-topic sexual images, text, or behaviour in spaces where they're not appropriate will not be accepted whatsoever. We are an Uninvited or off-topic sexual images, text, or behaviour in spaces where they're
open community, which means spaces must be appropriate for all ages, and everybody must feel comfortable. Discussion of sexual things, will not appropriate will not be accepted whatsoever. We are an open community, which
be prohibited unless otherwise noted. means spaces must be appropriate for all ages, and everybody must feel
comfortable. Discussion of sexual things, will be prohibited unless otherwise
noted.
### Discussion of Sensitive Topics ### Discussion of Sensitive Topics
Discussion of sensitive topics when asked to stop, or when not appropriate. Including, but not limited to: Discussion of sensitive topics when asked to stop, or when not appropriate.
Including, but not limited to:
- Anything sexual - Anything sexual
- Gore - Gore
@ -167,171 +209,241 @@ Discussion of sensitive topics when asked to stop, or when not appropriate. Incl
- Anything related to death - Anything related to death
- Or really anything that someone may be sensitive about. - Or really anything that someone may be sensitive about.
shall not be tolerated. As a community for all ages and all kinds of people, we must cater to everyone, and must make sure everyone feels shall not be tolerated. As a community for all ages and all kinds of people, we
comfortable here. Repeatedly breaking someone else's boundaries will not be tolerated. must cater to everyone, and must make sure everyone feels comfortable here.
Repeatedly breaking someone else's boundaries will not be tolerated.
### Disruptive Behavior ### Disruptive Behavior
Sustained disruption of events, forums, or meetings, online or otherwise, including talks and presentations, will not be tolerated. This Sustained disruption of events, forums, or meetings, online or otherwise,
includes: including talks and presentations, will not be tolerated. This includes:
- 'Talking over', 'heckling', or otherwise disrupting speakers. - 'Talking over', 'heckling', or otherwise disrupting speakers.
- Making derogatory comments about someone else's choices, pushing people to do something they do not wish to do, talking about their - Making derogatory comments about someone else's choices, pushing people to do
choices or personal preferences to others, or pressuring them to do something they don't wish to - physically or through jeering. something they do not wish to do, talking about their choices or personal
preferences to others, or pressuring them to do something they don't wish to -
physically or through jeering.
- Behaviour that intentionally disrupts an event. - Behaviour that intentionally disrupts an event.
- Otherwise influencing actions that may cause hostility in the session. - Otherwise influencing actions that may cause hostility in the session.
### Influencing Unacceptable Behavior ### Influencing Unacceptable Behavior
We will treat influencing or leading such activities the same way we treat the activities themselves, and thus the same consequences apply. We will treat influencing or leading such activities the same way we treat the
To make someone do something bad is the same thing as if you were to do it yourself, and we will not tolerate it. activities themselves, and thus the same consequences apply. To make someone do
something bad is the same thing as if you were to do it yourself, and we will
not tolerate it.
### Stalking or Following ### Stalking or Following
Stalking or following in any form (offline or online) is unnacceptable. In addition, you may not take pictures or record video of others Stalking or following in any form (offline or online) is unnacceptable. In
without their express permission or when asked to stop. Any individual may also request for you to delete all footage you have of them, even addition, you may not take pictures or record video of others without their
if you took it with their prior consent. express permission or when asked to stop. Any individual may also request for
you to delete all footage you have of them, even if you took it with their prior
consent.
### Publication of Personal Information ### Publication of Personal Information
The publication of personally identifying information (commonly known as "[doxxing](https://en.wikipedia.org/wiki/Doxing)") is directly The publication of personally identifying information (commonly known
prohibited. You may not publish information that someone wants to keep private, unless it is necessary to protect vulnerable people from as "[doxxing](https://en.wikipedia.org/wiki/Doxing)") is directly prohibited.
intentional abuse. Addditionally, you may not deliberately "out" any aspect of a person's identity without their consent, this includes You may not publish information that someone wants to keep private, unless it is
gender, pronouns, sexual identity, etc. necessary to protect vulnerable people from intentional abuse. Addditionally,
you may not deliberately "out" any aspect of a person's identity without their
consent, this includes gender, pronouns, sexual identity, etc.
Unless it pretains to a case of harassment, as outlined here, in which case some personally identifying information may need to be brought Unless it pretains to a case of harassment, as outlined here, in which case some
up in private with the appropriate moderation team to help aid our efforts in keeping the community safe. personally identifying information may need to be brought up in private with the
appropriate moderation team to help aid our efforts in keeping the community
safe.
### Deliberate Misuse of Pronouns<sup>[\[1\]](#1)</sup> or Names ### Deliberate Misuse of Pronouns<sup>[\[1\]](#1)</sup> or Names
As an inclusive community, we must respect everyone. That means respecting the pronouns or names they wish for us to use. Deliberate As an inclusive community, we must respect everyone. That means respecting the
misgendering, misuse of preferred pronouns<sup>[\[1\]](#1)</sup>, or use of 'dead' or rejected names is not to be tolerated. (If someone pronouns or names they wish for us to use. Deliberate misgendering, misuse of
*accidentally* uses the incorrect pronouns, gender, or name, politely ask them to use the correct pronouns/gender/name. But if they are to preferred pronouns<sup>[\[1\]](#1)</sup>, or use of 'dead' or rejected names is
continue using the incorrect pronouns, gender, or name, then you should escalate and report them to us.) not to be tolerated. (If someone
*accidentally* uses the incorrect pronouns, gender, or name, politely ask them
to use the correct pronouns/gender/name. But if they are to continue using the
incorrect pronouns, gender, or name, then you should escalate and report them to
us.)
### Not Stopping After Multiple Requests ### Not Stopping After Multiple Requests
If someone asks you to stop doing something, then you should stop. Continuing to do it may be considered harassment, and can lead you to be If someone asks you to stop doing something, then you should stop. Continuing to
removed from our community. do it may be considered harassment, and can lead you to be removed from our
community.
## Complains We May Ignore ## Complains We May Ignore
Additionally, Terra prioritizes marginalized people's safety over privileged people's comfort. We reserve the right to ignore complaints Additionally, Terra prioritizes marginalized people's safety over privileged
regarding: people's comfort. We reserve the right to ignore complaints regarding:
- Claims of discrimination against non-marginalized or oppressed groups (eg. being 'superphobic', meaning to not support people who are - Claims of discrimination against non-marginalized or oppressed groups (eg.
'superstraight', which is a dog whistle for transphobic groups, or being 'cisphobic' without large amounts of evidence, etc.), or claims being 'superphobic', meaning to not support people who are
of discrimination with no evidence. (Basically, don't report 'cisphobia' to us, because it doesn't exist. But if someone is mocking you or 'superstraight', which is a dog whistle for transphobic groups, or being '
making fun of you for being cis, and it is *really* getting out of hand, then do tell us.) cisphobic' without large amounts of evidence, etc.), or claims of
- Reasonable communication of boundaries, such as "leave me alone," "go away," or "I'm not discussing this with you." (If someone is asking discrimination with no evidence. (Basically, don't report 'cisphobia' to us,
you to stop, that is not reason for you to report them as harassing you.) because it doesn't exist. But if someone is mocking you or making fun of you
- Communicating in a 'tone' you don't find [congenial](https://www.thefreedictionary.com/congenial). (You may not report someone for for being cis, and it is *really* getting out of hand, then do tell us.)
harassment for being 'annoyed with you' or 'talking sternly to you') - Reasonable communication of boundaries, such as "leave me alone," "go away,"
- Criticizing or calling out racist, sexist, discriminatory, or otherwise oppressive behavior or assumptions. (You may not say that someone or "I'm not discussing this with you." (If someone is asking you to stop, that
is harassing you if they are telling you to stop discriminating against someone.) is not reason for you to report them as harassing you.)
- Disagreements that do not qualify as harassment. If you have a simple disagreement with someone, and they have not been discriminating to - Communicating in a 'tone' you don't
anyone, in any form, then we will not take action against them. Two people are allowed to disagree on things without it getting toxic. find [congenial](https://www.thefreedictionary.com/congenial). (You may not
report someone for harassment for being 'annoyed with you' or 'talking sternly
to you')
- Criticizing or calling out racist, sexist, discriminatory, or otherwise
oppressive behavior or assumptions. (You may not say that someone is harassing
you if they are telling you to stop discriminating against someone.)
- Disagreements that do not qualify as harassment. If you have a simple
disagreement with someone, and they have not been discriminating to anyone, in
any form, then we will not take action against them. Two people are allowed to
disagree on things without it getting toxic.
We may also additionally choose to enact punishment for submitting a complaint in bad-faith or without adequate justification, if we deem We may also additionally choose to enact punishment for submitting a complaint
necessary; if you're submitting a complaint just to troll or to annoy people, we may choose to have you banned or removed from the community in bad-faith or without adequate justification, if we deem necessary; if you're
spaces. Don't waste our time. submitting a complaint just to troll or to annoy people, we may choose to have
you banned or removed from the community spaces. Don't waste our time.
In order to protect volunteers from abuse and burnout, we reserve the right to reject any report we believe to have been made in bad faith In order to protect volunteers from abuse and burnout, we reserve the right to
or with misintent. Reports intended to silence legitimate criticism may be deleted without response. reject any report we believe to have been made in bad faith or with misintent.
Reports intended to silence legitimate criticism may be deleted without
response.
## Reporting ## Reporting
Terra has a global moderation team which is currently comprised of the following members: Terra has a global moderation team which is currently comprised of the following
members:
- solonovamax - 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) - github: [@solonovamax](https://github.com/solonovamax)
- email: [solonovamax@12oclockpoint.com](mailto:solonovamax@12oclockpoint.com) -
email: [solonovamax@12oclockpoint.com](mailto:solonovamax@12oclockpoint.com)
- dfsek - 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) - github: [@dfsek](https://github.com/dfsek)
- email: [dfsek@protonmail.com](mailto:dfsek@protonmail.com) - email: [dfsek@protonmail.com](mailto:dfsek@protonmail.com)
- duplex (duplexsystem) - 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) - github: [@duplexsystem](https://github.com/duplexsystem)
- email: [duplexsys@protonmail.com](mailto:duplexsys@protonmail.com) - email: [duplexsys@protonmail.com](mailto:duplexsys@protonmail.com)
\* The preferred method of communication is through discord. Although we will still be responsive on the other platforms, we will be more \* The preferred method of communication is through discord. Although we will
responsive on discord. still be responsive on the other platforms, we will be more responsive on
discord.
These are people you can contact for anything regarding this code of conduct. These are people you can contact for anything regarding this code of conduct.
If you are being harassed by a member of the Terra community, or by someone in a Terra community space, notice that someone else is being If you are being harassed by a member of the Terra community, or by someone in a
harassed, or have any other concerns, please contact a moderator of the platform it occurred on, or someone on the global moderation team. Terra community space, notice that someone else is being harassed, or have any
If the person who is harassing you is on the global moderation team, they will [recuse](https://www.thefreedictionary.com/recuse) themselves other concerns, please contact a moderator of the platform it occurred on, or
from handling your incident. (Meaning: if you are reporting someone on the team, they will not be involved in the discussion.) We will someone on the global moderation team. If the person who is harassing you is on
respond within a reasonable time frame, but generally within about 1 day. the global moderation team, they
will [recuse](https://www.thefreedictionary.com/recuse) themselves from handling
your incident. (Meaning: if you are reporting someone on the team, they will not
be involved in the discussion.) We will respond within a reasonable time frame,
but generally within about 1 day.
This code of conduct applies to Terra community spaces, but if you are being harassed by a member of Terra *outside* our spaces, we still This code of conduct applies to Terra community spaces, but if you are being
want to know about it as we may choose to take action within our community. We will take all good-faith reports seriously and will always harassed by a member of Terra *outside* our spaces, we still want to know about
attempt to handle them appropriately. This includes harassment outside our spaces and harassment that took place at any point in time. The it as we may choose to take action within our community. We will take all
moderation team reserves the right to exclude people from Terra communities based on their past behavior, including behavior outside Terra good-faith reports seriously and will always attempt to handle them
spaces and behavior towards people who are not in Terra. appropriately. This includes harassment outside our spaces and harassment that
took place at any point in time. The moderation team reserves the right to
exclude people from Terra communities based on their past behavior, including
behavior outside Terra spaces and behavior towards people who are not in Terra.
Note: although we only have the ability to moderate official community spaces, if you are being harassed by someone in a non-official Note: although we only have the ability to moderate official community spaces,
community space, and the moderation team of that platform refuses to do anything to help you (or even if they *do* help you), then you if you are being harassed by someone in a non-official community space, and the
should notify us so that we may take appropriate action. moderation team of that platform refuses to do anything to help you (or even if
they *do* help you), then you should notify us so that we may take appropriate
action.
We will respect confidentiality requests for the purpose of protecting victims of abuse. At our discretion, we may publicly name a person We will respect confidentiality requests for the purpose of protecting victims
which we have received harassment complaints about, or privately warn third parties about them, but only if we believe that doing so will of abuse. At our discretion, we may publicly name a person which we have
increase the safety of Terra community members or the general public. We will not name harassment victims or reporters of harassment received harassment complaints about, or privately warn third parties about
(assuming the report was made in good-faith) without their explicit consent; all reports will remain anonymous by default. them, but only if we believe that doing so will increase the safety of Terra
community members or the general public. We will not name harassment victims or
reporters of harassment
(assuming the report was made in good-faith) without their explicit consent; all
reports will remain anonymous by default.
## Consequences of Unacceptable Behavior ## Consequences of Unacceptable Behavior
Participants asked to stop any harassing behavior are expected to comply immediately. Whether or not you comply immediately, you may still Participants asked to stop any harassing behavior are expected to comply
face consequences for you actions, but if the harasser doesn't comply immediately then we may choose to take additional actions to protect immediately. Whether or not you comply immediately, you may still face
the Terra community members or the individual being harassed. consequences for you actions, but if the harasser doesn't comply immediately
then we may choose to take additional actions to protect the Terra community
members or the individual being harassed.
Violation of this code can result in being asked to leave an event or online space, either temporarily or for the duration of the event, or Violation of this code can result in being asked to leave an event or online
being banned from participation in spaces, or future events and activities in perpetuity. If a participant engages in harassing behavior, space, either temporarily or for the duration of the event, or being banned from
the global moderation team may take any action they deem appropriate, up to and including expulsion from all Terra community spaces and participation in spaces, or future events and activities in perpetuity. If a
identification of the participant as a harasser to other Terra community members or the general public. Bad behavior from any community participant engages in harassing behavior, the global moderation team may take
any action they deem appropriate, up to and including expulsion from all Terra
community spaces and identification of the participant as a harasser to other
Terra community members or the general public. Bad behavior from any community
member, including those with decision-making authority, will not be tolerated. member, including those with decision-making authority, will not be tolerated.
In addition, any participants who abuse the reporting process will be considered to be in violation of these guidelines and subject to In addition, any participants who abuse the reporting process will be considered
consequences. False reporting, especially to retaliate or exclude, will not be accepted or tolerated. to be in violation of these guidelines and subject to consequences. False
reporting, especially to retaliate or exclude, will not be accepted or
tolerated.
## Questions ## Questions
if you have further questions for anything not addressed here, you may open an issue on this github repo, or contact a member of the global if you have further questions for anything not addressed here, you may open an
moderation team. issue on this github repo, or contact a member of the global moderation team.
## License and Attribution ## License and Attribution
This set of guidelines is distributed under a 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 from These guidelines have been adapted from
[Mozilla's Community Participation Guidelines](https://www.mozilla.org/en-US/about/governance/policies/participation/), which were adapted [Mozilla's Community Participation Guidelines](https://www.mozilla.org/en-US/about/governance/policies/participation/)
from: , which were adapted from:
- Mozilla's original Community Participation Guidelines - Mozilla's original Community Participation Guidelines
- The [Ubuntu Code of Conduct](https://ubuntu.com/community/code-of-conduct) - 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/) -
- 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 Mozilla's [View Source Conference Code of Conduct](https://viewsourceconf.org/berlin-2016/code-of-conduct/)
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/). - 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 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. the [LGBTQ in Technology Code of Conduct](https://lgbtq.technology/coc.html) and
a few other sources.
## Notes ## Notes
#### \[1\] #### \[1\]
You provide a set of pronouns that everyone is comfortable addressing you with. Although some people are comfortable You provide a set of pronouns that everyone is comfortable addressing you with.
using [neopronouns](https://www.mypronouns.org/neopronouns), not everyone is. Therefore, if you use neopronouns, you should have at *least* Although some people are comfortable
one set of more common pronouns (One of he/him, she/her, or they/them; it doesn't matter which one. Anyone who doesn't respect your basic using [neopronouns](https://www.mypronouns.org/neopronouns), not everyone is.
pronouns will be removed from the community.) that people may use, should they so choose, as some people are not comfortable Therefore, if you use neopronouns, you should have at *least*
using [neopronouns](https://www.mypronouns.org/neopronouns). But if someone refuses to use your more common pronouns, you should report them one set of more common pronouns (One of he/him, she/her, or they/them; it
to us. Additionally, you may not ask people to use unreasonable pronouns, such as 'acab/acabself', 'that/bitch', 'ur/mom', or doesn't matter which one. Anyone who doesn't respect your basic pronouns will be
'dream/dreamself' (pronouns related to real people, eg. the minecraft youtuber 'dreamwastaken'). Doing so will be considered mockery of removed from the community.) that people may use, should they so choose, as some
individuals who use non-standard pronouns and is very disrespectful. 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
'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.

View File

@ -1,17 +1,22 @@
# Contributing to Terra # Contributing to Terra
First off, thank you for considering contributing to Terra. It's people like you that make Terra such a great tool. First off, thank you for considering contributing to Terra. It's people like you
that make Terra such a great tool.
Following these guidelines helps to effectively use the time of the developers managing and developing this open source project, making it Following these guidelines helps to effectively use the time of the developers
more enjoyable for all of us. managing and developing this open source project, making it more enjoyable for
all of us.
Terra is an open source project and we love to receive contributions from our community, you! There are many ways to contribute, from Terra is an open source project and we love to receive contributions from our
writing tutorials or blog posts, improving the documentation, submitting bug reports and feature requests or writing code which can be community, you! There are many ways to contribute, from writing tutorials or
incorporated into Terra. blog posts, improving the documentation, submitting bug reports and feature
requests or writing code which can be incorporated into Terra.
The following is a set of guidelines for contributing to Terra and its packages, which are hosted in The following is a set of guidelines for contributing to Terra and its packages,
the [PolyhedralDev Organization](https://github.com/PolyhedralDev) on GitHub. These are mostly guidelines, not rules. Use your best which are hosted in
judgment, and feel free to propose changes to this document in a pull request. the [PolyhedralDev Organization](https://github.com/PolyhedralDev) on GitHub.
These are mostly guidelines, not rules. Use your best judgment, and feel free to
propose changes to this document in a pull request.
#### Table Of Contents #### Table Of Contents
@ -51,8 +56,10 @@ judgment, and feel free to propose changes to this document in a pull request.
## Code of Conduct ## Code of Conduct
This project and everyone participating in it is governed by the [Terra of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected This project and everyone participating in it is governed by
to uphold this code. Please report unacceptable behavior to [Terra global moderation team](CODE_OF_CONDUCT.md#Reporting). the [Terra of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected
to uphold this code. Please report unacceptable behavior
to [Terra global moderation team](CODE_OF_CONDUCT.md#Reporting).
## I don't want to read this whole thing I just have a question!!! ## I don't want to read this whole thing I just have a question!!!
@ -66,160 +73,219 @@ We have an official discord server where you can request help from various users
### Your First Contribution ### Your First Contribution
Unsure where to begin contributing to Terra? You can start by looking through "beginner" and "help wanted" issues: Unsure where to begin contributing to Terra? You can start by looking through "
beginner" and "help wanted" issues:
- [Beginner issues](https://github.com/PolyhedralDev/Terra/labels/Note%3A%20Good%20First%20Issue) - issues which should be friendly to - [Beginner issues](https://github.com/PolyhedralDev/Terra/labels/Note%3A%20Good%20First%20Issue)
anyone new to terra. - issues which should be friendly to anyone new to terra.
- [Help wanted issues](https://github.com/PolyhedralDev/Terra/labels/Note%3A%20Help%20Wanted) - issues which should be a bit more involved - [Help wanted issues](https://github.com/PolyhedralDev/Terra/labels/Note%3A%20Help%20Wanted)
than "beginner" issues. - issues which should be a bit more involved than "beginner" issues.
New to github? Working on your first Pull Request? Check New to github? Working on your first Pull Request? Check
out [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github) out [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github)
to get you up on your feet. to get you up on your feet.
At this point, you're ready to make your changes! Feel free to ask for help; everyone is a beginner at first! At this point, you're ready to make your changes! Feel free to ask for help;
everyone is a beginner at first!
If a maintainer asks you to "rebase" your PR, they're saying that a lot of code has changed, and that you need to update your branch so it's If a maintainer asks you to "rebase" your PR, they're saying that a lot of code
easier to merge. has changed, and that you need to update your branch so it's easier to merge.
### Reporting Bugs ### Reporting Bugs
This section guides you through submitting a bug report for Terra. Following these guidelines helps maintainers and the community understand This section guides you through submitting a bug report for Terra. Following
your report, and spend their time fixing the issue instead of understanding what you mean. these guidelines helps maintainers and the community understand your report, and
spend their time fixing the issue instead of understanding what you mean.
Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create Before creating bug reports, please
one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). check [this list](#before-submitting-a-bug-report) as you might find out that
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 #### Before Submitting A Bug Report
- Join the [discord server](https://discord.dfsek.com) to help resolve simple issues. - Join the [discord server](https://discord.dfsek.com) to help resolve simple
- You must be on the LATEST version of Terra to receive any support. There is no support for older versions of Terra. issues.
- Make sure that this is not a *specific* compatibility issue with another terrain generation mod. Do not request *specific* compatibility - You must be on the LATEST version of Terra to receive any support. There is no
with mods or plugins (e.g. "Compatibility with TechCraft v7"). That should be implemented in an addon, **not** in the main project. support for older versions of Terra.
*General* compatibility (e.g. "Ability to pull Vanilla/Modded features from parent biomes") will be considered in the main project. - Make sure that this is not a *specific* compatibility issue with another
- Search for any [already existing issues](https://github.com/PolyhedralDev/Terra/issues?q=is%3Aissue+) open with your problem. If you open terrain generation mod. Do not request *specific* compatibility with mods or
a duplicate, it will be closed as such. plugins (e.g. "Compatibility with TechCraft v7"). That should be implemented
- 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 in an addon, **not** in the main project.
the issue without Terra installed. *General* compatibility (e.g. "Ability to pull Vanilla/Modded features from
- Double check that this is not an issue with a specific Terra *pack* or Terra *addon*, and instead applies to all of Terra. parent biomes") will be considered in the main project.
- Include a copy of the latest.log file. Putting *just* the exception is not enough. We need to be able to check that there wasn't anything - Search for
else before that caused it. any [already existing issues](https://github.com/PolyhedralDev/Terra/issues?q=is%3Aissue+)
- Be sure to fill out all the required information and give descriptions of everything. 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.
- Double check that this is not an issue with a specific Terra *pack* or Terra *
addon*, and instead applies to all of Terra.
- Include a copy of the latest.log file. Putting *just* the exception is not
enough. We need to be able to check that there wasn't anything else before
that caused it.
- Be sure to fill out all the required information and give descriptions of
everything.
#### How Do I Submit A (Good) Bug Report? #### How Do I Submit A (Good) Bug Report?
Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/) Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/)
. [Create an issue](https://github.com/PolyhedralDev/Terra/issues/new) and provide the prerequisite information by filling in the Bug Report . [Create an issue](https://github.com/PolyhedralDev/Terra/issues/new) and
template. provide the prerequisite information by filling in the Bug Report template.
Explain the problem and include additional details to help maintainers reproduce the problem: Explain the problem and include additional details to help maintainers reproduce
the problem:
- **Use a clear and descriptive title** for the issue to identify the problem. - **Use a clear and descriptive title** for the issue to identify the problem.
- **Describe the exact steps which reproduce the problem** in as many details as possible. When listing steps, **don't just say what you - **Describe the exact steps which reproduce the problem** in as many details as
did, but explain how you did it**. possible. When listing steps, **don't just say what you did, but explain how
you did it**.
- **Provide specific examples to demonstrate the steps**. - **Provide specific examples to demonstrate the steps**.
- **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. - **Describe the behavior you observed after following the steps** and point out
what exactly is the problem with that behavior.
- **Explain which behavior you expected to see instead and why.** - **Explain which behavior you expected to see instead and why.**
- **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more - **If the problem wasn't triggered by a specific action**, describe what you
information using the guidelines below. were doing before the problem happened and share more information using the
guidelines below.
Include details about your configuration and environment: Include details about your configuration and environment:
- **Which version of Terra are you using?** You can get the exact version by running `/te version`. - **Which version of Terra are you using?** You can get the exact version by
- **What's the name and version of the platform you're using**? (eg. Spigot, Fabric, Paper, etc.) running `/te version`.
- **What's the name and version of the platform you're using**? (eg. Spigot,
Fabric, Paper, etc.)
- **Which external plugins or mods do you have installed?** - **Which external plugins or mods do you have installed?**
- **Which Terra packs do you have installed?** You can get that list by running `/te packs`. - **Which Terra packs do you have installed?** You can get that list by
- **Which Terra addons do you have installed?** You can get that list by running `/te addons`. running `/te packs`.
- **Which Terra addons do you have installed?** You can get that list by
running `/te addons`.
### Suggesting Enhancements ### Suggesting Enhancements
This section guides you through submitting an enhancement suggestion for Terra, including completely new features and minor improvements to This section guides you through submitting an enhancement suggestion for Terra,
existing functionality. Following these guidelines helps maintainers and the community understand your suggestion and find related including completely new features and minor improvements to existing
suggestions. functionality. Following these guidelines helps maintainers and the community
understand your suggestion and find related suggestions.
Before creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that Before creating enhancement suggestions, please
you don't need to create one. When you are creating an enhancement suggestion, check [this list](#before-submitting-an-enhancement-suggestion) as you might
please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). find out that you don't need to create one. When you are creating an enhancement
suggestion,
please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion)
.
#### Before Submitting An Enhancement Suggestion #### Before Submitting An Enhancement Suggestion
- You must be on the **LATEST** version of Terra to make sure your feature hasn't been added yet. - You must be on the **LATEST** version of Terra to make sure your feature
- Search for any [already existing issues](https://github.com/PolyhedralDev/Terra/issues?q=is%3Aissue+) (Including closed!) with your hasn't been added yet.
problem. If you open a duplicate, it will be closed as such. - Search for
any [already existing issues](https://github.com/PolyhedralDev/Terra/issues?q=is%3Aissue+) (
Including closed!) with your problem. If you open a duplicate, it will be
closed as such.
- Verify that this is actually within the scope of Terra. - Verify that this is actually within the scope of Terra.
- Be sure that this is not a feature request that should be made for a specific Terra *pack*, and instead applies to all of Terra. - Be sure that this is not a feature request that should be made for a specific
- Be sure that this is not something that should be implemented as a Terra addon, and instead applies to all of Terra. Terra *pack*, and instead applies to all of Terra.
- Make sure that you attach a copy of the latest.log file, if there are any exceptions thrown in the console. Putting *just* the exception - Be sure that this is not something that should be implemented as a Terra
**is not enough**. We need to be able to check that there wasn't anything else before that caused it. addon, and instead applies to all of Terra.
- Make sure that you attach a copy of the latest.log file, if there are any
exceptions thrown in the console. Putting *just* the exception
**is not enough**. We need to be able to check that there wasn't anything else
before that caused it.
#### How Do I Submit A (Good) Enhancement Suggestion? #### How Do I Submit A (Good) Enhancement Suggestion?
Enhancement suggestions are tracked as [GitHub issues](https://guides.github.com/features/issues/). Create an issue on our main repository Enhancement suggestions are tracked
and provide the following information: as [GitHub issues](https://guides.github.com/features/issues/). Create an issue
on our main repository and provide the following information:
- **Use a clear and descriptive title** for the issue to identify the suggestion. - **Use a clear and descriptive title** for the issue to identify the
- **Provide a step-by-step description of the suggested enhancement** in as many details as possible. suggestion.
- **Provide a step-by-step description of the suggested enhancement** in as many
details as possible.
- **Provide specific examples to demonstrate the steps**. - **Provide specific examples to demonstrate the steps**.
- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. - **Describe the current behavior** and **explain which behavior you expected to
- **Explain why this enhancement would be useful** to most Terra users and isn't something that can or should be implemented as an addon. see instead** and why.
- **Explain why this enhancement would be useful** to most Terra users and isn't
something that can or should be implemented as an addon.
### Pull Requests ### Pull Requests
This section guides you through submitting a pull request for Terra. This section guides you through submitting a pull request for Terra.
While the prerequisites above must be satisfied prior to having your pull request reviewed, the reviewer(s) may ask you to complete While the prerequisites above must be satisfied prior to having your pull
additional design work, tests, or other changes before your pull request can be ultimately accepted. request reviewed, the reviewer(s) may ask you to complete additional design
work, tests, or other changes before your pull request can be ultimately
accepted.
#### Before Submitting A Pull Request #### Before Submitting A Pull Request
- You must be on the **LATEST** version of Terra to make sure your feature hasn't been added yet. - You must be on the **LATEST** version of Terra to make sure your feature
- Search for any [already existing issues](https://github.com/PolyhedralDev/Terra/issues?q=is%3Aissue+) (Including closed!) with your hasn't been added yet.
problem. If you open a duplicate, it will be closed as such. - Search for
any [already existing issues](https://github.com/PolyhedralDev/Terra/issues?q=is%3Aissue+) (
Including closed!) with your problem. If you open a duplicate, it will be
closed as such.
- Verify that this is actually within the scope of Terra. - Verify that this is actually within the scope of Terra.
- Be sure that this is not a feature request that should be made for a specific Terra *pack*, and instead applies to all of Terra. - Be sure that this is not a feature request that should be made for a specific
- Be sure that this is not something that should be implemented as a Terra addon, and instead applies to all of Terra. Terra *pack*, and instead applies to all of Terra.
- Make sure that you attach a copy of the latest.log file, if there are any exceptions thrown in the console. Putting *just* the - Be sure that this is not something that should be implemented as a Terra
exception **is not enough**. We need to be able to check that there wasn't anything else before that caused it. addon, and instead applies to all of Terra.
- Make sure that you attach a copy of the latest.log file, if there are any
exceptions thrown in the console. Putting *just* the exception **is not
enough**. We need to be able to check that there wasn't anything else before
that caused it.
#### How Do I Submit A (Good) Pull Request? #### How Do I Submit A (Good) Pull Request?
Pull Requests are tracked as [GitHub Pull Requests](https://guides.github.com/activities/forking/#making-a-pull-request). Create a pr on our Pull Requests are tracked
main repository and provide the following information: as [GitHub Pull Requests](https://guides.github.com/activities/forking/#making-a-pull-request)
. Create a pr on our main repository and provide the following information:
- **Use a clear and descriptive title** to identify the pull request. - **Use a clear and descriptive title** to identify the pull request.
- **State what this pull request adds/fixes**. - **State what this pull request adds/fixes**.
- **Be sure that you are the owner of the code you contributed** or that it can be licensed under the GPLv3. - **Be sure that you are the owner of the code you contributed** or that it can
- **Provide a description goals and non-goals of the pull request** in as many details as possible. be licensed under the GPLv3.
- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. - **Provide a description goals and non-goals of the pull request** in as many
- **Explain why this enhancement would be useful** to most Terra users and isn't something that can or should be implemented as an addon. details as possible.
- **Describe the current behavior** and **explain which behavior you expected to
see instead** and why.
- **Explain why this enhancement would be useful** to most Terra users and isn't
something that can or should be implemented as an addon.
## Styleguides ## Styleguides
### Git Commits ### Git Commits
Following this is not mandatory, but rather a set of guidelines. As long as your commit messages aren't absolutely awful, it's probably Following this is not mandatory, but rather a set of guidelines. As long as your
fine. But it would be nice if you followed them. commit messages aren't absolutely awful, it's probably fine. But it would be
nice if you followed them.
#### Committing #### Committing
When you commit code, try to avoid committing large amounts of code in a single go. Splitting up code into smaller commits is much nicer and When you commit code, try to avoid committing large amounts of code in a single
makes it easier to trace a feature to a single commit. go. Splitting up code into smaller commits is much nicer and makes it easier to
trace a feature to a single commit.
Try to stick to one feature/fix/etc. per commit. A good rule of thumb is if you need to use the word "and" in the subject line, then it Try to stick to one feature/fix/etc. per commit. A good rule of thumb is if you
should probably™ be two commits. need to use the word "and" in the subject line, then it should probably™ be two
commits.
#### Git Commit Messages #### Git Commit Messages
- Subject line must fit the following format: `<type>: <short summary>`. Type must be one of the following: - Subject line must fit the following format: `<type>: <short summary>`. Type
must be one of the following:
- Build: Changes that affect the build system or external dependencies. - Build: Changes that affect the build system or external dependencies.
- Docs: Documentation only changes. - Docs: Documentation only changes.
- Feat: A new feature. - Feat: A new feature.
- Fix: A bug fix. - Fix: A bug fix.
- Perf: Performance improvements. - Perf: Performance improvements.
- Refactor: Refactoring sections of the codebase. - Refactor: Refactoring sections of the codebase.
- Repo: Changes to the repository structure that do not affect code. (Eg. modification of the `README.md` file, etc.) - Repo: Changes to the repository structure that do not affect code. (Eg.
modification of the `README.md` file, etc.)
- Revert: Revert a previous commit. - Revert: Revert a previous commit.
- Style: Code style updates. - Style: Code style updates.
- Test: Anything related to testing. - Test: Anything related to testing.
@ -266,7 +332,8 @@ should probably™ be two commits.
### Code Styleguide ### Code Styleguide
Use an IDE with support for `.editorconfig` files. There is an included editorconfig file in the base of the project so that your IDE should Use an IDE with support for `.editorconfig` files. There is an included
editorconfig file in the base of the project so that your IDE should
automatically use the correct code style settings. automatically use the correct code style settings.
### Documentation Styleguide ### Documentation Styleguide
@ -279,41 +346,55 @@ TODO
#### General Compatibility #### General Compatibility
General compatibility (example: injection of Vanilla structures/features/carvers into packs) is acceptable in the main project. General compatibility (example: injection of Vanilla structures/features/carvers
into packs) is acceptable in the main project.
- General compatibility features should be *disabled by default*. Having things auto-injected causes unpredictable behaviour that is - General compatibility features should be *disabled by default*. Having things
annoying to diagnose. General-compatibility options should have config values attached which are disabled by default. auto-injected causes unpredictable behaviour that is annoying to diagnose.
- These config options should also be *simple to use*. Think of the people who will be using these compatibility options. They want to flick General-compatibility options should have config values attached which are
a switch and have things be compatible. That means that a majority of compatibility options should stay in `pack.yml`, to make it simple disabled by default.
to go into a pack and turn on specific compatibilities. This does *not* mean that more advanced compatibility options are off the table, - These config options should also be *simple to use*. Think of the people who
for example, look at Feature compatibility, where features can either be automatically injected, *or* configured individually per Terra will be using these compatibility options. They want to flick a switch and
biome, depending on how much control the user wants. have things be compatible. That means that a majority of compatibility options
should stay in `pack.yml`, to make it simple to go into a pack and turn on
specific compatibilities. This does *not* mean that more advanced
compatibility options are off the table, for example, look at Feature
compatibility, where features can either be automatically injected, *or*
configured individually per Terra biome, depending on how much control the
user wants.
#### Specific Compatibility #### Specific Compatibility
Specific compatibility should *not* be put in the main project. (Example: Adding the ability to generate TechCraft v7's doo-dads with a Specific compatibility should *not* be put in the main project. (Example: Adding
TerraScript function) the ability to generate TechCraft v7's doo-dads with a TerraScript function)
Having specific compatibilities leads to tons of extra dependencies to keep track of, as well as adding lots of additional stuff to Having specific compatibilities leads to tons of extra dependencies to keep
maintain. It quickly becomes a mess. Especially when most users will never need to use this feature. track of, as well as adding lots of additional stuff to maintain. It quickly
becomes a mess. Especially when most users will never need to use this feature.
We have designed an addon API for exactly this purpose. **Specific compatibilities are welcome and encouraged, in the form of addons.** We have designed an addon API for exactly this purpose. **Specific
compatibilities are welcome and encouraged, in the form of addons.**
### Platform-Agnostic Design ### Platform-Agnostic Design
Terra must, at all times, remain platform agnostic. This means it must be able to run on theoretically any voxel based platform. Including Terra must, at all times, remain platform agnostic. This means it must be able
non-minecraft games like Terasology. to run on theoretically any voxel based platform. Including non-minecraft games
like Terasology.
When adding a new feature to `common`, make no assumptions about what platform it'll be running on. When adding a new feature to `common`, make no assumptions about what platform
it'll be running on.
Examples: Examples:
- Don't assume the world height is 256. - Don't assume the world height is 256.
- Don't assume that a specific block, item, or entity exists. (Eg. don't assume there exists a block called `minecraft:grass_block`) - Don't assume that a specific block, item, or entity exists. (Eg. don't assume
there exists a block called `minecraft:grass_block`)
### Data-Driven ### Data-Driven
When adding a new feature, make it abstract. Don't make assumptions about "specific use cases." If you can only think of a few use cases, When adding a new feature, make it abstract. Don't make assumptions about "
your idea should probably be generalized. specific use cases." If you can only think of a few use cases, your idea should
probably be generalized.
You must use configs effectively. Make configs that are *powerful* but also *make sense* and are \[easy\] to use. You must use configs effectively. Make configs that are *powerful* but also *
make sense* and are \[easy\] to use.

View File

@ -1,19 +1,23 @@
# Terra # Terra
Terra is an incredibly powerful free & open-source data-driven, platform-agnostic world generator. It allows you to create a world exactly Terra is an incredibly powerful free & open-source data-driven,
to your specifications, with no knowledge of Java required. platform-agnostic world generator. It allows you to create a world exactly to
your specifications, with no knowledge of Java required.
## Downloads: ## Downloads:
* Paper+ servers (Paper, Tuinity, Purpur, etc): [SpigotMC](https://www.spigotmc.org/resources/85151/) * Paper+ servers (Paper, Tuinity, Purpur,
* Fabric: [Modrinth](https://modrinth.com/mod/terra) / [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator) etc): [SpigotMC](https://www.spigotmc.org/resources/85151/)
* Forge **(ALPHA - NOT PRODUCTION-READY)**: [Modrinth](https://modrinth.com/mod/terra) * Fabric: [Modrinth](https://modrinth.com/mod/terra)
/ [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator)
* Forge **(ALPHA - NOT
PRODUCTION-READY)**: [Modrinth](https://modrinth.com/mod/terra)
/ [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator) / [CurseForge](https://www.curseforge.com/minecraft/mc-mods/terra-world-generator)
## Building and Running Terra ## Building and Running Terra
To build, simply run `./gradlew build` (`gradlew.bat build` on Windows). This will build all platforms, and produce JARs To build, simply run `./gradlew build` (`gradlew.bat build` on Windows). This
in `platforms/<platform>/build/libs` will build all platforms, and produce JARs in `platforms/<platform>/build/libs`
### Production JARs: ### Production JARs:
@ -32,10 +36,14 @@ JARs are produced in `platforms/<platform>/build/libs`.
To run Minecraft with Terra in the IDE (for testing) use the following tasks: To run Minecraft with Terra in the IDE (for testing) use the following tasks:
* Bukkit * Bukkit
* `installPaper` - Install a [Paper](https://github.com/PaperMC/Paper) test server. (Only needs to be run once). * `installPaper` - Install a [Paper](https://github.com/PaperMC/Paper) test
* `installPurpur` - Install a [Purpur](https://github.com/pl3xgaming/Purpur) test server. (Only needs to be run once). server. (Only needs to be run once).
* `runPaper` - Run the Paper test server with Terra (`installPaper` must have been run previously). * `installPurpur` - Install a [Purpur](https://github.com/pl3xgaming/Purpur)
* `runPurpur` - Run the Purpur test server with Terra (`installPurpur` must have been run previously). 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 * Fabric
* `runClient` - Run a Minecraft Fabric client with Terra installed. * `runClient` - Run a Minecraft Fabric client with Terra installed.
* `runServer` - Run a Minecraft Fabric server with Terra installed. * `runServer` - Run a Minecraft Fabric server with Terra installed.
@ -45,9 +53,12 @@ To run Minecraft with Terra in the IDE (for testing) use the following tasks:
## Contributing ## Contributing
Contributions are welcome! If you want to see a feature in Terra, please, open an issue, or implement it yourself and submit a PR! Contributions are welcome! If you want to see a feature in Terra, please, open
Join the discord [here](https://discord.gg/PXUEbbF) if you would like to talk more about the project! an issue, or implement it yourself and submit a PR!
Join the discord [here](https://discord.gg/PXUEbbF) if you would like to talk
more about the project!
## Beta ## Beta
Terra is still in beta! While it is stable, it is not feature-complete. There is a lot to be added! Terra is still in beta! While it is stable, it is not feature-complete. There is
a lot to be added!

View File

@ -1,28 +1,32 @@
import com.dfsek.terra.* import com.dfsek.terra.configureCompilation
import com.dfsek.terra.configureDependencies
import com.dfsek.terra.configureDistribution
import com.dfsek.terra.configurePublishing
import com.dfsek.terra.getGitHash
val versionObj = Version("6", "0", "0", true) val versionObj = Version("6", "0", "0", true)
allprojects { allprojects {
version = versionObj version = versionObj
group = "com.dfsek.terra" group = "com.dfsek.terra"
configureDependencies() configureDependencies()
configureCompilation() configureCompilation()
configurePublishing() configurePublishing()
tasks.withType<JavaCompile>().configureEach { tasks.withType<JavaCompile>().configureEach {
options.isFork = true options.isFork = true
options.isIncremental = true options.isIncremental = true
} }
tasks.withType<Test>().configureEach { tasks.withType<Test>().configureEach {
useJUnitPlatform() useJUnitPlatform()
maxHeapSize = "2G" maxHeapSize = "2G"
ignoreFailures = false ignoreFailures = false
failFast = true failFast = true
maxParallelForks = (Runtime.getRuntime().availableProcessors() - 1).takeIf { it > 0 } ?: 1 maxParallelForks = (Runtime.getRuntime().availableProcessors() - 1).takeIf { it > 0 } ?: 1
reports.html.required.set(false) reports.html.required.set(false)
reports.junitXml.required.set(false) reports.junitXml.required.set(false)
} }
@ -39,7 +43,7 @@ afterEvaluate {
*/ */
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
class Version(val major: String, val minor: String, val revision: String, val preRelease: Boolean = false) { class Version(val major: String, val minor: String, val revision: String, val preRelease: Boolean = false) {
override fun toString(): String { override fun toString(): String {
return if (!preRelease) return if (!preRelease)
"$major.$minor.$revision" "$major.$minor.$revision"

View File

@ -1,10 +1,10 @@
package com.dfsek.terra package com.dfsek.terra
import java.io.File
import java.util.function.Predicate
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.jvm.tasks.Jar import org.gradle.jvm.tasks.Jar
import java.io.File
import java.util.function.Predicate
import kotlin.streams.asStream import kotlin.streams.asStream
@ -22,13 +22,13 @@ fun Project.addonDir(dir: File, task: Task) {
} }
project(":common:addons").subprojects.forEach { addonProject -> project(":common:addons").subprojects.forEach { addonProject ->
val jar = (addonProject.tasks.named("jar").get() as Jar) val jar = (addonProject.tasks.named("jar").get() as Jar)
val target = File(dir, jar.archiveFileName.get()) val target = File(dir, jar.archiveFileName.get())
val base = "${jar.archiveBaseName.get()}-${project.version}" val base = "${jar.archiveBaseName.get()}-${project.version}"
println("Copying addon ${jar.archiveFileName.get()} to ${target.absolutePath}. Base name: $base") println("Copying addon ${jar.archiveFileName.get()} to ${target.absolutePath}. Base name: $base")
jar.archiveFile.orNull?.asFile?.copyTo(target) jar.archiveFile.orNull?.asFile?.copyTo(target)
} }
} }

View File

@ -1,7 +1,7 @@
package com.dfsek.terra package com.dfsek.terra
import org.gradle.api.Project
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import org.gradle.api.Project
fun Project.getGitHash(): String { fun Project.getGitHash(): String {
val stdout = ByteArrayOutputStream() val stdout = ByteArrayOutputStream()

View File

@ -6,7 +6,12 @@ import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.bundling.Jar import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.compile.JavaCompile import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.kotlin.dsl.* import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.filter
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.language.jvm.tasks.ProcessResources
fun Project.configureCompilation() { fun Project.configureCompilation() {
@ -14,46 +19,46 @@ fun Project.configureCompilation() {
apply(plugin = "java") apply(plugin = "java")
apply(plugin = "java-library") apply(plugin = "java-library")
apply(plugin = "idea") apply(plugin = "idea")
configure<JavaPluginExtension> { configure<JavaPluginExtension> {
sourceCompatibility = JavaVersion.VERSION_16 sourceCompatibility = JavaVersion.VERSION_16
targetCompatibility = JavaVersion.VERSION_16 targetCompatibility = JavaVersion.VERSION_16
} }
tasks.withType<JavaCompile> { tasks.withType<JavaCompile> {
options.encoding = "UTF-8" options.encoding = "UTF-8"
doFirst { doFirst {
options.compilerArgs.add("-Xlint:all") options.compilerArgs.add("-Xlint:all")
} }
} }
tasks.withType<ProcessResources> { tasks.withType<ProcessResources> {
include("**/*.*") include("**/*.*")
filter<org.apache.tools.ant.filters.ReplaceTokens>( filter<org.apache.tools.ant.filters.ReplaceTokens>(
"tokens" to mapOf( "tokens" to mapOf(
"VERSION" to project.version.toString(), "VERSION" to project.version.toString(),
"DESCRIPTION" to project.properties["terra.description"], "DESCRIPTION" to project.properties["terra.description"],
"WIKI" to project.properties["terra.wiki"], "WIKI" to project.properties["terra.wiki"],
"SOURCE" to project.properties["terra.source"], "SOURCE" to project.properties["terra.source"],
"ISSUES" to project.properties["terra.issues"], "ISSUES" to project.properties["terra.issues"],
"LICENSE" to project.properties["terra.license"] "LICENSE" to project.properties["terra.license"]
) )
) )
} }
tasks.withType<Javadoc> { tasks.withType<Javadoc> {
options.encoding = "UTF-8" options.encoding = "UTF-8"
} }
tasks.withType<Jar> { tasks.withType<Jar> {
archiveBaseName.set("Terra-${archiveBaseName.get()}") archiveBaseName.set("Terra-${archiveBaseName.get()}")
from("../LICENSE", "../../LICENSE") from("../LICENSE", "../../LICENSE")
} }
tasks.register<Jar>("sourcesJar") { tasks.register<Jar>("sourcesJar") {
archiveClassifier.set("sources") archiveClassifier.set("sources")
} }
tasks.register<Jar>("javadocJar") { tasks.register<Jar>("javadocJar") {
dependsOn("javadoc") dependsOn("javadoc")
archiveClassifier.set("javadoc") archiveClassifier.set("javadoc")

View File

@ -1,12 +1,16 @@
package com.dfsek.terra package com.dfsek.terra
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.kotlin.dsl.* import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.invoke
import org.gradle.kotlin.dsl.project
import org.gradle.kotlin.dsl.repositories
fun Project.configureDependencies() { fun Project.configureDependencies() {
apply(plugin = "java") apply(plugin = "java")
apply(plugin = "java-library") apply(plugin = "java-library")
configurations { configurations {
val shaded = create("shaded") val shaded = create("shaded")
val shadedApi = create("shadedApi") val shadedApi = create("shadedApi")
@ -16,7 +20,7 @@ fun Project.configureDependencies() {
shaded.extendsFrom(shadedImplementation) shaded.extendsFrom(shadedImplementation)
getByName("implementation").extendsFrom(shadedImplementation) getByName("implementation").extendsFrom(shadedImplementation)
} }
repositories { repositories {
maven { url = uri("https://maven.enginehub.org/repo/") } maven { url = uri("https://maven.enginehub.org/repo/") }
maven { url = uri("https://repo.codemc.org/repository/maven-public") } maven { url = uri("https://repo.codemc.org/repository/maven-public") }
@ -25,16 +29,16 @@ fun Project.configureDependencies() {
gradlePluginPortal() gradlePluginPortal()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.7.0") "testImplementation"("org.junit.jupiter:junit-jupiter-api:5.7.0")
"testImplementation"("org.junit.jupiter:junit-jupiter-engine:5.7.0") "testImplementation"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
"compileOnly"("org.jetbrains:annotations:20.1.0") "compileOnly"("org.jetbrains:annotations:20.1.0")
"compileOnly"("com.google.guava:guava:30.0-jre") "compileOnly"("com.google.guava:guava:30.0-jre")
"testImplementation"("com.google.guava:guava:30.0-jre") "testImplementation"("com.google.guava:guava:30.0-jre")
} }
if (project(":common:addons").subprojects.contains(this)) { // If this is an addon project, depend on the API. if (project(":common:addons").subprojects.contains(this)) { // If this is an addon project, depend on the API.
dependencies { dependencies {
"compileOnly"(project(":common:api")) "compileOnly"(project(":common:api"))

View File

@ -1,6 +1,13 @@
package com.dfsek.terra package com.dfsek.terra
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.FileWriter
import java.net.URL
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.plugins.BasePluginExtension import org.gradle.api.plugins.BasePluginExtension
@ -11,29 +18,22 @@ import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.named import org.gradle.kotlin.dsl.named
import org.yaml.snakeyaml.DumperOptions import org.yaml.snakeyaml.DumperOptions
import org.yaml.snakeyaml.Yaml import org.yaml.snakeyaml.Yaml
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.FileWriter
import java.net.URL
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
fun Project.configureDistribution() { fun Project.configureDistribution() {
apply(plugin = "com.github.johnrengelman.shadow") apply(plugin = "com.github.johnrengelman.shadow")
val downloadDefaultPacks = tasks.create("downloadDefaultPacks") { val downloadDefaultPacks = tasks.create("downloadDefaultPacks") {
group = "terra" group = "terra"
doFirst { doFirst {
file("${buildDir}/resources/main/packs/").deleteRecursively() file("${buildDir}/resources/main/packs/").deleteRecursively()
val defaultPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/default.zip") val defaultPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/default.zip")
downloadPack(defaultPackUrl, project) downloadPack(defaultPackUrl, project)
val netherPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/nether.zip") val netherPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/nether.zip")
downloadPack(netherPackUrl, project) downloadPack(netherPackUrl, project)
} }
} }
val installAddons = tasks.create("installAddons") { val installAddons = tasks.create("installAddons") {
group = "terra" group = "terra"
project(":common:addons").subprojects.forEach { project(":common:addons").subprojects.forEach {
@ -41,7 +41,7 @@ fun Project.configureDistribution() {
dependsOn(it.tasks.getByName("build")) // Depend on addon JARs dependsOn(it.tasks.getByName("build")) // Depend on addon JARs
} }
} }
doFirst { doFirst {
// The addons are copied into a JAR because of a ShadowJar bug // The addons are copied into a JAR because of a ShadowJar bug
// which expands *all* JARs, even resource ones, into the fat JAR. // which expands *all* JARs, even resource ones, into the fat JAR.
@ -52,13 +52,13 @@ fun Project.configureDistribution() {
// https://github.com/johnrengelman/shadow/issues/111 // https://github.com/johnrengelman/shadow/issues/111
val dest = File(buildDir, "/resources/main/addons.jar") val dest = File(buildDir, "/resources/main/addons.jar")
dest.parentFile.mkdirs() dest.parentFile.mkdirs()
val zip = ZipOutputStream(FileOutputStream(dest)) val zip = ZipOutputStream(FileOutputStream(dest))
project(":common:addons").subprojects.forEach { addonProject -> project(":common:addons").subprojects.forEach { addonProject ->
val jar = (addonProject.tasks.named("jar").get() as Jar) val jar = (addonProject.tasks.named("jar").get() as Jar)
println("Packaging addon ${jar.archiveFileName.get()} to ${dest.absolutePath}.") println("Packaging addon ${jar.archiveFileName.get()} to ${dest.absolutePath}.")
val entry = ZipEntry("addons/${jar.archiveFileName.get()}") val entry = ZipEntry("addons/${jar.archiveFileName.get()}")
zip.putNextEntry(entry) zip.putNextEntry(entry)
FileInputStream(jar.archiveFile.get().asFile).copyTo(zip) FileInputStream(jar.archiveFile.get().asFile).copyTo(zip)
@ -67,7 +67,7 @@ fun Project.configureDistribution() {
zip.close() zip.close()
} }
} }
val generateResourceManifest = tasks.create("generateResourceManifest") { val generateResourceManifest = tasks.create("generateResourceManifest") {
group = "terra" group = "terra"
dependsOn(downloadDefaultPacks) dependsOn(downloadDefaultPacks)
@ -75,24 +75,24 @@ fun Project.configureDistribution() {
doFirst { doFirst {
val resources = HashMap<String, MutableList<String>>() val resources = HashMap<String, MutableList<String>>()
val packsDir = File("${project.buildDir}/resources/main/packs/") val packsDir = File("${project.buildDir}/resources/main/packs/")
packsDir.walkTopDown().forEach { packsDir.walkTopDown().forEach {
if (it.isDirectory || !it.name.endsWith(".zip")) return@forEach if (it.isDirectory || !it.name.endsWith(".zip")) return@forEach
resources.computeIfAbsent("packs") { ArrayList() }.add(it.name) resources.computeIfAbsent("packs") { ArrayList() }.add(it.name)
} }
val langDir = File("${project(":common:implementation").buildDir}/resources/main/lang/") val langDir = File("${project(":common:implementation").buildDir}/resources/main/lang/")
langDir.walkTopDown().forEach { langDir.walkTopDown().forEach {
if (it.isDirectory || !it.name.endsWith(".yml")) return@forEach if (it.isDirectory || !it.name.endsWith(".yml")) return@forEach
resources.computeIfAbsent("lang") { ArrayList() }.add(it.name) resources.computeIfAbsent("lang") { ArrayList() }.add(it.name)
} }
project(":common:addons").subprojects.forEach { addonProject -> project(":common:addons").subprojects.forEach { addonProject ->
val jar = (addonProject.tasks.named("jar").get() as Jar).archiveFileName.get() val jar = (addonProject.tasks.named("jar").get() as Jar).archiveFileName.get()
resources.computeIfAbsent("addons") { ArrayList() }.add(jar) resources.computeIfAbsent("addons") { ArrayList() }.add(jar)
} }
val options = DumperOptions() val options = DumperOptions()
options.indent = 2 options.indent = 2
options.indentWithIndicator = true options.indentWithIndicator = true
@ -100,25 +100,25 @@ fun Project.configureDistribution() {
options.isPrettyFlow = true options.isPrettyFlow = true
options.defaultFlowStyle = DumperOptions.FlowStyle.BLOCK options.defaultFlowStyle = DumperOptions.FlowStyle.BLOCK
options.defaultScalarStyle = DumperOptions.ScalarStyle.DOUBLE_QUOTED options.defaultScalarStyle = DumperOptions.ScalarStyle.DOUBLE_QUOTED
val yaml = Yaml(options) val yaml = Yaml(options)
val manifest = File("${project.buildDir}/resources/main/resources.yml") val manifest = File("${project.buildDir}/resources/main/resources.yml")
if (manifest.exists()) manifest.delete() if (manifest.exists()) manifest.delete()
manifest.createNewFile() manifest.createNewFile()
yaml.dump(resources, FileWriter(manifest)) yaml.dump(resources, FileWriter(manifest))
} }
} }
tasks["processResources"].dependsOn(generateResourceManifest) tasks["processResources"].dependsOn(generateResourceManifest)
tasks.named<ShadowJar>("shadowJar") { tasks.named<ShadowJar>("shadowJar") {
// Tell shadow to download the packs // Tell shadow to download the packs
dependsOn(downloadDefaultPacks) dependsOn(downloadDefaultPacks)
configurations = listOf(project.configurations["shaded"]) configurations = listOf(project.configurations["shaded"])
archiveClassifier.set("shaded") archiveClassifier.set("shaded")
setVersion(project.version) setVersion(project.version)
relocate("org.apache.commons", "com.dfsek.terra.lib.commons") relocate("org.apache.commons", "com.dfsek.terra.lib.commons")
@ -126,11 +126,11 @@ fun Project.configureDistribution() {
relocate("org.json", "com.dfsek.terra.lib.json") relocate("org.json", "com.dfsek.terra.lib.json")
relocate("org.yaml", "com.dfsek.terra.lib.yaml") relocate("org.yaml", "com.dfsek.terra.lib.yaml")
} }
configure<BasePluginExtension> { configure<BasePluginExtension> {
archivesName.set(project.name) archivesName.set(project.name)
} }
tasks.named<DefaultTask>("build") { tasks.named<DefaultTask>("build") {
dependsOn(tasks["shadowJar"]) dependsOn(tasks["shadowJar"])
} }

View File

@ -3,7 +3,11 @@ package com.dfsek.terra
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.publish.PublishingExtension import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.publish.maven.MavenPublication
import org.gradle.kotlin.dsl.* import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.maven
import org.gradle.kotlin.dsl.provideDelegate
fun Project.configurePublishing() { fun Project.configurePublishing() {
configure<PublishingExtension> { configure<PublishingExtension> {
@ -13,11 +17,11 @@ fun Project.configurePublishing() {
artifact(tasks["jar"]) artifact(tasks["jar"])
} }
} }
repositories { repositories {
val mavenUrl = "https://repo.codemc.io/repository/maven-releases/" val mavenUrl = "https://repo.codemc.io/repository/maven-releases/"
//val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/" //val mavenSnapshotUrl = "https://repo.codemc.io/repository/maven-snapshots/"
maven(mavenUrl) { maven(mavenUrl) {
val mavenUsername: String? by project val mavenUsername: String? by project
val mavenPassword: String? by project val mavenPassword: String? by project

View File

@ -1,3 +1,4 @@
# Core Addons # Core Addons
This directory contains the modularized "core addons" that implement Terra's default behavior. This directory contains the modularized "core addons" that implement Terra's
default behavior.

View File

@ -1,8 +1,10 @@
# api-features # api-features
Contains the API for feature generation. Contains the API for feature generation.
This API implemented in: This API implemented in:
* `config-feature`
* `generation-stage-feature` * `config-feature`
* `config-locators` * `generation-stage-feature`
* `config-distributors` * `config-locators`
* `config-distributors`

View File

@ -1,6 +1,6 @@
# biome-provider-image # biome-provider-image
Implements and registers the `IMAGE` biome provider, a biome provider which generates Implements and registers the `IMAGE` biome provider, a biome provider which
biomes from an image, using the `color` attribute of biomes. generates biomes from an image, using the `color` attribute of biomes.
This addon registers the provider type, and all associated config options. This addon registers the provider type, and all associated config options.

View File

@ -1,57 +1,64 @@
package com.dfsek.terra.addons.biome.image; package com.dfsek.terra.addons.biome.image;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import net.jafama.FastMath; import net.jafama.FastMath;
import java.awt.*; import java.awt.Color;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class ImageBiomeProvider implements BiomeProvider { public class ImageBiomeProvider implements BiomeProvider {
private final Map<Color, TerraBiome> colorBiomeMap = new HashMap<>(); private final Map<Color, TerraBiome> colorBiomeMap = new HashMap<>();
private final BufferedImage image; private final BufferedImage image;
private final int resolution; private final int resolution;
private final Align align; private final Align align;
public ImageBiomeProvider(Set<TerraBiome> registry, BufferedImage image, int resolution, Align align) { public ImageBiomeProvider(Set<TerraBiome> registry, BufferedImage image, int resolution, Align align) {
this.image = image; this.image = image;
this.resolution = resolution; this.resolution = resolution;
this.align = align; this.align = align;
registry.forEach(biome -> colorBiomeMap.put(new Color(biome.getColor()), biome)); registry.forEach(biome -> colorBiomeMap.put(new Color(biome.getColor()), biome));
} }
private static int distance(Color a, Color b) { 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()); return FastMath.abs(a.getRed() - b.getRed()) + FastMath.abs(a.getGreen() - b.getGreen()) + FastMath.abs(a.getBlue() - b.getBlue());
} }
@Override @Override
public TerraBiome getBiome(int x, int z, long seed) { public TerraBiome getBiome(int x, int z, long seed) {
x /= resolution; x /= resolution;
z /= resolution; z /= resolution;
Color color = align.getColor(image, 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) -> { return colorBiomeMap.get(colorBiomeMap.keySet()
int d1 = distance(color, running); .stream()
int d2 = distance(color, element); .reduce(colorBiomeMap.keySet().stream().findAny().orElseThrow(IllegalStateException::new),
return d1 < d2 ? running : element; (running, element) -> {
})); int d1 = distance(color, running);
int d2 = distance(color, element);
return d1 < d2 ? running : element;
}));
} }
public enum Align { public enum Align {
CENTER { CENTER {
@Override @Override
public Color getColor(BufferedImage image, int x, int z) { 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()))); return new Color(image.getRGB(FastMath.floorMod(x - image.getWidth() / 2, image.getWidth()),
FastMath.floorMod(z - image.getHeight() / 2, image.getHeight())));
} }
}, NONE { },
NONE {
@Override @Override
public Color getColor(BufferedImage image, int x, int z) { public Color getColor(BufferedImage image, int x, int z) {
return new Color(image.getRGB(FastMath.floorMod(x, image.getWidth()), FastMath.floorMod(z, image.getHeight()))); 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); public abstract Color getColor(BufferedImage image, int x, int z);
} }
} }

View File

@ -1,6 +1,9 @@
package com.dfsek.terra.addons.biome.image; package com.dfsek.terra.addons.biome.image;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.function.Supplier;
import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.addon.TerraAddon; import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
@ -14,26 +17,27 @@ import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import java.util.function.Supplier;
@Addon("biome-provider-image") @Addon("biome-provider-image")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public class ImageBiomeProviderAddon extends TerraAddon { public class ImageBiomeProviderAddon extends TerraAddon {
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {}; public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
};
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager() main.getEventManager()
.getHandler(FunctionalEventHandler.class) .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class) .register(this, ConfigPackPreLoadEvent.class)
.then(event -> { .then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(PROVIDER_REGISTRY_KEY); CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(
providerRegistry.register("IMAGE", () -> new ImageProviderTemplate(event.getPack().getRegistry(TerraBiome.class))); PROVIDER_REGISTRY_KEY);
}) providerRegistry.register("IMAGE", () -> new ImageProviderTemplate(event.getPack().getRegistry(TerraBiome.class)));
.failThrough(); })
.failThrough();
} }
} }

View File

@ -3,29 +3,29 @@ package com.dfsek.terra.addons.biome.image;
import com.dfsek.tectonic.annotations.Default; import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.HashSet; import java.util.HashSet;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class ImageProviderTemplate implements ObjectTemplate<BiomeProvider> { public class ImageProviderTemplate implements ObjectTemplate<BiomeProvider> {
private final Registry<TerraBiome> biomes; private final Registry<TerraBiome> biomes;
@Value("image.name")
private BufferedImage image;
@Value("image.align")
private ImageBiomeProvider.Align align;
@Value("resolution") @Value("resolution")
@Default @Default
private int resolution = 1; private final int resolution = 1;
@Value("image.name")
private BufferedImage image;
@Value("image.align")
private ImageBiomeProvider.Align align;
public ImageProviderTemplate(Registry<TerraBiome> set) { public ImageProviderTemplate(Registry<TerraBiome> set) {
this.biomes = set; this.biomes = set;
} }
@Override @Override
public BiomeProvider get() { public BiomeProvider get() {
return new ImageBiomeProvider(new HashSet<>(biomes.entries()), image, resolution, align); return new ImageBiomeProvider(new HashSet<>(biomes.entries()), image, resolution, align);

View File

@ -3,5 +3,5 @@
Implements the Biome Pipeline, a procedural biome provider that uses a series Implements the Biome Pipeline, a procedural biome provider that uses a series
of "stages" to apply "mutations" to a 2D grid of biomes. of "stages" to apply "mutations" to a 2D grid of biomes.
This addon registers the `PIPELINE` biome provider type, and all associated
This addon registers the `PIPELINE` biome provider type, and all associated configurations. configurations.

View File

@ -3,16 +3,17 @@ package com.dfsek.terra.addons.biome.pipeline;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeExpander; import com.dfsek.terra.addons.biome.pipeline.api.BiomeExpander;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder; import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator; import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.vector.Vector2; import com.dfsek.terra.api.vector.Vector2;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
public class BiomeHolderImpl implements BiomeHolder { public class BiomeHolderImpl implements BiomeHolder {
private final Vector2 origin; private final Vector2 origin;
private final int width; private final int width;
private final int offset; private final int offset;
private TerraBiome[][] biomes; private TerraBiome[][] biomes;
public BiomeHolderImpl(int width, Vector2 origin) { public BiomeHolderImpl(int width, Vector2 origin) {
width += 4; width += 4;
this.width = width; this.width = width;
@ -20,35 +21,38 @@ public class BiomeHolderImpl implements BiomeHolder {
this.origin = origin; this.origin = origin;
this.offset = 2; this.offset = 2;
} }
private BiomeHolderImpl(TerraBiome[][] biomes, Vector2 origin, int width, int offset) { private BiomeHolderImpl(TerraBiome[][] biomes, Vector2 origin, int width, int offset) {
this.biomes = biomes; this.biomes = biomes;
this.origin = origin; this.origin = origin;
this.width = width; this.width = width;
this.offset = 2 * offset; this.offset = 2 * offset;
} }
@Override @Override
public BiomeHolder expand(BiomeExpander expander, long seed) { public BiomeHolder expand(BiomeExpander expander, long seed) {
TerraBiome[][] old = biomes; TerraBiome[][] old = biomes;
int newWidth = width * 2 - 1; int newWidth = width * 2 - 1;
biomes = new TerraBiome[newWidth][newWidth]; biomes = new TerraBiome[newWidth][newWidth];
for(int x = 0; x < width; x++) { for(int x = 0; x < width; x++) {
for(int z = 0; z < width; z++) { for(int z = 0; z < width; z++) {
biomes[x * 2][z * 2] = old[x][z]; biomes[x * 2][z * 2] = old[x][z];
if(z != width - 1) if(z != width - 1)
biomes[x * 2][z * 2 + 1] = expander.getBetween(x + origin.getX(), z + 1 + origin.getZ(), seed, old[x][z], old[x][z + 1]); biomes[x * 2][z * 2 + 1] = expander.getBetween(x + origin.getX(), z + 1 + origin.getZ(), seed, old[x][z],
old[x][z + 1]);
if(x != width - 1) if(x != width - 1)
biomes[x * 2 + 1][z * 2] = expander.getBetween(x + 1 + origin.getX(), z + origin.getZ(), seed, old[x][z], old[x + 1][z]); biomes[x * 2 + 1][z * 2] = expander.getBetween(x + 1 + origin.getX(), z + origin.getZ(), seed, old[x][z],
old[x + 1][z]);
if(x != width - 1 && z != width - 1) if(x != width - 1 && z != width - 1)
biomes[x * 2 + 1][z * 2 + 1] = expander.getBetween(x + 1 + origin.getX(), z + 1 + origin.getZ(), seed, old[x][z], old[x + 1][z + 1], old[x][z + 1], old[x + 1][z]); biomes[x * 2 + 1][z * 2 + 1] = expander.getBetween(x + 1 + origin.getX(), z + 1 + origin.getZ(), seed, old[x][z],
old[x + 1][z + 1], old[x][z + 1], old[x + 1][z]);
} }
} }
return new BiomeHolderImpl(biomes, origin.setX(origin.getX() * 2 - 1).setZ(origin.getZ() * 2 - 1), newWidth, offset); return new BiomeHolderImpl(biomes, origin.setX(origin.getX() * 2 - 1).setZ(origin.getZ() * 2 - 1), newWidth, offset);
} }
@Override @Override
public void mutate(BiomeMutator mutator, long seed) { public void mutate(BiomeMutator mutator, long seed) {
for(int x = 0; x < width; x++) { for(int x = 0; x < width; x++) {
@ -58,7 +62,7 @@ public class BiomeHolderImpl implements BiomeHolder {
} }
} }
} }
@Override @Override
public void fill(BiomeSource source, long seed) { public void fill(BiomeSource source, long seed) {
for(int x = 0; x < width; x++) { for(int x = 0; x < width; x++) {
@ -67,14 +71,14 @@ public class BiomeHolderImpl implements BiomeHolder {
} }
} }
} }
@Override @Override
public TerraBiome getBiome(int x, int z) { public TerraBiome getBiome(int x, int z) {
x += offset; x += offset;
z += offset; z += offset;
return getBiomeRaw(x, z); return getBiomeRaw(x, z);
} }
@Override @Override
public TerraBiome getBiomeRaw(int x, int z) { public TerraBiome getBiomeRaw(int x, int z) {
if(x >= width || z >= width || x < 0 || z < 0) return null; if(x >= width || z >= width || x < 0 || z < 0) return null;

View File

@ -1,31 +1,33 @@
package com.dfsek.terra.addons.biome.pipeline; package com.dfsek.terra.addons.biome.pipeline;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.api.vector.Vector2;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.vector.Vector2;
public class BiomePipeline { public class BiomePipeline {
private final BiomeSource source; private final BiomeSource source;
private final List<Stage> stages; private final List<Stage> stages;
private final int size; private final int size;
private final int init; private final int init;
private BiomePipeline(BiomeSource source, List<Stage> stages, int size, int init) { private BiomePipeline(BiomeSource source, List<Stage> stages, int size, int init) {
this.source = source; this.source = source;
this.stages = stages; this.stages = stages;
this.size = size; this.size = size;
this.init = init; this.init = init;
} }
/** /**
* Get biomes in a chunk * Get biomes in a chunk
* *
* @param x Chunk X coord * @param x Chunk X coord
* @param z Chunk Z coord * @param z Chunk Z coord
*
* @return BiomeHolder containing biomes. * @return BiomeHolder containing biomes.
*/ */
public BiomeHolder getBiomes(int x, int z, long seed) { public BiomeHolder getBiomes(int x, int z, long seed) {
@ -34,29 +36,29 @@ public class BiomePipeline {
for(Stage stage : stages) holder = stage.apply(holder, seed); for(Stage stage : stages) holder = stage.apply(holder, seed);
return holder; return holder;
} }
public int getSize() { public int getSize() {
return size; return size;
} }
public static final class BiomePipelineBuilder { public static final class BiomePipelineBuilder {
private final int init; private final int init;
List<Stage> stages = new ArrayList<>(); List<Stage> stages = new ArrayList<>();
private int expand; private int expand;
public BiomePipelineBuilder(int init) { public BiomePipelineBuilder(int init) {
this.init = init; this.init = init;
expand = init; expand = init;
} }
public BiomePipeline build(BiomeSource source) { public BiomePipeline build(BiomeSource source) {
for(Stage stage : stages) { for(Stage stage : stages) {
if(stage.isExpansion()) expand = expand * 2 - 1; if(stage.isExpansion()) expand = expand * 2 - 1;
} }
return new BiomePipeline(source, stages, expand, init); return new BiomePipeline(source, stages, expand, init);
} }
public BiomePipelineBuilder addStage(Stage stage) { public BiomePipelineBuilder addStage(Stage stage) {
stages.add(stage); stages.add(stage);
return this; return this;

View File

@ -1,9 +1,11 @@
package com.dfsek.terra.addons.biome.pipeline; package com.dfsek.terra.addons.biome.pipeline;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.function.Supplier;
import com.dfsek.terra.addons.biome.pipeline.api.Stage; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.BiomePipelineTemplate; import com.dfsek.terra.addons.biome.pipeline.config.BiomePipelineTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.BiomeProviderLoader;
import com.dfsek.terra.addons.biome.pipeline.config.NoiseSourceTemplate; import com.dfsek.terra.addons.biome.pipeline.config.NoiseSourceTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.expander.ExpanderStageTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.expander.ExpanderStageTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.BorderListMutatorTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.BorderListMutatorTemplate;
@ -11,6 +13,7 @@ import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.BorderMutatorT
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.ReplaceListMutatorTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.ReplaceListMutatorTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.ReplaceMutatorTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.ReplaceMutatorTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.SmoothMutatorTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.SmoothMutatorTemplate;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.addon.TerraAddon; import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
@ -22,44 +25,47 @@ import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import java.util.function.Supplier;
@Addon("biome-provider-pipeline") @Addon("biome-provider-pipeline")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public class BiomePipelineAddon extends TerraAddon { public class BiomePipelineAddon extends TerraAddon {
public static final TypeKey<Supplier<ObjectTemplate<BiomeSource>>> SOURCE_REGISTRY_KEY = new TypeKey<>() {}; public static final TypeKey<Supplier<ObjectTemplate<BiomeSource>>> SOURCE_REGISTRY_KEY = new TypeKey<>() {
};
public static final TypeKey<Supplier<ObjectTemplate<Stage>>> STAGE_REGISTRY_KEY = new TypeKey<>() {};
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {}; public static final TypeKey<Supplier<ObjectTemplate<Stage>>> STAGE_REGISTRY_KEY = new TypeKey<>() {
};
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
};
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager() main.getEventManager()
.getHandler(FunctionalEventHandler.class) .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class) .register(this, ConfigPackPreLoadEvent.class)
.then(event -> { .then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(PROVIDER_REGISTRY_KEY); CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(
providerRegistry.register("PIPELINE", () -> new BiomePipelineTemplate(main)); PROVIDER_REGISTRY_KEY);
}) providerRegistry.register("PIPELINE", () -> new BiomePipelineTemplate(main));
.then(event -> { })
CheckedRegistry<Supplier<ObjectTemplate<BiomeSource>>> sourceRegistry = event.getPack().getOrCreateRegistry(SOURCE_REGISTRY_KEY); .then(event -> {
sourceRegistry.register("NOISE", NoiseSourceTemplate::new); CheckedRegistry<Supplier<ObjectTemplate<BiomeSource>>> sourceRegistry = event.getPack().getOrCreateRegistry(
}) SOURCE_REGISTRY_KEY);
.then(event -> { sourceRegistry.register("NOISE", NoiseSourceTemplate::new);
CheckedRegistry<Supplier<ObjectTemplate<Stage>>> stageRegistry = event.getPack().getOrCreateRegistry(STAGE_REGISTRY_KEY); })
stageRegistry.register("FRACTAL_EXPAND", ExpanderStageTemplate::new); .then(event -> {
stageRegistry.register("SMOOTH", SmoothMutatorTemplate::new); CheckedRegistry<Supplier<ObjectTemplate<Stage>>> stageRegistry = event.getPack().getOrCreateRegistry(STAGE_REGISTRY_KEY);
stageRegistry.register("REPLACE", ReplaceMutatorTemplate::new); stageRegistry.register("FRACTAL_EXPAND", ExpanderStageTemplate::new);
stageRegistry.register("REPLACE_LIST", ReplaceListMutatorTemplate::new); stageRegistry.register("SMOOTH", SmoothMutatorTemplate::new);
stageRegistry.register("BORDER", BorderMutatorTemplate::new); stageRegistry.register("REPLACE", ReplaceMutatorTemplate::new);
stageRegistry.register("BORDER_LIST", BorderListMutatorTemplate::new); stageRegistry.register("REPLACE_LIST", ReplaceListMutatorTemplate::new);
}) stageRegistry.register("BORDER", BorderMutatorTemplate::new);
.failThrough(); stageRegistry.register("BORDER_LIST", BorderListMutatorTemplate::new);
})
.failThrough();
} }
} }

View File

@ -1,15 +1,17 @@
package com.dfsek.terra.addons.biome.pipeline; package com.dfsek.terra.addons.biome.pipeline;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder; import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
public class BiomePipelineProvider implements BiomeProvider { public class BiomePipelineProvider implements BiomeProvider {
private final LoadingCache<SeededVector, BiomeHolder> holderCache; private final LoadingCache<SeededVector, BiomeHolder> holderCache;
@ -17,50 +19,51 @@ public class BiomePipelineProvider implements BiomeProvider {
private final int resolution; private final int resolution;
private final NoiseSampler mutator; private final NoiseSampler mutator;
private final double noiseAmp; private final double noiseAmp;
public BiomePipelineProvider(BiomePipeline pipeline, TerraPlugin main, int resolution, NoiseSampler mutator, double noiseAmp) { public BiomePipelineProvider(BiomePipeline pipeline, TerraPlugin main, int resolution, NoiseSampler mutator, double noiseAmp) {
this.resolution = resolution; this.resolution = resolution;
this.mutator = mutator; this.mutator = mutator;
this.noiseAmp = noiseAmp; this.noiseAmp = noiseAmp;
holderCache = CacheBuilder.newBuilder() holderCache = CacheBuilder.newBuilder()
.maximumSize(main == null ? 32 : main.getTerraConfig().getProviderCache()) .maximumSize(main == null ? 32 : main.getTerraConfig().getProviderCache())
.build( .build(
new CacheLoader<SeededVector, BiomeHolder>() { new CacheLoader<SeededVector, BiomeHolder>() {
@Override @Override
public BiomeHolder load(@NotNull SeededVector key) { public BiomeHolder load(@NotNull SeededVector key) {
return pipeline.getBiomes(key.x, key.z, key.seed); return pipeline.getBiomes(key.x, key.z, key.seed);
} }
} }
); );
this.pipeline = pipeline; this.pipeline = pipeline;
} }
@Override @Override
public TerraBiome getBiome(int x, int z, long seed) { public TerraBiome getBiome(int x, int z, long seed) {
x += mutator.getNoiseSeeded(seed + 1, x, z) * noiseAmp; x += mutator.getNoiseSeeded(seed + 1, x, z) * noiseAmp;
z += mutator.getNoiseSeeded(seed + 2, x, z) * noiseAmp; z += mutator.getNoiseSeeded(seed + 2, x, z) * noiseAmp;
x = FastMath.floorToInt(FastMath.floorDiv(x, resolution)); x = FastMath.floorToInt(FastMath.floorDiv(x, resolution));
z = FastMath.floorToInt(FastMath.floorDiv(z, resolution)); z = FastMath.floorToInt(FastMath.floorDiv(z, resolution));
int fdX = FastMath.floorDiv(x, pipeline.getSize()); int fdX = FastMath.floorDiv(x, pipeline.getSize());
int fdZ = FastMath.floorDiv(z, pipeline.getSize()); int fdZ = FastMath.floorDiv(z, pipeline.getSize());
return holderCache.getUnchecked(new SeededVector(fdX, fdZ, seed)).getBiome(x - fdX * pipeline.getSize(), z - fdZ * pipeline.getSize()); return holderCache.getUnchecked(new SeededVector(fdX, fdZ, seed)).getBiome(x - fdX * pipeline.getSize(),
z - fdZ * pipeline.getSize());
} }
private static final class SeededVector { private static final class SeededVector {
private final int x; private final int x;
private final int z; private final int z;
private final long seed; private final long seed;
private SeededVector(int x, int z, long seed) { private SeededVector(int x, int z, long seed) {
this.x = x; this.x = x;
this.z = z; this.z = z;
this.seed = seed; this.seed = seed;
} }
@Override @Override
public int hashCode() { public int hashCode() {
int result = 0; int result = 0;
@ -69,12 +72,12 @@ public class BiomePipelineProvider implements BiomeProvider {
result = 31 * result + z; result = 31 * result + z;
return result; return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if(!(obj instanceof SeededVector)) return false; if(!(obj instanceof SeededVector)) return false;
SeededVector that = (SeededVector) obj; SeededVector that = (SeededVector) obj;
return this.seed == that.seed && this.x == that.x && this.z == that.z; return this.seed == that.seed && this.x == that.x && this.z == that.z;
} }
} }

View File

@ -2,6 +2,7 @@ package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
public interface BiomeExpander { public interface BiomeExpander {
TerraBiome getBetween(double x, double z, long seed, TerraBiome... others); TerraBiome getBetween(double x, double z, long seed, TerraBiome... others);
} }

View File

@ -1,16 +1,17 @@
package com.dfsek.terra.addons.biome.pipeline.api; package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource; import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.world.biome.TerraBiome;
public interface BiomeHolder { public interface BiomeHolder {
BiomeHolder expand(BiomeExpander expander, long seed); BiomeHolder expand(BiomeExpander expander, long seed);
void mutate(BiomeMutator mutator, long seed); void mutate(BiomeMutator mutator, long seed);
void fill(BiomeSource source, long seed); void fill(BiomeSource source, long seed);
TerraBiome getBiome(int x, int z); TerraBiome getBiome(int x, int z);
TerraBiome getBiomeRaw(int x, int z); TerraBiome getBiomeRaw(int x, int z);
} }

View File

@ -2,21 +2,22 @@ package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
public interface BiomeMutator { public interface BiomeMutator {
TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed); TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed);
class ViewPoint { class ViewPoint {
private final BiomeHolder biomes; private final BiomeHolder biomes;
private final int offX; private final int offX;
private final int offZ; private final int offZ;
public ViewPoint(BiomeHolder biomes, int offX, int offZ) { public ViewPoint(BiomeHolder biomes, int offX, int offZ) {
this.biomes = biomes; this.biomes = biomes;
this.offX = offX; this.offX = offX;
this.offZ = offZ; this.offZ = offZ;
} }
public TerraBiome getBiome(int x, int z) { public TerraBiome getBiome(int x, int z) {
return biomes.getBiomeRaw(x + offX, z + offZ); return biomes.getBiomeRaw(x + offX, z + offZ);
} }

View File

@ -1,8 +1,8 @@
package com.dfsek.terra.addons.biome.pipeline.api; package com.dfsek.terra.addons.biome.pipeline.api;
public interface Stage { public interface Stage {
boolean isExpansion();
BiomeHolder apply(BiomeHolder in, long seed); BiomeHolder apply(BiomeHolder in, long seed);
boolean isExpansion();
} }

View File

@ -2,33 +2,35 @@ package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.annotations.Default; import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.BiomePipeline;
import com.dfsek.terra.addons.biome.pipeline.BiomePipelineProvider;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import java.util.List; import java.util.List;
@SuppressWarnings({"FieldMayBeFinal", "unused"}) import com.dfsek.terra.addons.biome.pipeline.BiomePipeline;
import com.dfsek.terra.addons.biome.pipeline.BiomePipelineProvider;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@SuppressWarnings({ "FieldMayBeFinal", "unused" })
public class BiomePipelineTemplate extends BiomeProviderTemplate { public class BiomePipelineTemplate extends BiomeProviderTemplate {
private final TerraPlugin main; private final TerraPlugin main;
@Value("pipeline.initial-size") @Value("pipeline.initial-size")
@Default @Default
private @Meta int initialSize = 2; private @Meta int initialSize = 2;
@Value("pipeline.stages") @Value("pipeline.stages")
private @Meta List<@Meta Stage> stages; private @Meta List<@Meta Stage> stages;
@Value("pipeline.source") @Value("pipeline.source")
private @Meta BiomeSource source; private @Meta BiomeSource source;
public BiomePipelineTemplate(TerraPlugin main) { public BiomePipelineTemplate(TerraPlugin main) {
this.main = main; this.main = main;
} }
@Override @Override
public BiomeProvider get() { public BiomeProvider get() {
BiomePipeline.BiomePipelineBuilder biomePipelineBuilder = new BiomePipeline.BiomePipelineBuilder(initialSize); BiomePipeline.BiomePipelineBuilder biomePipelineBuilder = new BiomePipeline.BiomePipelineBuilder(initialSize);

View File

@ -3,10 +3,12 @@ package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader; import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader; import com.dfsek.tectonic.loading.TypeLoader;
import java.lang.reflect.AnnotatedType;
import com.dfsek.terra.addons.biome.pipeline.BiomePipelineProvider; import com.dfsek.terra.addons.biome.pipeline.BiomePipelineProvider;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import java.lang.reflect.AnnotatedType;
public class BiomeProviderLoader implements TypeLoader<BiomeProvider> { public class BiomeProviderLoader implements TypeLoader<BiomeProvider> {
@Override @Override

View File

@ -3,10 +3,12 @@ package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.annotations.Default; import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public abstract class BiomeProviderTemplate implements ObjectTemplate<BiomeProvider> { public abstract class BiomeProviderTemplate implements ObjectTemplate<BiomeProvider> {
@Value("resolution") @Value("resolution")
@Default @Default

View File

@ -1,20 +1,22 @@
package com.dfsek.terra.addons.biome.pipeline.config; package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.addons.biome.pipeline.source.NoiseSource; import com.dfsek.terra.addons.biome.pipeline.source.NoiseSource;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
public class NoiseSourceTemplate extends SourceTemplate { public class NoiseSourceTemplate extends SourceTemplate {
@Value("noise") @Value("noise")
private @Meta NoiseSampler noise; private @Meta NoiseSampler noise;
@Value("biomes") @Value("biomes")
private @Meta ProbabilityCollection<@Meta TerraBiome> biomes; private @Meta ProbabilityCollection<@Meta TerraBiome> biomes;
@Override @Override
public BiomeSource get() { public BiomeSource get() {
return new NoiseSource(biomes, noise); return new NoiseSource(biomes, noise);

View File

@ -1,8 +1,10 @@
package com.dfsek.terra.addons.biome.pipeline.config; package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource; import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
public abstract class SourceTemplate implements ObjectTemplate<BiomeSource>{
public abstract class SourceTemplate implements ObjectTemplate<BiomeSource> {
} }

View File

@ -2,12 +2,12 @@ package com.dfsek.terra.addons.biome.pipeline.config.stage;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.api.Stage; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
public abstract class StageTemplate implements ObjectTemplate<Stage> { public abstract class StageTemplate implements ObjectTemplate<Stage> {
@Value("noise") @Value("noise")
protected @Meta NoiseSampler noise; protected @Meta NoiseSampler noise;

View File

@ -5,6 +5,7 @@ import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.expand.FractalExpander; import com.dfsek.terra.addons.biome.pipeline.expand.FractalExpander;
import com.dfsek.terra.addons.biome.pipeline.stages.ExpanderStage; import com.dfsek.terra.addons.biome.pipeline.stages.ExpanderStage;
public class ExpanderStageTemplate extends StageTemplate { public class ExpanderStageTemplate extends StageTemplate {
@Override @Override
public Stage get() { public Stage get() {

View File

@ -1,6 +1,9 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator; package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import java.util.Map;
import com.dfsek.terra.addons.biome.pipeline.api.Stage; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.BorderListMutator; import com.dfsek.terra.addons.biome.pipeline.mutator.BorderListMutator;
@ -9,23 +12,22 @@ import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import java.util.Map;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class BorderListMutatorTemplate extends StageTemplate { public class BorderListMutatorTemplate extends StageTemplate {
@Value("from") @Value("from")
private @Meta String from; private @Meta String from;
@Value("default-replace") @Value("default-replace")
private @Meta String defaultReplace; private @Meta String defaultReplace;
@Value("default-to") @Value("default-to")
private @Meta ProbabilityCollection<@Meta TerraBiome> defaultTo; private @Meta ProbabilityCollection<@Meta TerraBiome> defaultTo;
@Value("replace") @Value("replace")
private @Meta Map<@Meta TerraBiome, @Meta ProbabilityCollection<@Meta TerraBiome>> replace; private @Meta Map<@Meta TerraBiome, @Meta ProbabilityCollection<@Meta TerraBiome>> replace;
@Override @Override
public Stage get() { public Stage get() {
return new MutatorStage(new BorderListMutator(replace, from, defaultReplace, noise, defaultTo)); return new MutatorStage(new BorderListMutator(replace, from, defaultReplace, noise, defaultTo));

View File

@ -1,7 +1,7 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator; package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.api.Stage; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.BorderMutator; import com.dfsek.terra.addons.biome.pipeline.mutator.BorderMutator;
@ -10,17 +10,18 @@ import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class BorderMutatorTemplate extends StageTemplate { public class BorderMutatorTemplate extends StageTemplate {
@Value("from") @Value("from")
private @Meta String from; private @Meta String from;
@Value("replace") @Value("replace")
private @Meta String replace; private @Meta String replace;
@Value("to") @Value("to")
private @Meta ProbabilityCollection<@Meta TerraBiome> to; private @Meta ProbabilityCollection<@Meta TerraBiome> to;
@Override @Override
public Stage get() { public Stage get() {
return new MutatorStage(new BorderMutator(from, replace, noise, to)); return new MutatorStage(new BorderMutator(from, replace, noise, to));

View File

@ -1,7 +1,9 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator; package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import java.util.Map;
import com.dfsek.terra.addons.biome.pipeline.api.Stage; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.ReplaceListMutator; import com.dfsek.terra.addons.biome.pipeline.mutator.ReplaceListMutator;
@ -10,19 +12,18 @@ import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import java.util.Map;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class ReplaceListMutatorTemplate extends StageTemplate { public class ReplaceListMutatorTemplate extends StageTemplate {
@Value("default-from") @Value("default-from")
private @Meta String defaultFrom; private @Meta String defaultFrom;
@Value("default-to") @Value("default-to")
private @Meta ProbabilityCollection<@Meta TerraBiome> defaultTo; private @Meta ProbabilityCollection<@Meta TerraBiome> defaultTo;
@Value("to") @Value("to")
private @Meta Map<@Meta TerraBiome, @Meta ProbabilityCollection<@Meta TerraBiome>> replace; private @Meta Map<@Meta TerraBiome, @Meta ProbabilityCollection<@Meta TerraBiome>> replace;
@Override @Override
public Stage get() { public Stage get() {
return new MutatorStage(new ReplaceListMutator(replace, defaultFrom, defaultTo, noise)); return new MutatorStage(new ReplaceListMutator(replace, defaultFrom, defaultTo, noise));

View File

@ -1,7 +1,7 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator; package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.api.Stage; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.ReplaceMutator; import com.dfsek.terra.addons.biome.pipeline.mutator.ReplaceMutator;
@ -10,14 +10,15 @@ import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class ReplaceMutatorTemplate extends StageTemplate { public class ReplaceMutatorTemplate extends StageTemplate {
@Value("from") @Value("from")
private @Meta String from; private @Meta String from;
@Value("to") @Value("to")
private @Meta ProbabilityCollection<@Meta TerraBiome> to; private @Meta ProbabilityCollection<@Meta TerraBiome> to;
@Override @Override
public Stage get() { public Stage get() {
return new MutatorStage(new ReplaceMutator(from, to, noise)); return new MutatorStage(new ReplaceMutator(from, to, noise));

View File

@ -1,11 +1,11 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator; package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.api.Stage; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate; import com.dfsek.terra.addons.biome.pipeline.config.stage.StageTemplate;
import com.dfsek.terra.addons.biome.pipeline.mutator.SmoothMutator; import com.dfsek.terra.addons.biome.pipeline.mutator.SmoothMutator;
import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage; import com.dfsek.terra.addons.biome.pipeline.stages.MutatorStage;
public class SmoothMutatorTemplate extends StageTemplate { public class SmoothMutatorTemplate extends StageTemplate {
@Override @Override
public Stage get() { public Stage get() {

View File

@ -5,13 +5,14 @@ import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.MathUtil; import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
public class FractalExpander implements BiomeExpander { public class FractalExpander implements BiomeExpander {
private final NoiseSampler sampler; private final NoiseSampler sampler;
public FractalExpander(NoiseSampler sampler) { public FractalExpander(NoiseSampler sampler) {
this.sampler = sampler; this.sampler = sampler;
} }
@Override @Override
public TerraBiome getBetween(double x, double z, long seed, TerraBiome... others) { public TerraBiome getBetween(double x, double z, long seed, TerraBiome... others) {
return others[MathUtil.normalizeIndex(sampler.getNoiseSeeded(seed, x, z), others.length)]; return others[MathUtil.normalizeIndex(sampler.getNoiseSeeded(seed, x, z), others.length)];

View File

@ -1,11 +1,12 @@
package com.dfsek.terra.addons.biome.pipeline.mutator; package com.dfsek.terra.addons.biome.pipeline.mutator;
import java.util.Map;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator; import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import java.util.Map;
public class BorderListMutator implements BiomeMutator { public class BorderListMutator implements BiomeMutator {
private final String border; private final String border;
@ -13,15 +14,16 @@ public class BorderListMutator implements BiomeMutator {
private final ProbabilityCollection<TerraBiome> replaceDefault; private final ProbabilityCollection<TerraBiome> replaceDefault;
private final String defaultReplace; private final String defaultReplace;
private final Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace; private final Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace;
public BorderListMutator(Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace, String border, String defaultReplace, NoiseSampler noiseSampler, ProbabilityCollection<TerraBiome> replaceDefault) { public BorderListMutator(Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace, String border, String defaultReplace,
NoiseSampler noiseSampler, ProbabilityCollection<TerraBiome> replaceDefault) {
this.border = border; this.border = border;
this.noiseSampler = noiseSampler; this.noiseSampler = noiseSampler;
this.replaceDefault = replaceDefault; this.replaceDefault = replaceDefault;
this.defaultReplace = defaultReplace; this.defaultReplace = defaultReplace;
this.replace = replace; this.replace = replace;
} }
@Override @Override
public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) { public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) {
TerraBiome origin = viewPoint.getBiome(0, 0); TerraBiome origin = viewPoint.getBiome(0, 0);

View File

@ -5,19 +5,20 @@ import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
public class BorderMutator implements BiomeMutator { public class BorderMutator implements BiomeMutator {
private final String border; private final String border;
private final NoiseSampler noiseSampler; private final NoiseSampler noiseSampler;
private final ProbabilityCollection<TerraBiome> replace; private final ProbabilityCollection<TerraBiome> replace;
private final String replaceTag; private final String replaceTag;
public BorderMutator(String border, String replaceTag, NoiseSampler noiseSampler, ProbabilityCollection<TerraBiome> replace) { public BorderMutator(String border, String replaceTag, NoiseSampler noiseSampler, ProbabilityCollection<TerraBiome> replace) {
this.border = border; this.border = border;
this.noiseSampler = noiseSampler; this.noiseSampler = noiseSampler;
this.replace = replace; this.replace = replace;
this.replaceTag = replaceTag; this.replaceTag = replaceTag;
} }
@Override @Override
public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) { public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) {
TerraBiome origin = viewPoint.getBiome(0, 0); TerraBiome origin = viewPoint.getBiome(0, 0);

View File

@ -1,25 +1,27 @@
package com.dfsek.terra.addons.biome.pipeline.mutator; package com.dfsek.terra.addons.biome.pipeline.mutator;
import java.util.Map;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator; import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import java.util.Map;
public class ReplaceListMutator implements BiomeMutator { public class ReplaceListMutator implements BiomeMutator {
private final Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace; private final Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace;
private final NoiseSampler sampler; private final NoiseSampler sampler;
private final ProbabilityCollection<TerraBiome> replaceDefault; private final ProbabilityCollection<TerraBiome> replaceDefault;
private final String defaultTag; private final String defaultTag;
public ReplaceListMutator(Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace, String defaultTag, ProbabilityCollection<TerraBiome> replaceDefault, NoiseSampler sampler) { public ReplaceListMutator(Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace, String defaultTag,
ProbabilityCollection<TerraBiome> replaceDefault, NoiseSampler sampler) {
this.replace = replace; this.replace = replace;
this.sampler = sampler; this.sampler = sampler;
this.defaultTag = defaultTag; this.defaultTag = defaultTag;
this.replaceDefault = replaceDefault; this.replaceDefault = replaceDefault;
} }
@Override @Override
public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) { public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) {
TerraBiome center = viewPoint.getBiome(0, 0); TerraBiome center = viewPoint.getBiome(0, 0);

View File

@ -5,17 +5,18 @@ import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
public class ReplaceMutator implements BiomeMutator { public class ReplaceMutator implements BiomeMutator {
private final String replaceableTag; private final String replaceableTag;
private final ProbabilityCollection<TerraBiome> replace; private final ProbabilityCollection<TerraBiome> replace;
private final NoiseSampler sampler; private final NoiseSampler sampler;
public ReplaceMutator(String replaceable, ProbabilityCollection<TerraBiome> replace, NoiseSampler sampler) { public ReplaceMutator(String replaceable, ProbabilityCollection<TerraBiome> replace, NoiseSampler sampler) {
this.replaceableTag = replaceable; this.replaceableTag = replaceable;
this.replace = replace; this.replace = replace;
this.sampler = sampler; this.sampler = sampler;
} }
@Override @Override
public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) { public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) {
if(viewPoint.getBiome(0, 0).getTags().contains(replaceableTag)) { if(viewPoint.getBiome(0, 0).getTags().contains(replaceableTag)) {

View File

@ -1,38 +1,39 @@
package com.dfsek.terra.addons.biome.pipeline.mutator; package com.dfsek.terra.addons.biome.pipeline.mutator;
import java.util.Objects;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator; import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.MathUtil; import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import java.util.Objects;
public class SmoothMutator implements BiomeMutator { public class SmoothMutator implements BiomeMutator {
private final NoiseSampler sampler; private final NoiseSampler sampler;
public SmoothMutator(NoiseSampler sampler) { public SmoothMutator(NoiseSampler sampler) {
this.sampler = sampler; this.sampler = sampler;
} }
@Override @Override
public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) { public TerraBiome mutate(ViewPoint viewPoint, double x, double z, long seed) {
TerraBiome top = viewPoint.getBiome(1, 0); TerraBiome top = viewPoint.getBiome(1, 0);
TerraBiome bottom = viewPoint.getBiome(-1, 0); TerraBiome bottom = viewPoint.getBiome(-1, 0);
TerraBiome left = viewPoint.getBiome(0, 1); TerraBiome left = viewPoint.getBiome(0, 1);
TerraBiome right = viewPoint.getBiome(0, -1); TerraBiome right = viewPoint.getBiome(0, -1);
boolean vert = Objects.equals(top, bottom) && top != null; boolean vert = Objects.equals(top, bottom) && top != null;
boolean horiz = Objects.equals(left, right) && left != null; boolean horiz = Objects.equals(left, right) && left != null;
if(vert && horiz) { if(vert && horiz) {
return MathUtil.normalizeIndex(sampler.getNoiseSeeded(seed, x, z), 2) == 0 ? left : top; return MathUtil.normalizeIndex(sampler.getNoiseSeeded(seed, x, z), 2) == 0 ? left : top;
} }
if(vert) return top; if(vert) return top;
if(horiz) return left; if(horiz) return left;
return viewPoint.getBiome(0, 0); return viewPoint.getBiome(0, 0);
} }
} }

View File

@ -2,6 +2,7 @@ package com.dfsek.terra.addons.biome.pipeline.source;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
public interface BiomeSource { public interface BiomeSource {
TerraBiome getBiome(double x, double z, long seed); TerraBiome getBiome(double x, double z, long seed);
} }

View File

@ -4,15 +4,16 @@ import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
public class NoiseSource implements BiomeSource { public class NoiseSource implements BiomeSource {
private final ProbabilityCollection<TerraBiome> biomes; private final ProbabilityCollection<TerraBiome> biomes;
private final NoiseSampler sampler; private final NoiseSampler sampler;
public NoiseSource(ProbabilityCollection<TerraBiome> biomes, NoiseSampler sampler) { public NoiseSource(ProbabilityCollection<TerraBiome> biomes, NoiseSampler sampler) {
this.biomes = biomes; this.biomes = biomes;
this.sampler = sampler; this.sampler = sampler;
} }
@Override @Override
public TerraBiome getBiome(double x, double z, long seed) { public TerraBiome getBiome(double x, double z, long seed) {
return biomes.get(sampler, x, z, seed); return biomes.get(sampler, x, z, seed);

View File

@ -4,23 +4,24 @@ import com.dfsek.terra.addons.biome.pipeline.api.BiomeExpander;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder; import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.Stage; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
public class ExpanderStage implements Stage { public class ExpanderStage implements Stage {
private final BiomeExpander expander; private final BiomeExpander expander;
public ExpanderStage(BiomeExpander expander) { public ExpanderStage(BiomeExpander expander) {
this.expander = expander; this.expander = expander;
} }
@Override
public boolean isExpansion() {
return true;
}
@Override @Override
public BiomeHolder apply(BiomeHolder in, long seed) { public BiomeHolder apply(BiomeHolder in, long seed) {
return in.expand(expander, seed); return in.expand(expander, seed);
} }
@Override
public boolean isExpansion() {
return true;
}
public enum Type { public enum Type {
FRACTAL FRACTAL
} }

View File

@ -4,25 +4,30 @@ import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator; import com.dfsek.terra.addons.biome.pipeline.api.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.api.Stage; import com.dfsek.terra.addons.biome.pipeline.api.Stage;
public class MutatorStage implements Stage { public class MutatorStage implements Stage {
private final BiomeMutator mutator; private final BiomeMutator mutator;
public MutatorStage(BiomeMutator mutator) { public MutatorStage(BiomeMutator mutator) {
this.mutator = mutator; this.mutator = mutator;
} }
@Override
public boolean isExpansion() {
return false;
}
@Override @Override
public BiomeHolder apply(BiomeHolder in, long seed) { public BiomeHolder apply(BiomeHolder in, long seed) {
in.mutate(mutator, seed); in.mutate(mutator, seed);
return in; return in;
} }
@Override
public boolean isExpansion() {
return false;
}
public enum Type { public enum Type {
REPLACE, REPLACE_LIST, BORDER, BORDER_LIST, SMOOTH REPLACE,
REPLACE_LIST,
BORDER,
BORDER_LIST,
SMOOTH
} }
} }

View File

@ -3,13 +3,14 @@ package com.dfsek.terra.addons.biome.single;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class SingleBiomeProvider implements BiomeProvider { public class SingleBiomeProvider implements BiomeProvider {
private final TerraBiome biome; private final TerraBiome biome;
public SingleBiomeProvider(TerraBiome biome) { public SingleBiomeProvider(TerraBiome biome) {
this.biome = biome; this.biome = biome;
} }
@Override @Override
public TerraBiome getBiome(int x, int z, long seed) { public TerraBiome getBiome(int x, int z, long seed) {
return biome; return biome;

View File

@ -1,6 +1,9 @@
package com.dfsek.terra.addons.biome.single; package com.dfsek.terra.addons.biome.single;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.function.Supplier;
import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.addon.TerraAddon; import com.dfsek.terra.api.addon.TerraAddon;
import com.dfsek.terra.api.addon.annotations.Addon; import com.dfsek.terra.api.addon.annotations.Addon;
@ -13,26 +16,27 @@ import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import java.util.function.Supplier;
@Addon("biome-provider-single") @Addon("biome-provider-single")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public class SingleBiomeProviderAddon extends TerraAddon { public class SingleBiomeProviderAddon extends TerraAddon {
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {}; public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
};
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager() main.getEventManager()
.getHandler(FunctionalEventHandler.class) .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class) .register(this, ConfigPackPreLoadEvent.class)
.then(event -> { .then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(PROVIDER_REGISTRY_KEY); CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(
providerRegistry.register("SINGLE", SingleBiomeProviderTemplate::new); PROVIDER_REGISTRY_KEY);
}) providerRegistry.register("SINGLE", SingleBiomeProviderTemplate::new);
.failThrough(); })
.failThrough();
} }
} }

View File

@ -2,14 +2,16 @@ package com.dfsek.terra.addons.biome.single;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class SingleBiomeProviderTemplate implements ObjectTemplate<BiomeProvider> { public class SingleBiomeProviderTemplate implements ObjectTemplate<BiomeProvider> {
@Value("biome") @Value("biome")
private @Meta TerraBiome biome; private @Meta TerraBiome biome;
@Override @Override
public BiomeProvider get() { public BiomeProvider get() {
return new SingleBiomeProvider(biome); return new SingleBiomeProvider(biome);

View File

@ -3,26 +3,26 @@ package com.dfsek.terra.addons.chunkgenerator;
import com.dfsek.tectonic.annotations.Default; import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder; import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteInfo; import com.dfsek.terra.addons.chunkgenerator.palette.PaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder; import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.world.generator.Palette; import com.dfsek.terra.api.world.generator.Palette;
public class BiomePaletteTemplate implements ObjectTemplate<PaletteInfo> {
@Value("palette")
private @Meta PaletteHolder palette;
public class BiomePaletteTemplate implements ObjectTemplate<PaletteInfo> {
@Value("slant") @Value("slant")
@Default @Default
private @Meta SlantHolder slant = null; private final @Meta SlantHolder slant;
@Value("palette")
private @Meta PaletteHolder palette;
@Value("ocean.level") @Value("ocean.level")
private @Meta int seaLevel; private @Meta int seaLevel;
@Value("ocean.palette") @Value("ocean.palette")
private @Meta Palette oceanPalette; private @Meta Palette oceanPalette;
@Override @Override
public PaletteInfo get() { public PaletteInfo get() {
return new PaletteInfo(palette, slant, oceanPalette, seaLevel); return new PaletteInfo(palette, slant, oceanPalette, seaLevel);

View File

@ -17,34 +17,36 @@ import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.generator.ChunkGeneratorProvider; import com.dfsek.terra.api.world.generator.ChunkGeneratorProvider;
@Addon("chunk-generator-noise-3d") @Addon("chunk-generator-noise-3d")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public class NoiseChunkGenerator3DAddon extends TerraAddon { public class NoiseChunkGenerator3DAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager() main.getEventManager()
.getHandler(FunctionalEventHandler.class) .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class) .register(this, ConfigPackPreLoadEvent.class)
.then(event -> { .then(event -> {
event.getPack().getOrCreateRegistry(ChunkGeneratorProvider.class).register("NOISE_3D", pack -> new NoiseChunkGenerator3D(pack, main)); event.getPack().getOrCreateRegistry(ChunkGeneratorProvider.class).register("NOISE_3D",
event.getPack() pack -> new NoiseChunkGenerator3D(pack, main));
.applyLoader(SlantHolder.class, new SlantHolderLoader()) event.getPack()
.applyLoader(PaletteHolder.class, new PaletteHolderLoader()); .applyLoader(SlantHolder.class, new SlantHolderLoader())
}) .applyLoader(PaletteHolder.class, new PaletteHolderLoader());
.failThrough(); })
.failThrough();
main.getEventManager() main.getEventManager()
.getHandler(FunctionalEventHandler.class) .getHandler(FunctionalEventHandler.class)
.register(this, ConfigurationLoadEvent.class) .register(this, ConfigurationLoadEvent.class)
.then(event -> { .then(event -> {
if(event.is(TerraBiome.class)) { if(event.is(TerraBiome.class)) {
event.getLoadedObject(TerraBiome.class).getContext().put(event.load(new BiomePaletteTemplate()).get()); event.getLoadedObject(TerraBiome.class).getContext().put(event.load(new BiomePaletteTemplate()).get());
} }
}) })
.failThrough(); .failThrough();
} }
} }

View File

@ -7,6 +7,7 @@ import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.generator.Palette; import com.dfsek.terra.api.world.generator.Palette;
import com.dfsek.terra.api.world.generator.Sampler; import com.dfsek.terra.api.world.generator.Sampler;
public final class PaletteUtil { public final class PaletteUtil {
public static Palette getPalette(int x, int y, int z, GenerationSettings c, Sampler sampler, PaletteInfo paletteInfo) { public static Palette getPalette(int x, int y, int z, GenerationSettings c, Sampler sampler, PaletteInfo paletteInfo) {
SlantHolder slant = paletteInfo.getSlantHolder(); SlantHolder slant = paletteInfo.getSlantHolder();
@ -16,7 +17,7 @@ public final class PaletteUtil {
return slant.getPalette(slope).getPalette(y); return slant.getPalette(slope).getPalette(y);
} }
} }
return paletteInfo.getPaletteHolder().getPalette(y); return paletteInfo.getPaletteHolder().getPalette(y);
} }
} }

View File

@ -1,5 +1,12 @@
package com.dfsek.terra.addons.chunkgenerator.generation.generators; package com.dfsek.terra.addons.chunkgenerator.generation.generators;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import com.dfsek.terra.addons.chunkgenerator.PaletteUtil; import com.dfsek.terra.addons.chunkgenerator.PaletteUtil;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D; import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteInfo; import com.dfsek.terra.addons.chunkgenerator.palette.PaletteInfo;
@ -16,32 +23,27 @@ import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.generator.ChunkData; import com.dfsek.terra.api.world.generator.ChunkData;
import com.dfsek.terra.api.world.generator.Palette;
import com.dfsek.terra.api.world.generator.Sampler;
import com.dfsek.terra.api.world.generator.ChunkGenerator; import com.dfsek.terra.api.world.generator.ChunkGenerator;
import com.dfsek.terra.api.world.generator.GenerationStage; import com.dfsek.terra.api.world.generator.GenerationStage;
import net.jafama.FastMath; import com.dfsek.terra.api.world.generator.Palette;
import org.jetbrains.annotations.NotNull; import com.dfsek.terra.api.world.generator.Sampler;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class NoiseChunkGenerator3D implements ChunkGenerator { public class NoiseChunkGenerator3D implements ChunkGenerator {
private final ConfigPack configPack; private final ConfigPack configPack;
private final TerraPlugin main; private final TerraPlugin main;
private final List<GenerationStage> generationStages = new ArrayList<>(); private final List<GenerationStage> generationStages = new ArrayList<>();
private final BlockState air; private final BlockState air;
public NoiseChunkGenerator3D(ConfigPack c, TerraPlugin main) { public NoiseChunkGenerator3D(ConfigPack c, TerraPlugin main) {
this.configPack = c; this.configPack = c;
this.main = main; this.main = main;
this.air = main.getWorldHandle().air(); this.air = main.getWorldHandle().air();
c.getStages().forEach(stage -> generationStages.add(stage.newInstance(c))); c.getStages().forEach(stage -> generationStages.add(stage.newInstance(c)));
} }
@SuppressWarnings({"try"}) @SuppressWarnings("try")
static void biomes(@NotNull World world, int chunkX, int chunkZ, @NotNull BiomeGrid biome, TerraPlugin main) { static void biomes(@NotNull World world, int chunkX, int chunkZ, @NotNull BiomeGrid biome, TerraPlugin main) {
try(ProfileFrame ignore = main.getProfiler().profile("biomes")) { try(ProfileFrame ignore = main.getProfiler().profile("biomes")) {
int xOrig = (chunkX << 4); int xOrig = (chunkX << 4);
@ -53,73 +55,64 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
int cx = xOrig + (x << 2); int cx = xOrig + (x << 2);
int cz = zOrig + (z << 2); int cz = zOrig + (z << 2);
TerraBiome b = grid.getBiome(cx, cz, seed); TerraBiome b = grid.getBiome(cx, cz, seed);
biome.setBiome(cx, cz, b.getVanillaBiomes().get(b.getGenerator().getBiomeNoise(), cx, 0, cz, world.getSeed())); biome.setBiome(cx, cz, b.getVanillaBiomes().get(b.getGenerator().getBiomeNoise(), cx, 0, cz, world.getSeed()));
} }
} }
} }
} }
@Override @Override
public ConfigPack getConfigPack() { @SuppressWarnings("try")
return configPack;
}
@Override
public TerraPlugin getMain() {
return main;
}
@Override
@SuppressWarnings({"try"})
public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) { public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) {
try(ProfileFrame ignore = main.getProfiler().profile("chunk_base_3d")) { try(ProfileFrame ignore = main.getProfiler().profile("chunk_base_3d")) {
BiomeProvider grid = world.getBiomeProvider(); BiomeProvider grid = world.getBiomeProvider();
int xOrig = (chunkX << 4); int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4); int zOrig = (chunkZ << 4);
Sampler sampler = world.getConfig().getSamplerCache().getChunk(chunkX, chunkZ); Sampler sampler = world.getConfig().getSamplerCache().getChunk(chunkX, chunkZ);
long seed = world.getSeed(); long seed = world.getSeed();
for(int x = 0; x < 16; x++) { for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) { for(int z = 0; z < 16; z++) {
int paletteLevel = 0; int paletteLevel = 0;
int cx = xOrig + x; int cx = xOrig + x;
int cz = zOrig + z; int cz = zOrig + z;
TerraBiome biome = grid.getBiome(cx, cz, seed); TerraBiome biome = grid.getBiome(cx, cz, seed);
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class); PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
if(paletteInfo == null) { if(paletteInfo == null) {
main.logger().info("null palette: " + biome.getID()); main.logger().info("null palette: " + biome.getID());
} }
GenerationSettings generationSettings = biome.getGenerator(); GenerationSettings generationSettings = biome.getGenerator();
int sea = paletteInfo.getSeaLevel(); int sea = paletteInfo.getSeaLevel();
Palette seaPalette = paletteInfo.getOcean(); Palette seaPalette = paletteInfo.getOcean();
boolean justSet = false; boolean justSet = false;
BlockState data = null; BlockState data = null;
for(int y = world.getMaxHeight() - 1; y >= world.getMinHeight(); y--) { for(int y = world.getMaxHeight() - 1; y >= world.getMinHeight(); y--) {
if(sampler.sample(x, y, z) > 0) { if(sampler.sample(x, y, z) > 0) {
justSet = true; justSet = true;
data = PaletteUtil.getPalette(x, y, z, generationSettings, sampler, paletteInfo).get(paletteLevel, cx, y, cz, seed); data = PaletteUtil.getPalette(x, y, z, generationSettings, sampler, paletteInfo).get(paletteLevel, cx, y, cz,
seed);
chunk.setBlock(x, y, z, data); chunk.setBlock(x, y, z, data);
paletteLevel++; paletteLevel++;
} else if(y <= sea) { } else if(y <= sea) {
chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, y, z + zOrig, seed)); chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, y, z + zOrig, seed));
justSet = false; justSet = false;
paletteLevel = 0; paletteLevel = 0;
} else { } else {
justSet = false; justSet = false;
paletteLevel = 0; paletteLevel = 0;
} }
@ -129,47 +122,38 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
return chunk; return chunk;
} }
} }
private boolean placeStair(BlockState orig, ChunkData chunk, Vector3 block, double thresh, Sampler sampler, BlockState stairNew) {
if(sampler.sample(block.getBlockX() - 0.55, block.getY(), block.getZ()) > thresh) {
stairNew.set(Properties.DIRECTION, Direction.WEST);
} else if(sampler.sample(block.getBlockX(), block.getY(), block.getZ() - 0.55) > thresh) {
stairNew.set(Properties.DIRECTION, Direction.NORTH);
} else if(sampler.sample(block.getBlockX(), block.getY(), block.getZ() + 0.55) > thresh) {
stairNew.set(Properties.DIRECTION, Direction.SOUTH);
} else if(sampler.sample(block.getX() + 0.55, block.getY(), block.getZ()) > thresh) {
stairNew.set(Properties.DIRECTION, Direction.EAST);
} else stairNew = null;
if(stairNew != null) {
stairNew.setIfPresent(Properties.WATERLOGGED, orig.getBlockType().isWater());
chunk.setBlock(block.getBlockX(), block.getBlockY(), block.getBlockZ(), stairNew);
return true;
}
return false;
}
@Override @Override
public void generateBiomes(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, @NotNull BiomeGrid biome) { public void generateBiomes(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, @NotNull BiomeGrid biome) {
biomes(world, chunkX, chunkZ, biome, main); biomes(world, chunkX, chunkZ, biome, main);
} }
@Override @Override
public Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth) { public Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth) {
return new Sampler3D(chunkX, chunkZ, provider, world, elevationSmooth); return new Sampler3D(chunkX, chunkZ, provider, world, elevationSmooth);
} }
@Override
public ConfigPack getConfigPack() {
return configPack;
}
@Override
public TerraPlugin getMain() {
return main;
}
@Override @Override
public List<GenerationStage> getGenerationStages() { public List<GenerationStage> getGenerationStages() {
return generationStages; return generationStages;
} }
@Override @Override
public BlockState getBlock(World world, int x, int y, int z) { public BlockState getBlock(World world, int x, int y, int z) {
BiomeProvider provider = world.getBiomeProvider(); BiomeProvider provider = world.getBiomeProvider();
TerraBiome biome = provider.getBiome(x, z, world.getSeed()); TerraBiome biome = provider.getBiome(x, z, world.getSeed());
Sampler sampler = world.getConfig().getSamplerCache().get(x, z); Sampler sampler = world.getConfig().getSamplerCache().get(x, z);
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class); PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
Palette palette = PaletteUtil.getPalette(x, y, z, biome.getGenerator(), sampler, paletteInfo); Palette palette = PaletteUtil.getPalette(x, y, z, biome.getGenerator(), sampler, paletteInfo);
int fdX = FastMath.floorMod(x, 16); int fdX = FastMath.floorMod(x, 16);
@ -186,4 +170,23 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
return paletteInfo.getOcean().get(paletteInfo.getSeaLevel() - y, x, y, z, world.getSeed()); return paletteInfo.getOcean().get(paletteInfo.getSeaLevel() - y, x, y, z, world.getSeed());
} else return air; } else return air;
} }
private boolean placeStair(BlockState orig, ChunkData chunk, Vector3 block, double thresh, Sampler sampler, BlockState stairNew) {
if(sampler.sample(block.getBlockX() - 0.55, block.getY(), block.getZ()) > thresh) {
stairNew.set(Properties.DIRECTION, Direction.WEST);
} else if(sampler.sample(block.getBlockX(), block.getY(), block.getZ() - 0.55) > thresh) {
stairNew.set(Properties.DIRECTION, Direction.NORTH);
} else if(sampler.sample(block.getBlockX(), block.getY(), block.getZ() + 0.55) > thresh) {
stairNew.set(Properties.DIRECTION, Direction.SOUTH);
} else if(sampler.sample(block.getX() + 0.55, block.getY(), block.getZ()) > thresh) {
stairNew.set(Properties.DIRECTION, Direction.EAST);
} else stairNew = null;
if(stairNew != null) {
stairNew.setIfPresent(Properties.WATERLOGGED, orig.getBlockType().isWater());
chunk.setBlock(block.getBlockX(), block.getBlockY(), block.getBlockZ(), stairNew);
return true;
}
return false;
}
} }

View File

@ -1,16 +1,18 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation; package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import net.jafama.FastMath;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import com.dfsek.terra.api.util.mutable.MutableInteger; import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.api.vector.Vector3; import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World; import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.GenerationSettings; import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.generator.ChunkInterpolator; import com.dfsek.terra.api.world.generator.ChunkInterpolator;
import net.jafama.FastMath;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
/** /**
* Class to abstract away the Interpolators needed to generate a chunk.<br> * Class to abstract away the Interpolators needed to generate a chunk.<br>
@ -19,7 +21,7 @@ import java.util.function.BiFunction;
public class ChunkInterpolator2D implements ChunkInterpolator { public class ChunkInterpolator2D implements ChunkInterpolator {
private final Interpolator[][] interpGrid = new Interpolator[4][4]; private final Interpolator[][] interpGrid = new Interpolator[4][4];
private final BiFunction<GenerationSettings, Vector3, Double> noiseGetter; private final BiFunction<GenerationSettings, Vector3, Double> noiseGetter;
/** /**
* Instantiates a 3D ChunkInterpolator3D at a pair of chunk coordinates. * Instantiates a 3D ChunkInterpolator3D at a pair of chunk coordinates.
* *
@ -27,33 +29,36 @@ public class ChunkInterpolator2D implements ChunkInterpolator {
* @param chunkZ Z coordinate of the chunk. * @param chunkZ Z coordinate of the chunk.
* @param provider Biome Provider to use for biome fetching. * @param provider Biome Provider to use for biome fetching.
*/ */
public ChunkInterpolator2D(World w, int chunkX, int chunkZ, BiomeProvider provider, BiFunction<GenerationSettings, Vector3, Double> noiseGetter) { public ChunkInterpolator2D(World w, int chunkX, int chunkZ, BiomeProvider provider,
BiFunction<GenerationSettings, Vector3, Double> noiseGetter) {
this.noiseGetter = noiseGetter; this.noiseGetter = noiseGetter;
int xOrigin = chunkX << 4; int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4; int zOrigin = chunkZ << 4;
long seed = w.getSeed(); long seed = w.getSeed();
double[][] noiseStorage = new double[5][5]; double[][] noiseStorage = new double[5][5];
for(int x = 0; x < 5; x++) { for(int x = 0; x < 5; x++) {
for(int z = 0; z < 5; z++) { for(int z = 0; z < 5; z++) {
GenerationSettings generationSettings = provider.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), seed).getGenerator(); GenerationSettings generationSettings = provider.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), seed).getGenerator();
Map<GenerationSettings, MutableInteger> genMap = new HashMap<>(); Map<GenerationSettings, MutableInteger> genMap = new HashMap<>();
int step = generationSettings.getBlendStep(); int step = generationSettings.getBlendStep();
int blend = generationSettings.getBlendDistance(); int blend = generationSettings.getBlendDistance();
for(int xi = -blend; xi <= blend; xi++) { for(int xi = -blend; xi <= blend; xi++) {
for(int zi = -blend; zi <= blend; zi++) { for(int zi = -blend; zi <= blend; zi++) {
genMap.computeIfAbsent(provider.getBiome(xOrigin + (x << 2) + (xi * step), zOrigin + (z << 2) + (zi * step), seed).getGenerator(), g -> new MutableInteger(0)).increment(); // Increment by 1 genMap.computeIfAbsent(
provider.getBiome(xOrigin + (x << 2) + (xi * step), zOrigin + (z << 2) + (zi * step), seed).getGenerator(),
g -> new MutableInteger(0)).increment(); // Increment by 1
} }
} }
noiseStorage[x][z] = computeNoise(genMap, (x << 2) + xOrigin, 0, (z << 2) + zOrigin); noiseStorage[x][z] = computeNoise(genMap, (x << 2) + xOrigin, 0, (z << 2) + zOrigin);
} }
} }
for(int x = 0; x < 4; x++) { for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) { for(int z = 0; z < 4; z++) {
interpGrid[x][z] = new Interpolator( interpGrid[x][z] = new Interpolator(
@ -64,27 +69,28 @@ public class ChunkInterpolator2D implements ChunkInterpolator {
} }
} }
} }
private static int reRange(int value, int high) { private static int reRange(int value, int high) {
return FastMath.max(FastMath.min(value, high), 0); return FastMath.max(FastMath.min(value, high), 0);
} }
public double computeNoise(GenerationSettings generationSettings, double x, double y, double z) { public double computeNoise(GenerationSettings generationSettings, double x, double y, double z) {
return noiseGetter.apply(generationSettings, new Vector3(x, y, z)); return noiseGetter.apply(generationSettings, new Vector3(x, y, z));
} }
/** /**
* Gets the noise at a pair of internal chunk coordinates. * Gets the noise at a pair of internal chunk coordinates.
* *
* @param x The internal X coordinate (0-15). * @param x The internal X coordinate (0-15).
* @param z The internal Z coordinate (0-15). * @param z The internal Z coordinate (0-15).
*
* @return double - The interpolated noise at the coordinates. * @return double - The interpolated noise at the coordinates.
*/ */
@Override @Override
public double getNoise(double x, double y, double z) { public double getNoise(double x, double y, double z) {
return interpGrid[reRange(((int) x) / 4, 3)][reRange(((int) z) / 4, 3)].bilerp((x % 4) / 4, (z % 4) / 4); return interpGrid[reRange(((int) x) / 4, 3)][reRange(((int) z) / 4, 3)].bilerp((x % 4) / 4, (z % 4) / 4);
} }
public double getNoise(int x, int y, int z) { public double getNoise(int x, int y, int z) {
return interpGrid[x / 4][z / 4].bilerp((double) (x % 4) / 4, (double) (z % 4) / 4); return interpGrid[x / 4][z / 4].bilerp((double) (x % 4) / 4, (double) (z % 4) / 4);
} }

View File

@ -1,16 +1,18 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation; package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import net.jafama.FastMath;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import com.dfsek.terra.api.util.mutable.MutableInteger; import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.api.vector.Vector3; import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World; import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.GenerationSettings; import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.generator.ChunkInterpolator; import com.dfsek.terra.api.world.generator.ChunkInterpolator;
import net.jafama.FastMath;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
/** /**
* Class to abstract away the Interpolators needed to generate a chunk.<br> * Class to abstract away the Interpolators needed to generate a chunk.<br>
@ -19,10 +21,10 @@ import java.util.function.BiFunction;
public class ChunkInterpolator3D implements ChunkInterpolator { public class ChunkInterpolator3D implements ChunkInterpolator {
private final Interpolator3[][][] interpGrid; private final Interpolator3[][][] interpGrid;
private final BiFunction<GenerationSettings, Vector3, Double> noiseGetter; private final BiFunction<GenerationSettings, Vector3, Double> noiseGetter;
private final int min; private final int min;
private final int max; private final int max;
/** /**
* Instantiates a 3D ChunkInterpolator3D at a pair of chunk coordinates. * Instantiates a 3D ChunkInterpolator3D at a pair of chunk coordinates.
* *
@ -30,43 +32,46 @@ public class ChunkInterpolator3D implements ChunkInterpolator {
* @param chunkZ Z coordinate of the chunk. * @param chunkZ Z coordinate of the chunk.
* @param provider Biome Provider to use for biome fetching. * @param provider Biome Provider to use for biome fetching.
*/ */
public ChunkInterpolator3D(World w, int chunkX, int chunkZ, BiomeProvider provider, BiFunction<GenerationSettings, Vector3, Double> noiseGetter) { public ChunkInterpolator3D(World w, int chunkX, int chunkZ, BiomeProvider provider,
BiFunction<GenerationSettings, Vector3, Double> noiseGetter) {
this.noiseGetter = noiseGetter; this.noiseGetter = noiseGetter;
int xOrigin = chunkX << 4; int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4; int zOrigin = chunkZ << 4;
this.max = w.getMaxHeight(); this.max = w.getMaxHeight();
this.min = w.getMinHeight(); this.min = w.getMinHeight();
int range = max - min + 1; int range = max - min + 1;
int size = range >> 2; int size = range >> 2;
interpGrid = new Interpolator3[4][size][4]; interpGrid = new Interpolator3[4][size][4];
double[][][] noiseStorage = new double[5][5][size + 1]; double[][][] noiseStorage = new double[5][5][size + 1];
long seed = w.getSeed(); long seed = w.getSeed();
for(int x = 0; x < 5; x++) { for(int x = 0; x < 5; x++) {
for(int z = 0; z < 5; z++) { for(int z = 0; z < 5; z++) {
GenerationSettings generationSettings = provider.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), seed).getGenerator(); GenerationSettings generationSettings = provider.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), seed).getGenerator();
Map<GenerationSettings, MutableInteger> genMap = new HashMap<>(); Map<GenerationSettings, MutableInteger> genMap = new HashMap<>();
int step = generationSettings.getBlendStep(); int step = generationSettings.getBlendStep();
int blend = generationSettings.getBlendDistance(); int blend = generationSettings.getBlendDistance();
for(int xi = -blend; xi <= blend; xi++) { for(int xi = -blend; xi <= blend; xi++) {
for(int zi = -blend; zi <= blend; zi++) { for(int zi = -blend; zi <= blend; zi++) {
genMap.computeIfAbsent(provider.getBiome(xOrigin + (x << 2) + (xi * step), zOrigin + (z << 2) + (zi * step), seed).getGenerator(), g -> new MutableInteger(0)).increment(); // Increment by 1 genMap.computeIfAbsent(
provider.getBiome(xOrigin + (x << 2) + (xi * step), zOrigin + (z << 2) + (zi * step), seed).getGenerator(),
g -> new MutableInteger(0)).increment(); // Increment by 1
} }
} }
for(int y = 0; y < size + 1; y++) { for(int y = 0; y < size + 1; y++) {
noiseStorage[x][z][y] = computeNoise(genMap, (x << 2) + xOrigin, (y << 2) + min, (z << 2) + zOrigin); noiseStorage[x][z][y] = computeNoise(genMap, (x << 2) + xOrigin, (y << 2) + min, (z << 2) + zOrigin);
} }
} }
} }
for(int x = 0; x < 4; x++) { for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) { for(int z = 0; z < 4; z++) {
for(int y = 0; y < size; y++) { for(int y = 0; y < size; y++) {
@ -83,27 +88,30 @@ public class ChunkInterpolator3D implements ChunkInterpolator {
} }
} }
} }
private static int reRange(int value, int high) { private static int reRange(int value, int high) {
return FastMath.max(FastMath.min(value, high), 0); return FastMath.max(FastMath.min(value, high), 0);
} }
public double computeNoise(GenerationSettings generationSettings, double x, double y, double z) { public double computeNoise(GenerationSettings generationSettings, double x, double y, double z) {
return noiseGetter.apply(generationSettings, new Vector3(x, y, z)); return noiseGetter.apply(generationSettings, new Vector3(x, y, z));
} }
/** /**
* Gets the noise at a pair of internal chunk coordinates. * Gets the noise at a pair of internal chunk coordinates.
* *
* @param x The internal X coordinate (0-15). * @param x The internal X coordinate (0-15).
* @param z The internal Z coordinate (0-15). * @param z The internal Z coordinate (0-15).
*
* @return double - The interpolated noise at the coordinates. * @return double - The interpolated noise at the coordinates.
*/ */
@Override @Override
public double getNoise(double x, double y, double z) { public double getNoise(double x, double y, double z) {
return interpGrid[reRange(((int) x) / 4, 3)][(FastMath.max(FastMath.min(((int) y), max), min) - min) / 4][reRange(((int) z) / 4, 3)].trilerp((x % 4) / 4, (y % 4) / 4, (z % 4) / 4); return interpGrid[reRange(((int) x) / 4, 3)][(FastMath.max(FastMath.min(((int) y), max), min) - min) / 4][reRange(((int) z) / 4,
3)].trilerp(
(x % 4) / 4, (y % 4) / 4, (z % 4) / 4);
} }
public double getNoise(int x, int y, int z) { public double getNoise(int x, int y, int z) {
return interpGrid[x / 4][(y - min) / 4][z / 4].trilerp((double) (x % 4) / 4, (double) (y % 4) / 4, (double) (z % 4) / 4); return interpGrid[x / 4][(y - min) / 4][z / 4].trilerp((double) (x % 4) / 4, (double) (y % 4) / 4, (double) (z % 4) / 4);
} }

View File

@ -4,24 +4,25 @@ import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.GenerationSettings; import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class ElevationInterpolator { public class ElevationInterpolator {
private final double[][] values = new double[18][18]; private final double[][] values = new double[18][18];
public ElevationInterpolator(World world, int chunkX, int chunkZ, BiomeProvider provider, int smooth) { public ElevationInterpolator(World world, int chunkX, int chunkZ, BiomeProvider provider, int smooth) {
int xOrigin = chunkX << 4; int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4; int zOrigin = chunkZ << 4;
long seed = world.getSeed(); long seed = world.getSeed();
GenerationSettings[][] gens = new GenerationSettings[18 + 2 * smooth][18 + 2 * smooth]; GenerationSettings[][] gens = new GenerationSettings[18 + 2 * smooth][18 + 2 * smooth];
// Precompute generators. // Precompute generators.
for(int x = -1 - smooth; x <= 16 + smooth; x++) { for(int x = -1 - smooth; x <= 16 + smooth; x++) {
for(int z = -1 - smooth; z <= 16 + smooth; z++) { for(int z = -1 - smooth; z <= 16 + smooth; z++) {
gens[x + 1 + smooth][z + 1 + smooth] = provider.getBiome(xOrigin + x, zOrigin + z, seed).getGenerator(); gens[x + 1 + smooth][z + 1 + smooth] = provider.getBiome(xOrigin + x, zOrigin + z, seed).getGenerator();
} }
} }
for(int x = -1; x <= 16; x++) { for(int x = -1; x <= 16; x++) {
for(int z = -1; z <= 16; z++) { for(int z = -1; z <= 16; z++) {
double noise = 0; double noise = 0;
@ -37,7 +38,7 @@ public class ElevationInterpolator {
} }
} }
} }
public double getElevation(int x, int z) { public double getElevation(int x, int z) {
return values[x + 1][z + 1]; return values[x + 1][z + 1];
} }

View File

@ -5,7 +5,7 @@ package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
*/ */
public class Interpolator { public class Interpolator {
private final double v0, v1, v2, v3; private final double v0, v1, v2, v3;
/** /**
* Constructs an interpolator with given values as vertices of a unit square. * Constructs an interpolator with given values as vertices of a unit square.
* *
@ -20,24 +20,26 @@ public class Interpolator {
this.v2 = v2; this.v2 = v2;
this.v3 = v3; this.v3 = v3;
} }
/** /**
* 1D Linear interpolation between 2 points 1 unit apart. * 1D Linear interpolation between 2 points 1 unit apart.
* *
* @param t - Distance from v0. Total distance between v0 and v1 is 1 unit. * @param t - Distance from v0. Total distance between v0 and v1 is 1 unit.
* @param v0 - Value at v0. * @param v0 - Value at v0.
* @param v1 - Value at v1. * @param v1 - Value at v1.
*
* @return double - The interpolated value. * @return double - The interpolated value.
*/ */
public static double lerp(double t, double v0, double v1) { public static double lerp(double t, double v0, double v1) {
return v0 + t * (v1 - v0); return v0 + t * (v1 - v0);
} }
/** /**
* 2D Bilinear interpolation between 4 points on a unit square. * 2D Bilinear interpolation between 4 points on a unit square.
* *
* @param s - X value * @param s - X value
* @param t - Z value * @param t - Z value
*
* @return double - The interpolated value. * @return double - The interpolated value.
*/ */
public double bilerp(double s, double t) { public double bilerp(double s, double t) {

View File

@ -6,7 +6,7 @@ package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
public class Interpolator3 { public class Interpolator3 {
private final Interpolator bottom; private final Interpolator bottom;
private final Interpolator top; private final Interpolator top;
/** /**
* Constructs an interpolator with given values as vertices of a unit cube. * Constructs an interpolator with given values as vertices of a unit cube.
* * @param _000 The value at <code>(t, u, v) = (0, 0, 0)</code>. * * @param _000 The value at <code>(t, u, v) = (0, 0, 0)</code>.
@ -25,7 +25,7 @@ public class Interpolator3 {
this.top = new Interpolator(_000, _010, _001, _011); this.top = new Interpolator(_000, _010, _001, _011);
this.bottom = new Interpolator(_100, _110, _101, _111); this.bottom = new Interpolator(_100, _110, _101, _111);
} }
public double trilerp(double x, double y, double z) { public double trilerp(double x, double y, double z) {
return Interpolator.lerp(x, top.bilerp(y, z), bottom.bilerp(y, z)); return Interpolator.lerp(x, top.bilerp(y, z), bottom.bilerp(y, z));
} }

View File

@ -1,26 +1,30 @@
package com.dfsek.terra.addons.chunkgenerator.generation.math.samplers; package com.dfsek.terra.addons.chunkgenerator.generation.math.samplers;
import net.jafama.FastMath;
import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.ChunkInterpolator3D; import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.ChunkInterpolator3D;
import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.ElevationInterpolator; import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.ElevationInterpolator;
import com.dfsek.terra.api.world.World; import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.generator.Sampler; import com.dfsek.terra.api.world.generator.Sampler;
import net.jafama.FastMath;
public class Sampler3D implements Sampler { public class Sampler3D implements Sampler {
private final ChunkInterpolator3D interpolator; private final ChunkInterpolator3D interpolator;
private final ElevationInterpolator elevationInterpolator; private final ElevationInterpolator elevationInterpolator;
public Sampler3D(int x, int z, BiomeProvider provider, World world, int elevationSmooth) { public Sampler3D(int x, int z, BiomeProvider provider, World world, int elevationSmooth) {
this.interpolator = new ChunkInterpolator3D(world, x, z, provider, (generator, coord) -> generator.getBaseSampler().getNoiseSeeded(coord, world.getSeed())); this.interpolator = new ChunkInterpolator3D(world, x, z, provider, (generator, coord) -> generator.getBaseSampler()
.getNoiseSeeded(coord,
world.getSeed()));
this.elevationInterpolator = new ElevationInterpolator(world, x, z, provider, elevationSmooth); this.elevationInterpolator = new ElevationInterpolator(world, x, z, provider, elevationSmooth);
} }
@Override @Override
public double sample(double x, double y, double z) { public double sample(double x, double y, double z) {
return interpolator.getNoise(x, y, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z)); return interpolator.getNoise(x, y, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z));
} }
@Override @Override
public double sample(int x, int y, int z) { public double sample(int x, int y, int z) {
return interpolator.getNoise(x, y, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z)); return interpolator.getNoise(x, y, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z));

View File

@ -2,21 +2,22 @@ package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.terra.api.world.generator.Palette; import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolder { public class PaletteHolder {
private final Palette[] palettes; private final Palette[] palettes;
private final int offset; private final int offset;
protected PaletteHolder(Palette[] palettes, int offset) { protected PaletteHolder(Palette[] palettes, int offset) {
this.palettes = palettes; this.palettes = palettes;
this.offset = offset; this.offset = offset;
} }
public Palette getPalette(int y) { public Palette getPalette(int y) {
int index = y + offset; int index = y + offset;
return index >= 0 return index >= 0
? index < palettes.length ? index < palettes.length
? palettes[index] ? palettes[index]
: palettes[palettes.length - 1] : palettes[palettes.length - 1]
: palettes[0]; : palettes[0];
} }
} }

View File

@ -1,24 +1,26 @@
package com.dfsek.terra.addons.chunkgenerator.palette; package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.terra.api.world.generator.Palette;
import net.jafama.FastMath; import net.jafama.FastMath;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolderBuilder { public class PaletteHolderBuilder {
private final TreeMap<Integer, Palette> paletteMap = new TreeMap<>(); private final TreeMap<Integer, Palette> paletteMap = new TreeMap<>();
public PaletteHolderBuilder add(int y, Palette palette) { public PaletteHolderBuilder add(int y, Palette palette) {
paletteMap.put(y, palette); paletteMap.put(y, palette);
return this; return this;
} }
public PaletteHolder build() { public PaletteHolder build() {
int min = FastMath.min(paletteMap.keySet().stream().min(Integer::compareTo).orElse(0), 0); int min = FastMath.min(paletteMap.keySet().stream().min(Integer::compareTo).orElse(0), 0);
int max = FastMath.max(paletteMap.keySet().stream().max(Integer::compareTo).orElse(255), 255); int max = FastMath.max(paletteMap.keySet().stream().max(Integer::compareTo).orElse(255), 255);
Palette[] palettes = new Palette[paletteMap.lastKey() + 1 - min]; Palette[] palettes = new Palette[paletteMap.lastKey() + 1 - min];
for(int y = min; y <= FastMath.max(paletteMap.lastKey(), max); y++) { for(int y = min; y <= FastMath.max(paletteMap.lastKey(), max); y++) {
Palette d = null; Palette d = null;

View File

@ -3,12 +3,14 @@ package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader; import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader; import com.dfsek.tectonic.loading.TypeLoader;
import com.dfsek.terra.api.world.generator.Palette;
import java.lang.reflect.AnnotatedType; import java.lang.reflect.AnnotatedType;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolderLoader implements TypeLoader<PaletteHolder> { public class PaletteHolderLoader implements TypeLoader<PaletteHolder> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override

View File

@ -3,32 +3,33 @@ package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.terra.api.properties.Properties; import com.dfsek.terra.api.properties.Properties;
import com.dfsek.terra.api.world.generator.Palette; import com.dfsek.terra.api.world.generator.Palette;
public class PaletteInfo implements Properties { public class PaletteInfo implements Properties {
private final PaletteHolder paletteHolder; private final PaletteHolder paletteHolder;
private final SlantHolder slantHolder; private final SlantHolder slantHolder;
private final Palette ocean; private final Palette ocean;
private final int seaLevel; private final int seaLevel;
public PaletteInfo(PaletteHolder paletteHolder, SlantHolder slantHolder, Palette ocean, int seaLevel) { public PaletteInfo(PaletteHolder paletteHolder, SlantHolder slantHolder, Palette ocean, int seaLevel) {
this.paletteHolder = paletteHolder; this.paletteHolder = paletteHolder;
this.slantHolder = slantHolder; this.slantHolder = slantHolder;
this.ocean = ocean; this.ocean = ocean;
this.seaLevel = seaLevel; this.seaLevel = seaLevel;
} }
public Palette getOcean() { public Palette getOcean() {
return ocean; return ocean;
} }
public PaletteHolder getPaletteHolder() { public PaletteHolder getPaletteHolder() {
return paletteHolder; return paletteHolder;
} }
public SlantHolder getSlantHolder() { public SlantHolder getSlantHolder() {
return slantHolder; return slantHolder;
} }
public int getSeaLevel() { public int getSeaLevel() {
return seaLevel; return seaLevel;
} }

View File

@ -3,19 +3,20 @@ package com.dfsek.terra.addons.chunkgenerator.palette;
import java.util.TreeMap; import java.util.TreeMap;
public class SlantHolder { public class SlantHolder {
private final TreeMap<Double, PaletteHolder> layers; private final TreeMap<Double, PaletteHolder> layers;
private final double minSlope; private final double minSlope;
public SlantHolder(TreeMap<Double, PaletteHolder> layers, double minSlope) { public SlantHolder(TreeMap<Double, PaletteHolder> layers, double minSlope) {
this.layers = layers; this.layers = layers;
this.minSlope = minSlope; this.minSlope = minSlope;
} }
public PaletteHolder getPalette(double slope) { public PaletteHolder getPalette(double slope) {
return layers.floorEntry(slope).getValue(); return layers.floorEntry(slope).getValue();
} }
public double getMinSlope() { public double getMinSlope() {
return minSlope; return minSlope;
} }

View File

@ -9,6 +9,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class SlantHolderLoader implements TypeLoader<SlantHolder> { public class SlantHolderLoader implements TypeLoader<SlantHolder> {
@Override @Override
@ -16,13 +17,13 @@ public class SlantHolderLoader implements TypeLoader<SlantHolder> {
List<Map<Object, Object>> layers = (List<Map<Object, Object>>) o; List<Map<Object, Object>> layers = (List<Map<Object, Object>>) o;
TreeMap<Double, PaletteHolder> slantLayers = new TreeMap<>(); TreeMap<Double, PaletteHolder> slantLayers = new TreeMap<>();
double minThreshold = Double.MAX_VALUE; double minThreshold = Double.MAX_VALUE;
for(Map<Object, Object> layer : layers) { for(Map<Object, Object> layer : layers) {
double threshold = ((Number) layer.get("threshold")).doubleValue(); double threshold = ((Number) layer.get("threshold")).doubleValue();
if(threshold < minThreshold) minThreshold = threshold; if(threshold < minThreshold) minThreshold = threshold;
slantLayers.put(threshold, configLoader.loadType(PaletteHolder.class, layer.get("palette"))); slantLayers.put(threshold, configLoader.loadType(PaletteHolder.class, layer.get("palette")));
} }
return new SlantHolder(slantLayers, minThreshold); return new SlantHolder(slantLayers, minThreshold);
} }
} }

View File

@ -11,22 +11,23 @@ import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
@Addon("config-biome") @Addon("config-biome")
@Author("Terra") @Author("Terra")
@Version("1.0.0") @Version("1.0.0")
public class BiomeAddon extends TerraAddon { public class BiomeAddon extends TerraAddon {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager() main.getEventManager()
.getHandler(FunctionalEventHandler.class) .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class) .register(this, ConfigPackPreLoadEvent.class)
.then(event -> { .then(event -> {
event.getPack().registerConfigType(new BiomeConfigType(event.getPack()), "BIOME", 5); event.getPack().registerConfigType(new BiomeConfigType(event.getPack()), "BIOME", 5);
event.getPack().applyLoader(PaletteHolder.class, new PaletteHolderLoader()); event.getPack().applyLoader(PaletteHolder.class, new PaletteHolderLoader());
}) })
.failThrough(); .failThrough();
} }
} }

View File

@ -2,6 +2,9 @@ package com.dfsek.terra.addons.biome;
import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.TypeLoader; import com.dfsek.tectonic.loading.TypeLoader;
import java.util.function.Supplier;
import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.config.ConfigFactory; import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
@ -10,32 +13,16 @@ import com.dfsek.terra.api.registry.OpenRegistry;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import java.util.function.Supplier;
public class BiomeConfigType implements ConfigType<BiomeTemplate, TerraBiome> { public class BiomeConfigType implements ConfigType<BiomeTemplate, TerraBiome> {
public static final TypeKey<TerraBiome> BIOME_TYPE_TOKEN = new TypeKey<>() {
};
private final BiomeFactory factory; private final BiomeFactory factory;
public static final TypeKey<TerraBiome> BIOME_TYPE_TOKEN = new TypeKey<>() {};
public BiomeConfigType(ConfigPack pack) { public BiomeConfigType(ConfigPack pack) {
this.factory = new BiomeFactory(pack); this.factory = new BiomeFactory(pack);
} }
@Override
public BiomeTemplate getTemplate(ConfigPack pack, TerraPlugin main) {
return new BiomeTemplate(pack, main);
}
@Override
public ConfigFactory<BiomeTemplate, TerraBiome> getFactory() {
return factory;
}
@Override
public TypeKey<TerraBiome> getTypeKey() {
return BIOME_TYPE_TOKEN;
}
@Override @Override
public Supplier<OpenRegistry<TerraBiome>> registrySupplier(ConfigPack pack) { public Supplier<OpenRegistry<TerraBiome>> registrySupplier(ConfigPack pack) {
return () -> pack.getRegistryFactory().create(registry -> (TypeLoader<TerraBiome>) (t, c, loader) -> { return () -> pack.getRegistryFactory().create(registry -> (TypeLoader<TerraBiome>) (t, c, loader) -> {
@ -46,4 +33,19 @@ public class BiomeConfigType implements ConfigType<BiomeTemplate, TerraBiome> {
return obj; return obj;
}); });
} }
@Override
public BiomeTemplate getTemplate(ConfigPack pack, TerraPlugin main) {
return new BiomeTemplate(pack, main);
}
@Override
public ConfigFactory<BiomeTemplate, TerraBiome> getFactory() {
return factory;
}
@Override
public TypeKey<TerraBiome> getTypeKey() {
return BIOME_TYPE_TOKEN;
}
} }

View File

@ -5,17 +5,22 @@ import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
public class BiomeFactory implements ConfigFactory<BiomeTemplate, TerraBiome> { public class BiomeFactory implements ConfigFactory<BiomeTemplate, TerraBiome> {
private final ConfigPack pack; private final ConfigPack pack;
public BiomeFactory(ConfigPack pack) { public BiomeFactory(ConfigPack pack) {
this.pack = pack; this.pack = pack;
} }
@Override @Override
public TerraBiome build(BiomeTemplate template, TerraPlugin main) { public TerraBiome build(BiomeTemplate template, TerraPlugin main) {
UserDefinedGenerationSettings generator = new UserDefinedGenerationSettings(template.getNoiseEquation(), template.getElevationEquation(), template.getCarvingEquation(), template.getBiomeNoise(), template.getElevationWeight(), UserDefinedGenerationSettings generator = new UserDefinedGenerationSettings(template.getNoiseEquation(),
template.getBlendDistance(), template.getBlendStep(), template.getBlendWeight()); template.getElevationEquation(),
template.getCarvingEquation(), template.getBiomeNoise(),
template.getElevationWeight(),
template.getBlendDistance(), template.getBlendStep(),
template.getBlendWeight());
return new UserDefinedBiome(template.getVanilla(), generator, template); return new UserDefinedBiome(template.getVanilla(), generator, template);
} }
} }

View File

@ -5,6 +5,14 @@ import com.dfsek.tectonic.annotations.Final;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ValidatedConfigTemplate; import com.dfsek.tectonic.config.ValidatedConfigTemplate;
import com.dfsek.tectonic.exception.ValidationException; import com.dfsek.tectonic.exception.ValidationException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.block.BlockType; import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.config.AbstractableTemplate; import com.dfsek.terra.api.config.AbstractableTemplate;
@ -15,196 +23,191 @@ import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.generator.Palette; import com.dfsek.terra.api.world.generator.Palette;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SuppressWarnings({"FieldMayBeFinal", "unused"}) @SuppressWarnings({ "FieldMayBeFinal", "unused" })
public class BiomeTemplate implements AbstractableTemplate, ValidatedConfigTemplate { public class BiomeTemplate implements AbstractableTemplate, ValidatedConfigTemplate {
private final ConfigPack pack; private final ConfigPack pack;
@Value("id") @Value("id")
@Final @Final
private @Meta String id; private @Meta String id;
@Value("extends") @Value("extends")
@Final @Final
@Default @Default
private List<String> extended = Collections.emptyList(); private List<String> extended = Collections.emptyList();
@Value("variables") @Value("variables")
@Default @Default
private @Meta Map<String, @Meta Double> variables = new HashMap<>(); private @Meta Map<String, @Meta Double> variables = new HashMap<>();
@Value("beta.carving.equation") @Value("beta.carving.equation")
@Default @Default
private @Meta NoiseSampler carvingEquation = NoiseSampler.zero(); private @Meta NoiseSampler carvingEquation = NoiseSampler.zero();
@Value("vanilla") @Value("vanilla")
private @Meta ProbabilityCollection<Biome> vanilla; private @Meta ProbabilityCollection<Biome> vanilla;
@Value("biome-noise") @Value("biome-noise")
@Default @Default
private @Meta NoiseSampler biomeNoise = NoiseSampler.zero(); private @Meta NoiseSampler biomeNoise = NoiseSampler.zero();
@Value("blend.distance") @Value("blend.distance")
@Default @Default
private @Meta int blendDistance = 3; private @Meta int blendDistance = 3;
@Value("blend.weight") @Value("blend.weight")
@Default @Default
private @Meta double blendWeight = 1; private @Meta double blendWeight = 1;
@Value("blend.step") @Value("blend.step")
@Default @Default
private @Meta int blendStep = 4; private @Meta int blendStep = 4;
@Value("noise") @Value("noise")
private @Meta NoiseSampler noiseEquation; private @Meta NoiseSampler noiseEquation;
@Value("ocean.level") @Value("ocean.level")
@Default @Default
private @Meta int seaLevel = 62; private @Meta int seaLevel = 62;
@Value("elevation.equation") @Value("elevation.equation")
@Default @Default
private @Meta NoiseSampler elevationEquation = NoiseSampler.zero(); private @Meta NoiseSampler elevationEquation = NoiseSampler.zero();
@Value("elevation.weight") @Value("elevation.weight")
@Default @Default
private @Meta double elevationWeight = 1; private @Meta double elevationWeight = 1;
@Value("slabs.enable") @Value("slabs.enable")
@Default @Default
private @Meta boolean doSlabs = false; private @Meta boolean doSlabs = false;
@Value("slabs.threshold") @Value("slabs.threshold")
@Default @Default
private @Meta double slabThreshold = 0.0075D; private @Meta double slabThreshold = 0.0075D;
@Value("slabs.palettes") @Value("slabs.palettes")
@Default @Default
private @Meta Map<@Meta BlockType, @Meta Palette> slabPalettes; private @Meta Map<@Meta BlockType, @Meta Palette> slabPalettes;
@Value("slabs.stair-palettes") @Value("slabs.stair-palettes")
@Default @Default
private @Meta Map<@Meta BlockType, @Meta Palette> stairPalettes; private @Meta Map<@Meta BlockType, @Meta Palette> stairPalettes;
@Value("interpolate-elevation") @Value("interpolate-elevation")
@Default @Default
private @Meta boolean interpolateElevation = true; private @Meta boolean interpolateElevation = true;
@Value("color") @Value("color")
@Final @Final
@Default @Default
private @Meta int color = 0; private @Meta int color = 0;
@Value("tags") @Value("tags")
@Default @Default
private @Meta Set<@Meta String> tags = new HashSet<>(); private @Meta Set<@Meta String> tags = new HashSet<>();
@Value("colors") @Value("colors")
@Default @Default
private @Meta Map<String, @Meta Integer> colors = new HashMap<>(); // Plain ol' map, so platforms can decide what to do with colors (if anything). private @Meta Map<String, @Meta Integer> colors = new HashMap<>();
// Plain ol' map, so platforms can decide what to do with colors (if anything).
public BiomeTemplate(ConfigPack pack, TerraPlugin main) { public BiomeTemplate(ConfigPack pack, TerraPlugin main) {
this.pack = pack; this.pack = pack;
} }
public List<String> getExtended() {
return extended;
}
public Set<String> getTags() {
return tags;
}
public Map<String, Integer> getColors() {
return colors;
}
public double getBlendWeight() {
return blendWeight;
}
public int getColor() {
return color;
}
public int getBlendDistance() {
return blendDistance;
}
public boolean interpolateElevation() { public boolean interpolateElevation() {
return interpolateElevation; return interpolateElevation;
} }
public double getSlabThreshold() {
return slabThreshold;
}
public boolean doSlabs() { public boolean doSlabs() {
return doSlabs; return doSlabs;
} }
public Map<BlockType, Palette> getSlabPalettes() {
return slabPalettes;
}
public Map<BlockType, Palette> getStairPalettes() {
return stairPalettes;
}
public NoiseSampler getBiomeNoise() {
return biomeNoise;
}
public NoiseSampler getElevationEquation() {
return elevationEquation;
}
public NoiseSampler getCarvingEquation() {
return carvingEquation;
}
public ConfigPack getPack() {
return pack;
}
public int getSeaLevel() {
return seaLevel;
}
public String getID() {
return id;
}
public ProbabilityCollection<Biome> getVanilla() {
return vanilla;
}
public NoiseSampler getNoiseEquation() {
return noiseEquation;
}
public double getElevationWeight() {
return elevationWeight;
}
public int getBlendStep() {
return blendStep;
}
public Map<String, Double> getVariables() {
return variables;
}
@Override @Override
public boolean validate() throws ValidationException { public boolean validate() throws ValidationException {
color |= 0xff000000; // Alpha adjustment color |= 0xff000000; // Alpha adjustment
return true; return true;
} }
public List<String> getExtended() {
return extended;
}
public Set<String> getTags() {
return tags;
}
public Map<String, Integer> getColors() {
return colors;
}
public double getBlendWeight() {
return blendWeight;
}
public int getColor() {
return color;
}
public int getBlendDistance() {
return blendDistance;
}
public double getSlabThreshold() {
return slabThreshold;
}
public Map<BlockType, Palette> getSlabPalettes() {
return slabPalettes;
}
public Map<BlockType, Palette> getStairPalettes() {
return stairPalettes;
}
public NoiseSampler getBiomeNoise() {
return biomeNoise;
}
public NoiseSampler getElevationEquation() {
return elevationEquation;
}
public NoiseSampler getCarvingEquation() {
return carvingEquation;
}
public ConfigPack getPack() {
return pack;
}
public int getSeaLevel() {
return seaLevel;
}
public String getID() {
return id;
}
public ProbabilityCollection<Biome> getVanilla() {
return vanilla;
}
public NoiseSampler getNoiseEquation() {
return noiseEquation;
}
public double getElevationWeight() {
return elevationWeight;
}
public int getBlendStep() {
return blendStep;
}
public Map<String, Double> getVariables() {
return variables;
}
} }

View File

@ -3,23 +3,24 @@ package com.dfsek.terra.addons.biome;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction; import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
public class BlankFunction implements DynamicFunction { public class BlankFunction implements DynamicFunction {
private final int args; private final int args;
public BlankFunction(int args) { public BlankFunction(int args) {
this.args = args; this.args = args;
} }
@Override
public int getArgNumber() {
return args;
}
@Override @Override
public double eval(double... d) { public double eval(double... d) {
return 0; return 0;
} }
@Override
public int getArgNumber() {
return args;
}
@Override @Override
public boolean isStateless() { public boolean isStateless() {
return true; return true;

View File

@ -4,13 +4,14 @@ import com.dfsek.terra.addons.biome.holder.PaletteHolder;
import com.dfsek.terra.api.world.biome.PaletteSettings; import com.dfsek.terra.api.world.biome.PaletteSettings;
import com.dfsek.terra.api.world.generator.Palette; import com.dfsek.terra.api.world.generator.Palette;
public class PaletteSettingsImpl implements PaletteSettings { public class PaletteSettingsImpl implements PaletteSettings {
private final PaletteHolder palette; private final PaletteHolder palette;
public PaletteSettingsImpl(PaletteHolder palette) { public PaletteSettingsImpl(PaletteHolder palette) {
this.palette = palette; this.palette = palette;
} }
@Override @Override
public Palette getPalette(int y) { public Palette getPalette(int y) {
return palette.getPalette(y); return palette.getPalette(y);

View File

@ -1,12 +1,13 @@
package com.dfsek.terra.addons.biome; package com.dfsek.terra.addons.biome;
import java.util.Set;
import com.dfsek.terra.api.properties.Context; import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.GenerationSettings; import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import java.util.Set;
/** /**
* Class representing a config-defined biome * Class representing a config-defined biome
@ -18,9 +19,9 @@ public class UserDefinedBiome implements TerraBiome {
private final BiomeTemplate config; private final BiomeTemplate config;
private final int color; private final int color;
private final Set<String> tags; private final Set<String> tags;
private final Context context = new Context(); private final Context context = new Context();
public UserDefinedBiome(ProbabilityCollection<Biome> vanilla, UserDefinedGenerationSettings gen, BiomeTemplate config) { public UserDefinedBiome(ProbabilityCollection<Biome> vanilla, UserDefinedGenerationSettings gen, BiomeTemplate config) {
this.vanilla = vanilla; this.vanilla = vanilla;
this.gen = gen; this.gen = gen;
@ -30,7 +31,12 @@ public class UserDefinedBiome implements TerraBiome {
this.tags = config.getTags(); this.tags = config.getTags();
tags.add("BIOME:" + id); tags.add("BIOME:" + id);
} }
@Override
public String toString() {
return "{BIOME:" + getID() + "}";
}
/** /**
* Gets the Vanilla biomes to represent the custom biome. * Gets the Vanilla biomes to represent the custom biome.
* *
@ -40,36 +46,31 @@ public class UserDefinedBiome implements TerraBiome {
public ProbabilityCollection<Biome> getVanillaBiomes() { public ProbabilityCollection<Biome> getVanillaBiomes() {
return vanilla; return vanilla;
} }
@Override
public String getID() {
return id;
}
public BiomeTemplate getConfig() {
return config;
}
@Override @Override
public GenerationSettings getGenerator() { public GenerationSettings getGenerator() {
return gen; return gen;
} }
@Override @Override
public int getColor() { public int getColor() {
return color; return color;
} }
@Override @Override
public Set<String> getTags() { public Set<String> getTags() {
return tags; return tags;
} }
@Override @Override
public String toString() { public String getID() {
return "{BIOME:" + getID() + "}"; return id;
} }
public BiomeTemplate getConfig() {
return config;
}
@Override @Override
public Context getContext() { public Context getContext() {
return context; return context;

View File

@ -3,65 +3,67 @@ package com.dfsek.terra.addons.biome;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.world.biome.GenerationSettings; import com.dfsek.terra.api.world.biome.GenerationSettings;
public class UserDefinedGenerationSettings implements GenerationSettings {
public class UserDefinedGenerationSettings implements GenerationSettings {
private final NoiseSampler noise; private final NoiseSampler noise;
private final NoiseSampler elevation; private final NoiseSampler elevation;
private final NoiseSampler carving; private final NoiseSampler carving;
private final NoiseSampler biomeNoise; private final NoiseSampler biomeNoise;
private final double elevationWeight; private final double elevationWeight;
private final int blendDistance; private final int blendDistance;
private final int blendStep; private final int blendStep;
private final double blendWeight; private final double blendWeight;
public UserDefinedGenerationSettings(NoiseSampler noise, NoiseSampler elevation, NoiseSampler carving, NoiseSampler biomeNoise, double elevationWeight, int blendDistance, int blendStep, double blendWeight) { public UserDefinedGenerationSettings(NoiseSampler noise, NoiseSampler elevation, NoiseSampler carving, NoiseSampler biomeNoise,
double elevationWeight, int blendDistance, int blendStep, double blendWeight) {
this.noise = noise; this.noise = noise;
this.elevation = elevation; this.elevation = elevation;
this.carving = carving; this.carving = carving;
this.biomeNoise = biomeNoise; this.biomeNoise = biomeNoise;
this.elevationWeight = elevationWeight; this.elevationWeight = elevationWeight;
this.blendDistance = blendDistance; this.blendDistance = blendDistance;
this.blendStep = blendStep; this.blendStep = blendStep;
this.blendWeight = blendWeight; this.blendWeight = blendWeight;
} }
@Override @Override
public NoiseSampler getBaseSampler() { public NoiseSampler getBaseSampler() {
return noise; return noise;
} }
@Override @Override
public NoiseSampler getElevationSampler() { public NoiseSampler getElevationSampler() {
return elevation; return elevation;
} }
@Override @Override
public NoiseSampler getCarver() { public NoiseSampler getCarver() {
return carving; return carving;
} }
@Override @Override
public int getBlendDistance() { public int getBlendDistance() {
return blendDistance; return blendDistance;
} }
@Override @Override
public double getWeight() { public double getWeight() {
return blendWeight; return blendWeight;
} }
@Override @Override
public NoiseSampler getBiomeNoise() { public NoiseSampler getBiomeNoise() {
return biomeNoise; return biomeNoise;
} }
@Override @Override
public double getElevationWeight() { public double getElevationWeight() {
return elevationWeight; return elevationWeight;
} }
@Override @Override
public int getBlendStep() { public int getBlendStep() {
return blendStep; return blendStep;

View File

@ -1,19 +1,21 @@
package com.dfsek.terra.addons.biome.command.biome; package com.dfsek.terra.addons.biome.command.biome;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.vector.Vector3; import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World; import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
/** /**
* Runnable that locates a biome asynchronously * Runnable that locates a biome asynchronously
*/ */
public class AsyncBiomeFinder implements Runnable { public class AsyncBiomeFinder implements Runnable {
protected final BiomeProvider provider; protected final BiomeProvider provider;
protected final TerraBiome target; protected final TerraBiome target;
protected final int startRadius; protected final int startRadius;
@ -24,8 +26,9 @@ public class AsyncBiomeFinder implements Runnable {
protected final TerraPlugin main; protected final TerraPlugin main;
private final Consumer<Vector3> callback; private final Consumer<Vector3> callback;
protected int searchSize = 1; protected int searchSize = 1;
public AsyncBiomeFinder(BiomeProvider provider, TerraBiome target, @NotNull Vector3 origin, World world, int startRadius, int maxRadius, Consumer<Vector3> callback, TerraPlugin main) { public AsyncBiomeFinder(BiomeProvider provider, TerraBiome target, @NotNull Vector3 origin, World world, int startRadius, int maxRadius,
Consumer<Vector3> callback, TerraPlugin main) {
this.provider = provider; this.provider = provider;
this.target = target; this.target = target;
this.main = main; this.main = main;
@ -36,35 +39,23 @@ public class AsyncBiomeFinder implements Runnable {
this.world = world; this.world = world;
this.callback = callback; this.callback = callback;
} }
/**
* Helper method to get biome at location
*
* @param x X coordinate
* @param z Z coordinate
* @return TerraBiome at coordinates
*/
public boolean isValid(int x, int z, TerraBiome target) {
int res = main.getTerraConfig().getBiomeSearchResolution();
return getProvider().getBiome(x * res, z * res, world.getSeed()).equals(target);
}
public Vector3 finalizeVector(Vector3 orig) { public Vector3 finalizeVector(Vector3 orig) {
return orig.multiply(main.getTerraConfig().getBiomeSearchResolution()); return orig.multiply(main.getTerraConfig().getBiomeSearchResolution());
} }
@Override @Override
public void run() { public void run() {
int x = centerX; int x = centerX;
int z = centerZ; int z = centerZ;
x /= searchSize; x /= searchSize;
z /= searchSize; z /= searchSize;
int run = 1; int run = 1;
boolean toggle = true; boolean toggle = true;
boolean found = false; boolean found = false;
main: main:
for(int i = startRadius; i < maxRadius; i++) { for(int i = startRadius; i < maxRadius; i++) {
for(int j = 0; j < run; j++) { for(int j = 0; j < run; j++) {
@ -89,23 +80,36 @@ public class AsyncBiomeFinder implements Runnable {
Vector3 finalSpawn = found ? finalizeVector(new Vector3(x, 0, z)) : null; Vector3 finalSpawn = found ? finalizeVector(new Vector3(x, 0, z)) : null;
callback.accept(finalSpawn); callback.accept(finalSpawn);
} }
/**
* Helper method to get biome at location
*
* @param x X coordinate
* @param z Z coordinate
*
* @return TerraBiome at coordinates
*/
public boolean isValid(int x, int z, TerraBiome target) {
int res = main.getTerraConfig().getBiomeSearchResolution();
return getProvider().getBiome(x * res, z * res, world.getSeed()).equals(target);
}
public TerraBiome getTarget() { public TerraBiome getTarget() {
return target; return target;
} }
public World getWorld() { public World getWorld() {
return world; return world;
} }
public BiomeProvider getProvider() { public BiomeProvider getProvider() {
return provider; return provider;
} }
public int getSearchSize() { public int getSearchSize() {
return searchSize; return searchSize;
} }
public void setSearchSize(int searchSize) { public void setSearchSize(int searchSize) {
this.searchSize = searchSize; this.searchSize = searchSize;
} }

View File

@ -12,18 +12,11 @@ import com.dfsek.terra.api.entity.Player;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@Command( @Command(
subcommands = { subcommands = {
@Subcommand( @Subcommand(value = "info", aliases = "i", clazz = BiomeInfoCommand.class),
value = "info", @Subcommand(value = "locate", aliases = "l", clazz = BiomeLocateCommand.class)
aliases = {"i"},
clazz = BiomeInfoCommand.class
),
@Subcommand(
value = "locate",
aliases = {"l"},
clazz = BiomeLocateCommand.class
)
}, },
usage = "/terra biome" usage = "/terra biome"
) )
@ -32,11 +25,11 @@ import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class BiomeCommand implements CommandTemplate { public class BiomeCommand implements CommandTemplate {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void execute(CommandSender sender) { public void execute(CommandSender sender) {
Player player = (Player) sender; Player player = (Player) sender;
BiomeProvider provider = player.world().getBiomeProvider(); BiomeProvider provider = player.world().getBiomeProvider();
UserDefinedBiome biome = (UserDefinedBiome) provider.getBiome(player.position(), player.world().getSeed()); UserDefinedBiome biome = (UserDefinedBiome) provider.getBiome(player.position(), player.world().getSeed());
sender.sendMessage("You are standing in " + biome.getID()); sender.sendMessage("You are standing in " + biome.getID());

View File

@ -11,27 +11,24 @@ import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
import com.dfsek.terra.api.entity.CommandSender; import com.dfsek.terra.api.entity.CommandSender;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
@Command(
arguments = { @Command(arguments = @Argument(
@Argument( value = "biome",
value = "biome", tabCompleter = BiomeTabCompleter.class,
tabCompleter = BiomeTabCompleter.class, argumentParser = BiomeArgumentParser.class
argumentParser = BiomeArgumentParser.class ))
)
}
)
public class BiomeInfoCommand implements CommandTemplate { public class BiomeInfoCommand implements CommandTemplate {
@ArgumentTarget("biome") @ArgumentTarget("biome")
private TerraBiome biome; private TerraBiome biome;
@Override @Override
public void execute(CommandSender sender) { public void execute(CommandSender sender) {
sender.sendMessage("Biome info for \"" + biome.getID() + "\"."); sender.sendMessage("Biome info for \"" + biome.getID() + "\".");
sender.sendMessage("Vanilla biome: " + biome.getVanillaBiomes()); sender.sendMessage("Vanilla biome: " + biome.getVanillaBiomes());
if(biome instanceof UserDefinedBiome) { if(biome instanceof UserDefinedBiome) {
BiomeTemplate bio = ((UserDefinedBiome) biome).getConfig(); BiomeTemplate bio = ((UserDefinedBiome) biome).getConfig();
if(bio.getExtended().size() == 0) { if(bio.getExtended().size() == 0) {
sender.sendMessage("No Parent Biomes"); sender.sendMessage("No Parent Biomes");
} else { } else {

View File

@ -1,5 +1,7 @@
package com.dfsek.terra.addons.biome.command.biome; package com.dfsek.terra.addons.biome.command.biome;
import java.util.Locale;
import com.dfsek.terra.addons.biome.command.biome.arg.BiomeArgumentParser; import com.dfsek.terra.addons.biome.command.biome.arg.BiomeArgumentParser;
import com.dfsek.terra.addons.biome.command.biome.tab.BiomeTabCompleter; import com.dfsek.terra.addons.biome.command.biome.tab.BiomeTabCompleter;
import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.TerraPlugin;
@ -18,58 +20,58 @@ import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.vector.Vector3; import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import java.util.Locale;
@PlayerCommand @PlayerCommand
@WorldCommand @WorldCommand
@Command( @Command(arguments = {
arguments = { @Argument(
@Argument( value = "biome",
value = "biome", tabCompleter = BiomeTabCompleter.class,
tabCompleter = BiomeTabCompleter.class, argumentParser = BiomeArgumentParser.class
argumentParser = BiomeArgumentParser.class ),
), @Argument(
@Argument( value = "radius",
value = "radius", required = false,
required = false, defaultValue = "1000",
defaultValue = "1000", argumentParser = IntegerArgumentParser.class
argumentParser = IntegerArgumentParser.class )
) }, switches = @Switch(
}, value = "teleport",
switches = { aliases = { "t", "tp" }
@Switch( ))
value = "teleport",
aliases = {"t", "tp"}
)
}
)
public class BiomeLocateCommand implements CommandTemplate { public class BiomeLocateCommand implements CommandTemplate {
@ArgumentTarget("radius") @ArgumentTarget("radius")
private Integer radius; private Integer radius;
@ArgumentTarget("biome") @ArgumentTarget("biome")
private TerraBiome biome; private TerraBiome biome;
@SwitchTarget("teleport") @SwitchTarget("teleport")
private boolean teleport; private boolean teleport;
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void execute(CommandSender sender) { public void execute(CommandSender sender) {
Player player = (Player) sender; Player player = (Player) sender;
new Thread(new AsyncBiomeFinder(player.world().getBiomeProvider(), biome, player.position().clone().multiply((1D / main.getTerraConfig().getBiomeSearchResolution())), player.world(), 0, radius, location -> { new Thread(new AsyncBiomeFinder(player.world().getBiomeProvider(), biome,
player.position().clone().multiply((1D / main.getTerraConfig().getBiomeSearchResolution())),
player.world(), 0, radius, location -> {
if(location != null) { if(location != null) {
sender.sendMessage(String.format("The nearest %s is at [%d, ~, %d] (%.1f blocks away)", biome.getID().toLowerCase(Locale.ROOT), location.getBlockX(), location.getBlockZ(), location.add(new Vector3(0, player.position().getY(), 0)).distance(player.position()))); sender.sendMessage(
String.format("The nearest %s is at [%d, ~, %d] (%.1f blocks away)", biome.getID().toLowerCase(Locale.ROOT),
location.getBlockX(), location.getBlockZ(),
location.add(new Vector3(0, player.position().getY(), 0)).distance(player.position())));
if(teleport) { if(teleport) {
main.runPossiblyUnsafeTask(() -> player.position(new Vector3(location.getX(), player.position().getY(), location.getZ()))); main.runPossiblyUnsafeTask(
() -> player.position(new Vector3(location.getX(), player.position().getY(), location.getZ())));
} }
} else sender.sendMessage("Unable to locate biome \"" + biome.getID() + "\""); } else sender.sendMessage("Unable to locate biome \"" + biome.getID() + "\"");
}, main), "Biome Location Thread").start(); }, main), "Biome Location Thread").start();
} }
} }

View File

@ -7,10 +7,11 @@ import com.dfsek.terra.api.entity.Player;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
public class BiomeArgumentParser implements ArgumentParser<TerraBiome> { public class BiomeArgumentParser implements ArgumentParser<TerraBiome> {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public TerraBiome parse(CommandSender sender, String arg) { public TerraBiome parse(CommandSender sender, String arg) {
Player player = (Player) sender; Player player = (Player) sender;

View File

@ -1,5 +1,8 @@
package com.dfsek.terra.addons.biome.command.biome.tab; package com.dfsek.terra.addons.biome.command.biome.tab;
import java.util.List;
import java.util.stream.Collectors;
import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.command.tab.TabCompleter; import com.dfsek.terra.api.command.tab.TabCompleter;
import com.dfsek.terra.api.entity.CommandSender; import com.dfsek.terra.api.entity.CommandSender;
@ -7,16 +10,15 @@ import com.dfsek.terra.api.entity.Player;
import com.dfsek.terra.api.injection.annotations.Inject; import com.dfsek.terra.api.injection.annotations.Inject;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import java.util.List;
import java.util.stream.Collectors;
public class BiomeTabCompleter implements TabCompleter { public class BiomeTabCompleter implements TabCompleter {
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public List<String> complete(CommandSender sender) { public List<String> complete(CommandSender sender) {
Player player = (Player) sender; Player player = (Player) sender;
return player.world().getConfig().getRegistry(TerraBiome.class).entries().stream().map(TerraBiome::getID).collect(Collectors.toList()); return player.world().getConfig().getRegistry(TerraBiome.class).entries().stream().map(TerraBiome::getID).collect(
Collectors.toList());
} }
} }

View File

@ -2,21 +2,22 @@ package com.dfsek.terra.addons.biome.holder;
import com.dfsek.terra.api.world.generator.Palette; import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolder { public class PaletteHolder {
private final Palette[] palettes; private final Palette[] palettes;
private final int offset; private final int offset;
protected PaletteHolder(Palette[] palettes, int offset) { protected PaletteHolder(Palette[] palettes, int offset) {
this.palettes = palettes; this.palettes = palettes;
this.offset = offset; this.offset = offset;
} }
public Palette getPalette(int y) { public Palette getPalette(int y) {
int index = y + offset; int index = y + offset;
return index >= 0 return index >= 0
? index < palettes.length ? index < palettes.length
? palettes[index] ? palettes[index]
: palettes[palettes.length - 1] : palettes[palettes.length - 1]
: palettes[0]; : palettes[0];
} }
} }

View File

@ -1,24 +1,26 @@
package com.dfsek.terra.addons.biome.holder; package com.dfsek.terra.addons.biome.holder;
import com.dfsek.terra.api.world.generator.Palette;
import net.jafama.FastMath; import net.jafama.FastMath;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolderBuilder { public class PaletteHolderBuilder {
private final TreeMap<Integer, Palette> paletteMap = new TreeMap<>(); private final TreeMap<Integer, Palette> paletteMap = new TreeMap<>();
public PaletteHolderBuilder add(int y, Palette palette) { public PaletteHolderBuilder add(int y, Palette palette) {
paletteMap.put(y, palette); paletteMap.put(y, palette);
return this; return this;
} }
public PaletteHolder build() { public PaletteHolder build() {
int min = FastMath.min(paletteMap.keySet().stream().min(Integer::compareTo).orElse(0), 0); int min = FastMath.min(paletteMap.keySet().stream().min(Integer::compareTo).orElse(0), 0);
int max = FastMath.max(paletteMap.keySet().stream().max(Integer::compareTo).orElse(255), 255); int max = FastMath.max(paletteMap.keySet().stream().max(Integer::compareTo).orElse(255), 255);
Palette[] palettes = new Palette[paletteMap.lastKey() + 1 - min]; Palette[] palettes = new Palette[paletteMap.lastKey() + 1 - min];
for(int y = min; y <= FastMath.max(paletteMap.lastKey(), max); y++) { for(int y = min; y <= FastMath.max(paletteMap.lastKey(), max); y++) {
Palette d = null; Palette d = null;

View File

@ -3,13 +3,14 @@ package com.dfsek.terra.addons.biome.holder;
import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader; import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader; import com.dfsek.tectonic.loading.TypeLoader;
import com.dfsek.terra.api.world.generator.Palette;
import java.lang.reflect.AnnotatedType; import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Type;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolderLoader implements TypeLoader<PaletteHolder> { public class PaletteHolderLoader implements TypeLoader<PaletteHolder> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override

View File

@ -1,13 +1,5 @@
package com.dfsek.terra.addons.carver; package com.dfsek.terra.addons.carver;
import com.dfsek.terra.addons.carver.carving.Worm;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.api.util.PopulationUtil;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
@ -18,43 +10,60 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
public class CarverCache { import com.dfsek.terra.addons.carver.carving.Worm;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.api.util.PopulationUtil;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class CarverCache {
private final LoadingCache<Long, List<Worm.WormPoint>> cache; private final LoadingCache<Long, List<Worm.WormPoint>> cache;
private final UserDefinedCarver carver; private final UserDefinedCarver carver;
public CarverCache(World w, TerraPlugin main, UserDefinedCarver carver) { public CarverCache(World w, TerraPlugin main, UserDefinedCarver carver) {
this.carver = carver; this.carver = carver;
cache = CacheBuilder.newBuilder().maximumSize(main.getTerraConfig().getCarverCacheSize()) cache = CacheBuilder.newBuilder().maximumSize(main.getTerraConfig().getCarverCacheSize())
.build(new CacheLoader<>() { .build(new CacheLoader<>() {
@Override @Override
public List<Worm.WormPoint> load(@NotNull Long key) { public List<Worm.WormPoint> load(@NotNull Long key) {
int chunkX = (int) (key >> 32); int chunkX = (int) (key >> 32);
int chunkZ = (int) key.longValue(); int chunkZ = (int) key.longValue();
BiomeProvider provider = w.getBiomeProvider(); BiomeProvider provider = w.getBiomeProvider();
if(CarverCache.this.carver.isChunkCarved(w, chunkX, chunkZ, new Random(PopulationUtil.getCarverChunkSeed(chunkX, chunkZ, w.getSeed() + CarverCache.this.carver.hashCode())))) { if(CarverCache.this.carver.isChunkCarved(w, chunkX, chunkZ, new Random(
long seed = PopulationUtil.getCarverChunkSeed(chunkX, chunkZ, w.getSeed()); PopulationUtil.getCarverChunkSeed(chunkX, chunkZ,
Random r = new Random(seed); w.getSeed() + CarverCache.this.carver.hashCode())))) {
Worm carving = CarverCache.this.carver.getWorm(seed, new Vector3((chunkX << 4) + r.nextInt(16), CarverCache.this.carver.getConfig().getHeight().get(r), (chunkZ << 4) + r.nextInt(16))); long seed = PopulationUtil.getCarverChunkSeed(chunkX, chunkZ, w.getSeed());
List<Worm.WormPoint> points = new ArrayList<>(); Random r = new Random(seed);
for(int i = 0; i < carving.getLength(); i++) { Worm carving = CarverCache.this.carver.getWorm(seed, new Vector3((chunkX << 4) + r.nextInt(16),
carving.step(); CarverCache.this.carver.getConfig()
TerraBiome biome = provider.getBiome(carving.getRunning(), w.getSeed()); .getHeight()
.get(r),
(chunkZ << 4) + r.nextInt(16)));
List<Worm.WormPoint> points = new ArrayList<>();
for(int i = 0; i < carving.getLength(); i++) {
carving.step();
TerraBiome biome = provider.getBiome(carving.getRunning(), w.getSeed());
/* /*
if(!((UserDefinedBiome) biome).getConfig().getCarvers().containsKey(CarverCache.this.carver)) { // Stop if we enter a biome this carver is not present in if(!((UserDefinedBiome) biome).getConfig().getCarvers().containsKey(CarverCache.this.carver)) { // Stop
if we enter a biome this carver is not present in
return Collections.emptyList(); return Collections.emptyList();
} }
*/ */
points.add(carving.getPoint()); points.add(carving.getPoint());
} }
return points; return points;
} }
return Collections.emptyList(); return Collections.emptyList();
} }
}); });
} }
public List<Worm.WormPoint> getPoints(int chunkX, int chunkZ) { public List<Worm.WormPoint> getPoints(int chunkX, int chunkZ) {
return cache.getUnchecked(MathUtil.squash(chunkX, chunkZ)); return cache.getUnchecked(MathUtil.squash(chunkX, chunkZ));
} }

View File

@ -3,30 +3,33 @@ package com.dfsek.terra.addons.carver;
import com.dfsek.paralithic.eval.parser.Scope; import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException; import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.exception.LoadException;
import java.util.Arrays;
import java.util.List;
import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.config.ConfigFactory; import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.util.MathUtil; import com.dfsek.terra.api.util.MathUtil;
import java.util.Arrays;
import java.util.List;
public class CarverFactory implements ConfigFactory<CarverTemplate, UserDefinedCarver> { public class CarverFactory implements ConfigFactory<CarverTemplate, UserDefinedCarver> {
private final ConfigPack pack; private final ConfigPack pack;
public CarverFactory(ConfigPack pack) { public CarverFactory(ConfigPack pack) {
this.pack = pack; this.pack = pack;
} }
@Override @Override
public UserDefinedCarver build(CarverTemplate config, TerraPlugin main) throws LoadException { public UserDefinedCarver build(CarverTemplate config, TerraPlugin main) throws LoadException {
double[] start = new double[] {config.getStartX(), config.getStartY(), config.getStartZ()}; double[] start = { config.getStartX(), config.getStartY(), config.getStartZ() };
double[] mutate = new double[] {config.getMutateX(), config.getMutateY(), config.getMutateZ()}; double[] mutate = { config.getMutateX(), config.getMutateY(), config.getMutateZ() };
List<String> radius = Arrays.asList(config.getRadMX(), config.getRadMY(), config.getRadMZ()); List<String> radius = Arrays.asList(config.getRadMX(), config.getRadMY(), config.getRadMZ());
long hash = MathUtil.hashToLong(config.getID()); long hash = MathUtil.hashToLong(config.getID());
UserDefinedCarver carver; UserDefinedCarver carver;
try { try {
carver = new UserDefinedCarver(config.getHeight(), config.getLength(), start, mutate, radius, new Scope(), hash, config.getCutTop(), config.getCutBottom(), config, main); carver = new UserDefinedCarver(config.getHeight(), config.getLength(), start, mutate, radius, new Scope(), hash,
config.getCutTop(), config.getCutBottom(), config, main);
} catch(ParseException e) { } catch(ParseException e) {
throw new LoadException("Unable to parse radius equations", e); throw new LoadException("Unable to parse radius equations", e);
} }

View File

@ -1,52 +1,54 @@
package com.dfsek.terra.addons.carver; package com.dfsek.terra.addons.carver;
import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.util.collection.MaterialSet;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import net.jafama.FastMath; import net.jafama.FastMath;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"}) import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.util.collection.MaterialSet;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
@SuppressWarnings({ "unchecked", "rawtypes", "RedundantSuppression" })
public class CarverPalette { public class CarverPalette {
private final boolean blacklist; private final boolean blacklist;
private final MaterialSet replace; private final MaterialSet replace;
private final TreeMap<Integer, ProbabilityCollection<BlockState>> map = new TreeMap<>(); private final TreeMap<Integer, ProbabilityCollection<BlockState>> map = new TreeMap<>();
private ProbabilityCollection<BlockState>[] layers; private ProbabilityCollection<BlockState>[] layers;
private int offset = 0; private int offset = 0;
public CarverPalette(MaterialSet replaceable, boolean blacklist) { public CarverPalette(MaterialSet replaceable, boolean blacklist) {
this.blacklist = blacklist; this.blacklist = blacklist;
this.replace = replaceable; this.replace = replaceable;
} }
public CarverPalette add(ProbabilityCollection<BlockState> collection, int y) { public CarverPalette add(ProbabilityCollection<BlockState> collection, int y) {
map.put(y, collection); map.put(y, collection);
return this; return this;
} }
public ProbabilityCollection<BlockState> get(int y) { public ProbabilityCollection<BlockState> get(int y) {
int index = y + offset; int index = y + offset;
return index >= 0 return index >= 0
? index < layers.length ? index < layers.length
? layers[index] ? layers[index]
: layers[layers.length - 1] : layers[layers.length - 1]
: layers[0]; : layers[0];
} }
public boolean canReplace(BlockType material) { public boolean canReplace(BlockType material) {
return blacklist != replace.contains(material); return blacklist != replace.contains(material);
} }
/** /**
* Build the palette to an array. * Build the palette to an array.
*/ */
public void build() { public void build() {
int min = FastMath.min(map.keySet().stream().min(Integer::compareTo).orElse(0), 0); int min = FastMath.min(map.keySet().stream().min(Integer::compareTo).orElse(0), 0);
int max = FastMath.max(map.keySet().stream().max(Integer::compareTo).orElse(255), 255); int max = FastMath.max(map.keySet().stream().max(Integer::compareTo).orElse(255), 255);
layers = new ProbabilityCollection[map.lastKey() + 1 - min]; layers = new ProbabilityCollection[map.lastKey() + 1 - min];
for(int y = min; y <= FastMath.max(map.lastKey(), max); y++) { for(int y = min; y <= FastMath.max(map.lastKey(), max); y++) {
ProbabilityCollection<BlockState> d = null; ProbabilityCollection<BlockState> d = null;

View File

@ -4,6 +4,10 @@ package com.dfsek.terra.addons.carver;
import com.dfsek.tectonic.annotations.Default; import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Final; import com.dfsek.tectonic.annotations.Final;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import java.util.HashMap;
import java.util.Map;
import com.dfsek.terra.api.block.BlockType; import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.config.AbstractableTemplate; import com.dfsek.terra.api.config.AbstractableTemplate;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
@ -11,176 +15,174 @@ import com.dfsek.terra.api.util.ConstantRange;
import com.dfsek.terra.api.util.Range; import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.collection.MaterialSet; import com.dfsek.terra.api.util.collection.MaterialSet;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings({"unused", "FieldMayBeFinal"}) @SuppressWarnings({ "unused", "FieldMayBeFinal" })
public class CarverTemplate implements AbstractableTemplate { public class CarverTemplate implements AbstractableTemplate {
@Value("id") @Value("id")
@Final @Final
private String id; private String id;
@Value("step") @Value("step")
@Default @Default
private @Meta int step = 2; private @Meta int step = 2;
@Value("recalculate-magnitude") @Value("recalculate-magnitude")
@Default @Default
private @Meta double recaclulateMagnitude = 4; private @Meta double recaclulateMagnitude = 4;
@Value("recalculate-direction") @Value("recalculate-direction")
@Default @Default
private @Meta Range recalc = new ConstantRange(8, 10); private @Meta Range recalc = new ConstantRange(8, 10);
@Value("length") @Value("length")
private @Meta Range length; private @Meta Range length;
@Value("start.x") @Value("start.x")
private @Meta double startX; private @Meta double startX;
@Value("start.y") @Value("start.y")
private @Meta double startY; private @Meta double startY;
@Value("start.z") @Value("start.z")
private @Meta double startZ; private @Meta double startZ;
@Value("start.radius.x") @Value("start.radius.x")
private @Meta String radMX; private @Meta String radMX;
@Value("start.radius.y") @Value("start.radius.y")
private @Meta String radMY; private @Meta String radMY;
@Value("start.radius.z") @Value("start.radius.z")
private @Meta String radMZ; private @Meta String radMZ;
@Value("start.height") @Value("start.height")
private @Meta Range height; private @Meta Range height;
@Value("cut.bottom") @Value("cut.bottom")
@Default @Default
private @Meta int cutBottom = 0; private @Meta int cutBottom = 0;
@Value("cut.top") @Value("cut.top")
@Default @Default
private @Meta int cutTop = 0; private @Meta int cutTop = 0;
@Value("mutate.x") @Value("mutate.x")
private @Meta double mutateX; private @Meta double mutateX;
@Value("mutate.y") @Value("mutate.y")
private @Meta double mutateY; private @Meta double mutateY;
@Value("mutate.z") @Value("mutate.z")
private @Meta double mutateZ; private @Meta double mutateZ;
@Value("palette.top") @Value("palette.top")
private @Meta CarverPalette top; private @Meta CarverPalette top;
@Value("palette.bottom") @Value("palette.bottom")
private @Meta CarverPalette bottom; private @Meta CarverPalette bottom;
@Value("palette.outer") @Value("palette.outer")
private @Meta CarverPalette outer; private @Meta CarverPalette outer;
@Value("palette.inner") @Value("palette.inner")
private @Meta CarverPalette inner; private @Meta CarverPalette inner;
@Value("shift") @Value("shift")
@Default @Default
private @Meta Map<@Meta BlockType, @Meta MaterialSet> shift = new HashMap<>(); private @Meta Map<@Meta BlockType, @Meta MaterialSet> shift = new HashMap<>();
@Value("update") @Value("update")
@Default @Default
private @Meta MaterialSet update = new MaterialSet(); private @Meta MaterialSet update = new MaterialSet();
public String getID() { public String getID() {
return id; return id;
} }
public int getStep() { public int getStep() {
return step; return step;
} }
public Range getLength() { public Range getLength() {
return length; return length;
} }
public double getStartX() { public double getStartX() {
return startX; return startX;
} }
public double getStartY() { public double getStartY() {
return startY; return startY;
} }
public double getStartZ() { public double getStartZ() {
return startZ; return startZ;
} }
public String getRadMX() { public String getRadMX() {
return radMX; return radMX;
} }
public String getRadMY() { public String getRadMY() {
return radMY; return radMY;
} }
public String getRadMZ() { public String getRadMZ() {
return radMZ; return radMZ;
} }
public Range getHeight() { public Range getHeight() {
return height; return height;
} }
public int getCutBottom() { public int getCutBottom() {
return cutBottom; return cutBottom;
} }
public int getCutTop() { public int getCutTop() {
return cutTop; return cutTop;
} }
public double getMutateX() { public double getMutateX() {
return mutateX; return mutateX;
} }
public double getMutateY() { public double getMutateY() {
return mutateY; return mutateY;
} }
public double getMutateZ() { public double getMutateZ() {
return mutateZ; return mutateZ;
} }
public CarverPalette getTop() { public CarverPalette getTop() {
return top; return top;
} }
public CarverPalette getBottom() { public CarverPalette getBottom() {
return bottom; return bottom;
} }
public CarverPalette getOuter() { public CarverPalette getOuter() {
return outer; return outer;
} }
public CarverPalette getInner() { public CarverPalette getInner() {
return inner; return inner;
} }
public Map<BlockType, MaterialSet> getShift() { public Map<BlockType, MaterialSet> getShift() {
return shift; return shift;
} }
public MaterialSet getUpdate() { public MaterialSet getUpdate() {
return update; return update;
} }
public Range getRecalc() { public Range getRecalc() {
return recalc; return recalc;
} }
public double getRecaclulateMagnitude() { public double getRecaclulateMagnitude() {
return recaclulateMagnitude; return recaclulateMagnitude;
} }

View File

@ -1,5 +1,11 @@
package com.dfsek.terra.addons.carver; package com.dfsek.terra.addons.carver;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.block.BlockType; import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.BlockState;
@ -11,20 +17,17 @@ import com.dfsek.terra.api.world.Chunk;
import com.dfsek.terra.api.world.World; import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.generator.Chunkified; import com.dfsek.terra.api.world.generator.Chunkified;
import com.dfsek.terra.api.world.generator.GenerationStage; import com.dfsek.terra.api.world.generator.GenerationStage;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class CavePopulator implements GenerationStage, Chunkified { public class CavePopulator implements GenerationStage, Chunkified {
private static final Map<BlockType, BlockState> shiftStorage = new HashMap<>(); // Persist BlockData created for shifts, to avoid re-calculating each time. private static final Map<BlockType, BlockState> shiftStorage = new HashMap<>();
// Persist BlockData created for shifts, to avoid re-calculating each time.
private final TerraPlugin main; private final TerraPlugin main;
public CavePopulator(TerraPlugin main) { public CavePopulator(TerraPlugin main) {
this.main = main; this.main = main;
} }
@SuppressWarnings("try") @SuppressWarnings("try")
@Override @Override
public void populate(@NotNull World world, @NotNull Chunk chunk) { public void populate(@NotNull World world, @NotNull Chunk chunk) {
@ -32,7 +35,7 @@ public class CavePopulator implements GenerationStage, Chunkified {
Random random = PopulationUtil.getRandom(chunk); Random random = PopulationUtil.getRandom(chunk);
WorldConfig config = world.getConfig(); WorldConfig config = world.getConfig();
if(config.disableCarving()) return; if(config.disableCarving()) return;
for(UserDefinedCarver c : config.getRegistry(UserDefinedCarver.class).entries()) { for(UserDefinedCarver c : config.getRegistry(UserDefinedCarver.class).entries()) {
CarverTemplate template = c.getConfig(); CarverTemplate template = c.getConfig();
Map<Vector3, BlockState> shiftCandidate = new HashMap<>(); Map<Vector3, BlockState> shiftCandidate = new HashMap<>();
@ -43,25 +46,29 @@ public class CavePopulator implements GenerationStage, Chunkified {
switch(type) { switch(type) {
case CENTER: case CENTER:
if(template.getInner().canReplace(re)) { if(template.getInner().canReplace(re)) {
chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(), template.getInner().get(v.getBlockY()).get(random), template.getUpdate().contains(re)); chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(),
template.getInner().get(v.getBlockY()).get(random), template.getUpdate().contains(re));
if(template.getShift().containsKey(re)) shiftCandidate.put(v, m); if(template.getShift().containsKey(re)) shiftCandidate.put(v, m);
} }
break; break;
case WALL: case WALL:
if(template.getOuter().canReplace(re)) { if(template.getOuter().canReplace(re)) {
chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(), template.getOuter().get(v.getBlockY()).get(random), template.getUpdate().contains(re)); chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(),
template.getOuter().get(v.getBlockY()).get(random), template.getUpdate().contains(re));
if(template.getShift().containsKey(re)) shiftCandidate.put(v, m); if(template.getShift().containsKey(re)) shiftCandidate.put(v, m);
} }
break; break;
case TOP: case TOP:
if(template.getTop().canReplace(re)) { if(template.getTop().canReplace(re)) {
chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(), template.getTop().get(v.getBlockY()).get(random), template.getUpdate().contains(re)); chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(),
template.getTop().get(v.getBlockY()).get(random), template.getUpdate().contains(re));
if(template.getShift().containsKey(re)) shiftCandidate.put(v, m); if(template.getShift().containsKey(re)) shiftCandidate.put(v, m);
} }
break; break;
case BOTTOM: case BOTTOM:
if(template.getBottom().canReplace(re)) { if(template.getBottom().canReplace(re)) {
chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(), template.getBottom().get(v.getBlockY()).get(random), template.getUpdate().contains(re)); chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(),
template.getBottom().get(v.getBlockY()).get(random), template.getUpdate().contains(re));
if(template.getShift().containsKey(re)) shiftCandidate.put(v, m); if(template.getShift().containsKey(re)) shiftCandidate.put(v, m);
} }
break; break;
@ -73,16 +80,19 @@ public class CavePopulator implements GenerationStage, Chunkified {
Vector3 mut = l.clone(); Vector3 mut = l.clone();
BlockState orig = chunk.getBlock(l.getBlockX(), l.getBlockY(), l.getBlockZ()); BlockState orig = chunk.getBlock(l.getBlockX(), l.getBlockY(), l.getBlockZ());
do mut.subtract(0, 1, 0); do mut.subtract(0, 1, 0);
while(mut.getY() > world.getMinHeight() && chunk.getBlock(mut.getBlockX(), mut.getBlockY(), mut.getBlockZ()).matches(orig)); while(mut.getY() > world.getMinHeight() && chunk.getBlock(mut.getBlockX(), mut.getBlockY(), mut.getBlockZ()).matches(
orig));
try { try {
if(template.getShift().get(entry.getValue().getBlockType()).contains(chunk.getBlock(mut.getBlockX(), mut.getBlockY(), mut.getBlockZ()).getBlockType())) { if(template.getShift().get(entry.getValue().getBlockType()).contains(
chunk.setBlock(mut.getBlockX(), mut.getBlockY(), mut.getBlockZ(), shiftStorage.computeIfAbsent(entry.getValue().getBlockType(), BlockType::getDefaultData), false); chunk.getBlock(mut.getBlockX(), mut.getBlockY(), mut.getBlockZ()).getBlockType())) {
chunk.setBlock(mut.getBlockX(), mut.getBlockY(), mut.getBlockZ(),
shiftStorage.computeIfAbsent(entry.getValue().getBlockType(), BlockType::getDefaultData), false);
} }
} catch(NullPointerException ignored) { } catch(NullPointerException ignored) {
} }
} }
} }
} }
} }
} }

View File

@ -4,13 +4,6 @@ import com.dfsek.paralithic.Expression;
import com.dfsek.paralithic.eval.parser.Parser; import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Scope; import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException; import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.terra.addons.carver.carving.Carver;
import com.dfsek.terra.addons.carver.carving.Worm;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.util.ConstantRange;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import net.jafama.FastMath; import net.jafama.FastMath;
import java.util.List; import java.util.List;
@ -19,6 +12,15 @@ import java.util.Random;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import com.dfsek.terra.addons.carver.carving.Carver;
import com.dfsek.terra.addons.carver.carving.Worm;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.util.ConstantRange;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
public class UserDefinedCarver extends Carver { public class UserDefinedCarver extends Carver {
private final double[] start; // 0, 1, 2 = x, y, z. private final double[] start; // 0, 1, 2 = x, y, z.
private final double[] mutate; // 0, 1, 2 = x, y, z. 3 = radius. private final double[] mutate; // 0, 1, 2 = x, y, z. 3 = radius.
@ -30,14 +32,15 @@ public class UserDefinedCarver extends Carver {
private final Expression xRad; private final Expression xRad;
private final Expression yRad; private final Expression yRad;
private final Expression zRad; private final Expression zRad;
private final Map<Long, CarverCache> cacheMap = new ConcurrentHashMap<>(); private final Map<Long, CarverCache> cacheMap = new ConcurrentHashMap<>();
private final TerraPlugin main; private final TerraPlugin main;
private double step = 2; private double step = 2;
private Range recalc = new ConstantRange(8, 10); private Range recalc = new ConstantRange(8, 10);
private double recalcMagnitude = 3; private double recalcMagnitude = 3;
public UserDefinedCarver(Range height, Range length, double[] start, double[] mutate, List<String> radii, Scope parent, long hash, int topCut, int bottomCut, CarverTemplate config, TerraPlugin main) throws ParseException { public UserDefinedCarver(Range height, Range length, double[] start, double[] mutate, List<String> radii, Scope parent, long hash,
int topCut, int bottomCut, CarverTemplate config, TerraPlugin main) throws ParseException {
super(height.getMin(), height.getMax()); super(height.getMin(), height.getMax());
this.length = length; this.length = length;
this.start = start; this.start = start;
@ -47,41 +50,27 @@ public class UserDefinedCarver extends Carver {
this.bottomCut = bottomCut; this.bottomCut = bottomCut;
this.config = config; this.config = config;
this.main = main; this.main = main;
Parser p = new Parser(); Parser p = new Parser();
Scope s = new Scope().withParent(parent); Scope s = new Scope().withParent(parent);
s.addInvocationVariable("x"); s.addInvocationVariable("x");
s.addInvocationVariable("y"); s.addInvocationVariable("y");
s.addInvocationVariable("z"); s.addInvocationVariable("z");
s.addInvocationVariable("length"); s.addInvocationVariable("length");
s.addInvocationVariable("position"); s.addInvocationVariable("position");
s.addInvocationVariable("seed"); s.addInvocationVariable("seed");
xRad = p.parse(radii.get(0), s); xRad = p.parse(radii.get(0), s);
yRad = p.parse(radii.get(1), s); yRad = p.parse(radii.get(1), s);
zRad = p.parse(radii.get(2), s); zRad = p.parse(radii.get(2), s);
} }
@Override
public Worm getWorm(long l, Vector3 vector) {
Random r = new Random(l + hash);
return new UserDefinedWorm(length.get(r) / 2, r, vector, topCut, bottomCut, l);
}
public void setStep(double step) {
this.step = step;
}
public void setRecalc(Range recalc) {
this.recalc = recalc;
}
@Override @Override
public void carve(int chunkX, int chunkZ, World w, BiConsumer<Vector3, CarvingType> consumer) { public void carve(int chunkX, int chunkZ, World w, BiConsumer<Vector3, CarvingType> consumer) {
synchronized(cacheMap) { synchronized(cacheMap) {
@ -91,7 +80,8 @@ public class UserDefinedCarver extends Carver {
for(int z = chunkZ - carvingRadius; z <= chunkZ + carvingRadius; z++) { for(int z = chunkZ - carvingRadius; z <= chunkZ + carvingRadius; z++) {
cache.getPoints(x, z).forEach(point -> { cache.getPoints(x, z).forEach(point -> {
Vector3 origin = point.getOrigin(); Vector3 origin = point.getOrigin();
if(FastMath.floorDiv(origin.getBlockX(), 16) != chunkX && FastMath.floorDiv(origin.getBlockZ(), 16) != chunkZ) // We only want to carve this chunk. if(FastMath.floorDiv(origin.getBlockX(), 16) != chunkX && FastMath.floorDiv(origin.getBlockZ(), 16) !=
chunkZ) // We only want to carve this chunk.
return; return;
point.carve(chunkX, chunkZ, consumer, w); point.carve(chunkX, chunkZ, consumer, w);
}); });
@ -99,24 +89,39 @@ public class UserDefinedCarver extends Carver {
} }
} }
} }
public void setRecalcMagnitude(double recalcMagnitude) { @Override
this.recalcMagnitude = recalcMagnitude; public Worm getWorm(long l, Vector3 vector) {
Random r = new Random(l + hash);
return new UserDefinedWorm(length.get(r) / 2, r, vector, topCut, bottomCut, l);
} }
@Override @Override
public boolean isChunkCarved(World w, int chunkX, int chunkZ, Random random) { public boolean isChunkCarved(World w, int chunkX, int chunkZ, Random random) {
/*BiomeTemplate conf = ((UserDefinedBiome) main.getWorld(w).getBiomeProvider().getBiome((chunkX << 4) + 8, (chunkZ << 4) + 8)).getConfig(); /*BiomeTemplate conf = ((UserDefinedBiome) main.getWorld(w).getBiomeProvider().getBiome((chunkX << 4) + 8, (chunkZ << 4) + 8))
.getConfig();
if(conf.getCarvers().get(this) != null) { if(conf.getCarvers().get(this) != null) {
return new Random(random.nextLong() + hash).nextInt(100) < conf.getCarvers().get(this); return new Random(random.nextLong() + hash).nextInt(100) < conf.getCarvers().get(this);
}*/ }*/
return false; return false;
} }
public void setRecalc(Range recalc) {
this.recalc = recalc;
}
public void setRecalcMagnitude(double recalcMagnitude) {
this.recalcMagnitude = recalcMagnitude;
}
public void setStep(double step) {
this.step = step;
}
public CarverTemplate getConfig() { public CarverTemplate getConfig() {
return config; return config;
} }
private class UserDefinedWorm extends Worm { private class UserDefinedWorm extends Worm {
private final Vector3 direction; private final Vector3 direction;
private final Vector3 origin; private final Vector3 origin;
@ -124,41 +129,44 @@ public class UserDefinedCarver extends Carver {
private int steps; private int steps;
private int nextDirection = 0; private int nextDirection = 0;
private double[] currentRotation = new double[3]; private double[] currentRotation = new double[3];
public UserDefinedWorm(int length, Random r, Vector3 origin, int topCut, int bottomCut, long seed) { public UserDefinedWorm(int length, Random r, Vector3 origin, int topCut, int bottomCut, long seed) {
super(length, r, origin); super(length, r, origin);
this.origin = origin; this.origin = origin;
this.seed = seed; this.seed = seed;
super.setTopCut(topCut); super.setTopCut(topCut);
super.setBottomCut(bottomCut); super.setBottomCut(bottomCut);
direction = new Vector3((r.nextDouble() - 0.5D) * start[0], (r.nextDouble() - 0.5D) * start[1], (r.nextDouble() - 0.5D) * start[2]).normalize().multiply(step); direction = new Vector3((r.nextDouble() - 0.5D) * start[0], (r.nextDouble() - 0.5D) * start[1],
double[] args = {origin.getX(), origin.getY(), origin.getZ(), length, 0, seed}; (r.nextDouble() - 0.5D) * start[2]).normalize().multiply(step);
setRadius(new int[] {(int) (xRad.evaluate(args)), (int) (yRad.evaluate(args)), (int) (zRad.evaluate(args))}); double[] args = { origin.getX(), origin.getY(), origin.getZ(), length, 0, seed };
setRadius(new int[]{ (int) (xRad.evaluate(args)), (int) (yRad.evaluate(args)), (int) (zRad.evaluate(args)) });
} }
@Override
public WormPoint getPoint() {
return new WormPoint(getRunning().clone(), getRadius(), config.getCutTop(), config.getCutBottom());
}
@Override @Override
public void step() { public void step() {
if(steps == nextDirection) { if(steps == nextDirection) {
direction.rotateAroundX(FastMath.toRadians((getRandom().nextGaussian()) * mutate[0] * recalcMagnitude)); direction.rotateAroundX(FastMath.toRadians((getRandom().nextGaussian()) * mutate[0] * recalcMagnitude));
direction.rotateAroundY(FastMath.toRadians((getRandom().nextGaussian()) * mutate[1] * recalcMagnitude)); direction.rotateAroundY(FastMath.toRadians((getRandom().nextGaussian()) * mutate[1] * recalcMagnitude));
direction.rotateAroundZ(FastMath.toRadians((getRandom().nextGaussian()) * mutate[2] * recalcMagnitude)); direction.rotateAroundZ(FastMath.toRadians((getRandom().nextGaussian()) * mutate[2] * recalcMagnitude));
currentRotation = new double[] {(getRandom().nextGaussian()) * mutate[0], currentRotation = new double[]{
(getRandom().nextGaussian()) * mutate[0],
(getRandom().nextGaussian()) * mutate[1], (getRandom().nextGaussian()) * mutate[1],
(getRandom().nextGaussian()) * mutate[2]}; (getRandom().nextGaussian()) * mutate[2]
};
nextDirection += recalc.get(getRandom()); nextDirection += recalc.get(getRandom());
} }
steps++; steps++;
double[] args = {origin.getX(), origin.getY(), origin.getZ(), getLength(), steps, seed}; double[] args = { origin.getX(), origin.getY(), origin.getZ(), getLength(), steps, seed };
setRadius(new int[] {(int) (xRad.evaluate(args)), (int) (yRad.evaluate(args)), (int) (zRad.evaluate(args))}); setRadius(new int[]{ (int) (xRad.evaluate(args)), (int) (yRad.evaluate(args)), (int) (zRad.evaluate(args)) });
direction.rotateAroundX(FastMath.toRadians(currentRotation[0] * mutate[0])); direction.rotateAroundX(FastMath.toRadians(currentRotation[0] * mutate[0]));
direction.rotateAroundY(FastMath.toRadians(currentRotation[1] * mutate[1])); direction.rotateAroundY(FastMath.toRadians(currentRotation[1] * mutate[1]));
direction.rotateAroundZ(FastMath.toRadians(currentRotation[2] * mutate[2])); direction.rotateAroundZ(FastMath.toRadians(currentRotation[2] * mutate[2]));
getRunning().add(direction); getRunning().add(direction);
} }
@Override
public WormPoint getPoint() {
return new WormPoint(getRunning().clone(), getRadius(), config.getCutTop(), config.getCutBottom());
}
} }
} }

View File

@ -1,38 +1,43 @@
package com.dfsek.terra.addons.carver.carving; package com.dfsek.terra.addons.carver.carving;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import net.jafama.FastMath; import net.jafama.FastMath;
import java.util.Random; import java.util.Random;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
public abstract class Carver { public abstract class Carver {
private final int minY; private final int minY;
private final int maxY; private final int maxY;
private final double sixtyFourSq = FastMath.pow(64, 2); private final double sixtyFourSq = FastMath.pow(64, 2);
private int carvingRadius = 4; private int carvingRadius = 4;
public Carver(int minY, int maxY) { public Carver(int minY, int maxY) {
this.minY = minY; this.minY = minY;
this.maxY = maxY; this.maxY = maxY;
} }
public abstract void carve(int chunkX, int chunkZ, World w, BiConsumer<Vector3, CarvingType> consumer); public abstract void carve(int chunkX, int chunkZ, World w, BiConsumer<Vector3, CarvingType> consumer);
public int getCarvingRadius() { public int getCarvingRadius() {
return carvingRadius; return carvingRadius;
} }
public void setCarvingRadius(int carvingRadius) { public void setCarvingRadius(int carvingRadius) {
this.carvingRadius = carvingRadius; this.carvingRadius = carvingRadius;
} }
public abstract Worm getWorm(long seed, Vector3 l); public abstract Worm getWorm(long seed, Vector3 l);
public abstract boolean isChunkCarved(World w, int chunkX, int chunkZ, Random r); public abstract boolean isChunkCarved(World w, int chunkX, int chunkZ, Random r);
public enum CarvingType { public enum CarvingType {
CENTER, WALL, TOP, BOTTOM CENTER,
WALL,
TOP,
BOTTOM
} }
} }

View File

@ -1,12 +1,14 @@
package com.dfsek.terra.addons.carver.carving; package com.dfsek.terra.addons.carver.carving;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
import net.jafama.FastMath; import net.jafama.FastMath;
import java.util.Random; import java.util.Random;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import com.dfsek.terra.api.vector.Vector3;
import com.dfsek.terra.api.world.World;
public abstract class Worm { public abstract class Worm {
private final Random r; private final Random r;
private final Vector3 origin; private final Vector3 origin;
@ -14,78 +16,73 @@ public abstract class Worm {
private final int length; private final int length;
private int topCut = 0; private int topCut = 0;
private int bottomCut = 0; private int bottomCut = 0;
private int[] radius = new int[] {0, 0, 0}; private int[] radius = { 0, 0, 0 };
public Worm(int length, Random r, Vector3 origin) { public Worm(int length, Random r, Vector3 origin) {
this.r = r; this.r = r;
this.length = length; this.length = length;
this.origin = origin; this.origin = origin;
this.running = origin; this.running = origin;
} }
public abstract void step();
public void setBottomCut(int bottomCut) { public void setBottomCut(int bottomCut) {
this.bottomCut = bottomCut; this.bottomCut = bottomCut;
} }
public void setTopCut(int topCut) { public void setTopCut(int topCut) {
this.topCut = topCut; this.topCut = topCut;
} }
public Vector3 getOrigin() { public Vector3 getOrigin() {
return origin; return origin;
} }
public int getLength() { public int getLength() {
return length; return length;
} }
public Vector3 getRunning() { public Vector3 getRunning() {
return running; return running;
} }
public WormPoint getPoint() { public WormPoint getPoint() {
return new WormPoint(running, radius, topCut, bottomCut); return new WormPoint(running, radius, topCut, bottomCut);
} }
public int[] getRadius() { public int[] getRadius() {
return radius; return radius;
} }
public void setRadius(int[] radius) { public void setRadius(int[] radius) {
this.radius = radius; this.radius = radius;
} }
public Random getRandom() { public Random getRandom() {
return r; return r;
} }
public abstract void step();
public static class WormPoint { public static class WormPoint {
private final Vector3 origin; private final Vector3 origin;
private final int topCut; private final int topCut;
private final int bottomCut; private final int bottomCut;
private final int[] rad; private final int[] rad;
public WormPoint(Vector3 origin, int[] rad, int topCut, int bottomCut) { public WormPoint(Vector3 origin, int[] rad, int topCut, int bottomCut) {
this.origin = origin; this.origin = origin;
this.rad = rad; this.rad = rad;
this.topCut = topCut; this.topCut = topCut;
this.bottomCut = bottomCut; this.bottomCut = bottomCut;
} }
private static double ellipseEquation(int x, int y, int z, double xr, double yr, double zr) { private static double ellipseEquation(int x, int y, int z, double xr, double yr, double zr) {
return (FastMath.pow2(x) / FastMath.pow2(xr + 0.5D)) + (FastMath.pow2(y) / FastMath.pow2(yr + 0.5D)) + (FastMath.pow2(z) / FastMath.pow2(zr + 0.5D)); return (FastMath.pow2(x) / FastMath.pow2(xr + 0.5D)) + (FastMath.pow2(y) / FastMath.pow2(yr + 0.5D)) + (FastMath.pow2(z) /
FastMath.pow2(
zr + 0.5D));
} }
public Vector3 getOrigin() {
return origin;
}
public int getRadius(int index) {
return rad[index];
}
public void carve(int chunkX, int chunkZ, BiConsumer<Vector3, Carver.CarvingType> consumer, World world) { public void carve(int chunkX, int chunkZ, BiConsumer<Vector3, Carver.CarvingType> consumer, World world) {
int xRad = getRadius(0); int xRad = getRadius(0);
int yRad = getRadius(1); int yRad = getRadius(1);
@ -101,8 +98,10 @@ public abstract class Worm {
if(position.getY() < world.getMinHeight() || position.getY() > world.getMaxHeight()) continue; if(position.getY() < world.getMinHeight() || position.getY() > world.getMaxHeight()) continue;
double eq = ellipseEquation(x, y, z, xRad, yRad, zRad); double eq = ellipseEquation(x, y, z, xRad, yRad, zRad);
if(eq <= 1 && if(eq <= 1 &&
y >= -yRad - 1 + bottomCut && y <= yRad + 1 - topCut) { y >= -yRad - 1 + bottomCut && y <= yRad + 1 - topCut) {
consumer.accept(new Vector3(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ), Carver.CarvingType.CENTER); consumer.accept(
new Vector3(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ),
Carver.CarvingType.CENTER);
} else if(eq <= 1.5) { } else if(eq <= 1.5) {
Carver.CarvingType type = Carver.CarvingType.WALL; Carver.CarvingType type = Carver.CarvingType.WALL;
if(y <= -yRad - 1 + bottomCut) { if(y <= -yRad - 1 + bottomCut) {
@ -110,11 +109,21 @@ public abstract class Worm {
} else if(y >= yRad + 1 - topCut) { } else if(y >= yRad + 1 - topCut) {
type = Carver.CarvingType.TOP; type = Carver.CarvingType.TOP;
} }
consumer.accept(new Vector3(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ), type); consumer.accept(
new Vector3(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ),
type);
} }
} }
} }
} }
} }
public Vector3 getOrigin() {
return origin;
}
public int getRadius(int index) {
return rad[index];
}
} }
} }

View File

@ -1,6 +1,9 @@
package com.dfsek.terra.addons.feature.distributor; package com.dfsek.terra.addons.feature.distributor;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.function.Supplier;
import com.dfsek.terra.addons.feature.distributor.config.AndDistributorTemplate; import com.dfsek.terra.addons.feature.distributor.config.AndDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.NoiseDistributorTemplate; import com.dfsek.terra.addons.feature.distributor.config.NoiseDistributorTemplate;
import com.dfsek.terra.addons.feature.distributor.config.OrDistributorTemplate; import com.dfsek.terra.addons.feature.distributor.config.OrDistributorTemplate;
@ -19,31 +22,32 @@ import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.structure.feature.Distributor; import com.dfsek.terra.api.structure.feature.Distributor;
import com.dfsek.terra.api.util.reflection.TypeKey; import com.dfsek.terra.api.util.reflection.TypeKey;
import java.util.function.Supplier;
@Addon("config-distributors") @Addon("config-distributors")
@Version("1.0.0") @Version("1.0.0")
@Author("Terra") @Author("Terra")
public class DistributorAddon extends TerraAddon { public class DistributorAddon extends TerraAddon {
public static final TypeKey<Supplier<ObjectTemplate<Distributor>>> DISTRIBUTOR_TOKEN = new TypeKey<>() {}; public static final TypeKey<Supplier<ObjectTemplate<Distributor>>> DISTRIBUTOR_TOKEN = new TypeKey<>() {
};
@Inject @Inject
private TerraPlugin main; private TerraPlugin main;
@Override @Override
public void initialize() { public void initialize() {
main.getEventManager() main.getEventManager()
.getHandler(FunctionalEventHandler.class) .getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class) .register(this, ConfigPackPreLoadEvent.class)
.then(event -> { .then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<Distributor>>> distributorRegistry = event.getPack().getOrCreateRegistry(DISTRIBUTOR_TOKEN); CheckedRegistry<Supplier<ObjectTemplate<Distributor>>> distributorRegistry = event.getPack().getOrCreateRegistry(
distributorRegistry.register("NOISE", NoiseDistributorTemplate::new); DISTRIBUTOR_TOKEN);
distributorRegistry.register("POINTS", PointSetDistributorTemplate::new); distributorRegistry.register("NOISE", NoiseDistributorTemplate::new);
distributorRegistry.register("AND", AndDistributorTemplate::new); distributorRegistry.register("POINTS", PointSetDistributorTemplate::new);
distributorRegistry.register("OR", OrDistributorTemplate::new); distributorRegistry.register("AND", AndDistributorTemplate::new);
distributorRegistry.register("OR", OrDistributorTemplate::new);
event.getPack()
.applyLoader(Point.class, PointTemplate::new); event.getPack()
}) .applyLoader(Point.class, PointTemplate::new);
.failThrough(); })
.failThrough();
} }
} }

View File

@ -4,16 +4,18 @@ import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ValidatedConfigTemplate; import com.dfsek.tectonic.config.ValidatedConfigTemplate;
import com.dfsek.tectonic.exception.ValidationException; import com.dfsek.tectonic.exception.ValidationException;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.List;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.structure.feature.Distributor; import com.dfsek.terra.api.structure.feature.Distributor;
import java.util.List;
public class AndDistributorTemplate implements ObjectTemplate<Distributor>, ValidatedConfigTemplate { public class AndDistributorTemplate implements ObjectTemplate<Distributor>, ValidatedConfigTemplate {
@Value("distributors") @Value("distributors")
private @Meta List<@Meta Distributor> distributors; private @Meta List<@Meta Distributor> distributors;
@Override @Override
public Distributor get() { public Distributor get() {
Distributor current = distributors.remove(0); Distributor current = distributors.remove(0);
@ -22,7 +24,7 @@ public class AndDistributorTemplate implements ObjectTemplate<Distributor>, Vali
} }
return current; return current;
} }
@Override @Override
public boolean validate() throws ValidationException { public boolean validate() throws ValidationException {
if(distributors.isEmpty()) throw new ValidationException("AND Distributor must specify at least 1 distributor."); if(distributors.isEmpty()) throw new ValidationException("AND Distributor must specify at least 1 distributor.");

View File

@ -3,19 +3,20 @@ package com.dfsek.terra.addons.feature.distributor.config;
import com.dfsek.tectonic.annotations.Default; import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.addons.feature.distributor.distributors.NoiseDistributor; import com.dfsek.terra.addons.feature.distributor.distributors.NoiseDistributor;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.structure.feature.Distributor; import com.dfsek.terra.api.structure.feature.Distributor;
public class NoiseDistributorTemplate implements ObjectTemplate<Distributor> {
@Value("distribution")
private @Meta NoiseSampler noise;
public class NoiseDistributorTemplate implements ObjectTemplate<Distributor> {
@Value("threshold") @Value("threshold")
@Default @Default
private @Meta double threshold = 0; private final @Meta double threshold = 0;
@Value("distribution")
private @Meta NoiseSampler noise;
@Override @Override
public Distributor get() { public Distributor get() {
return new NoiseDistributor(noise, threshold); return new NoiseDistributor(noise, threshold);

View File

@ -4,16 +4,18 @@ import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ValidatedConfigTemplate; import com.dfsek.tectonic.config.ValidatedConfigTemplate;
import com.dfsek.tectonic.exception.ValidationException; import com.dfsek.tectonic.exception.ValidationException;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.List;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.structure.feature.Distributor; import com.dfsek.terra.api.structure.feature.Distributor;
import java.util.List;
public class OrDistributorTemplate implements ObjectTemplate<Distributor>, ValidatedConfigTemplate { public class OrDistributorTemplate implements ObjectTemplate<Distributor>, ValidatedConfigTemplate {
@Value("distributors") @Value("distributors")
private @Meta List<@Meta Distributor> distributors; private @Meta List<@Meta Distributor> distributors;
@Override @Override
public Distributor get() { public Distributor get() {
Distributor current = distributors.remove(0); Distributor current = distributors.remove(0);
@ -22,7 +24,7 @@ public class OrDistributorTemplate implements ObjectTemplate<Distributor>, Valid
} }
return current; return current;
} }
@Override @Override
public boolean validate() throws ValidationException { public boolean validate() throws ValidationException {
if(distributors.isEmpty()) throw new ValidationException("AND Distributor must specify at least 1 distributor."); if(distributors.isEmpty()) throw new ValidationException("AND Distributor must specify at least 1 distributor.");

View File

@ -2,17 +2,19 @@ package com.dfsek.terra.addons.feature.distributor.config;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import java.util.Set;
import com.dfsek.terra.addons.feature.distributor.distributors.PointSetDistributor; import com.dfsek.terra.addons.feature.distributor.distributors.PointSetDistributor;
import com.dfsek.terra.addons.feature.distributor.util.Point; import com.dfsek.terra.addons.feature.distributor.util.Point;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.structure.feature.Distributor; import com.dfsek.terra.api.structure.feature.Distributor;
import java.util.Set;
public class PointSetDistributorTemplate implements ObjectTemplate<Distributor> { public class PointSetDistributorTemplate implements ObjectTemplate<Distributor> {
@Value("points") @Value("points")
private @Meta Set<@Meta Point> points; private @Meta Set<@Meta Point> points;
@Override @Override
public Distributor get() { public Distributor get() {
return new PointSetDistributor(points); return new PointSetDistributor(points);

View File

@ -3,15 +3,17 @@ package com.dfsek.terra.addons.feature.distributor.distributors;
import com.dfsek.terra.api.noise.NoiseSampler; import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.structure.feature.Distributor; import com.dfsek.terra.api.structure.feature.Distributor;
public class NoiseDistributor implements Distributor { public class NoiseDistributor implements Distributor {
private final NoiseSampler sampler; private final NoiseSampler sampler;
private final double threshold; private final double threshold;
public NoiseDistributor(NoiseSampler sampler, double threshold) { public NoiseDistributor(NoiseSampler sampler, double threshold) {
this.sampler = sampler; this.sampler = sampler;
this.threshold = threshold; this.threshold = threshold;
} }
@Override @Override
public boolean matches(int x, int z, long seed) { public boolean matches(int x, int z, long seed) {
return sampler.getNoiseSeeded(seed, x, z) > threshold; return sampler.getNoiseSeeded(seed, x, z) > threshold;

View File

@ -1,17 +1,18 @@
package com.dfsek.terra.addons.feature.distributor.distributors; package com.dfsek.terra.addons.feature.distributor.distributors;
import java.util.Set;
import com.dfsek.terra.addons.feature.distributor.util.Point; import com.dfsek.terra.addons.feature.distributor.util.Point;
import com.dfsek.terra.api.structure.feature.Distributor; import com.dfsek.terra.api.structure.feature.Distributor;
import java.util.Set;
public class PointSetDistributor implements Distributor { public class PointSetDistributor implements Distributor {
private final Set<Point> points; private final Set<Point> points;
public PointSetDistributor(Set<Point> points) { public PointSetDistributor(Set<Point> points) {
this.points = points; this.points = points;
} }
@Override @Override
public boolean matches(int x, int z, long seed) { public boolean matches(int x, int z, long seed) {
return points.contains(new Point(x, z)); return points.contains(new Point(x, z));

View File

@ -3,28 +3,28 @@ package com.dfsek.terra.addons.feature.distributor.util;
public class Point { public class Point {
private final int x; private final int x;
private final int z; private final int z;
private final int hash; private final int hash;
public Point(int x, int z) { public Point(int x, int z) {
this.x = x; this.x = x;
this.z = z; this.z = z;
this.hash = 31 * x + z; this.hash = 31 * x + z;
} }
public int getX() { public int getX() {
return x; return x;
} }
public int getZ() { public int getZ() {
return z; return z;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return hash; return hash;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if(!(obj instanceof Point)) return false; if(!(obj instanceof Point)) return false;

View File

@ -2,15 +2,17 @@ package com.dfsek.terra.addons.feature.distributor.util;
import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate; import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.config.meta.Meta;
public class PointTemplate implements ObjectTemplate<Point> { public class PointTemplate implements ObjectTemplate<Point> {
@Value("x") @Value("x")
private @Meta int x; private @Meta int x;
@Value("z") @Value("z")
private @Meta int z; private @Meta int z;
@Override @Override
public Point get() { public Point get() {
return new Point(x, z); return new Point(x, z);

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