Compare commits

..

331 Commits

Author SHA1 Message Date
dfsek e887a9f1a1 remove additional events, make Event extend Monad 2022-09-02 22:51:57 -07:00
dfsek 3077178cd2 Merge remote-tracking branch 'origin/ver/7.0.0' into dev/pure 2022-08-28 21:39:36 -07:00
dfsek a0738a3b32 Merge pull request #365 from Astrashh/dev/linear-map
Linear map normalizer
2022-08-24 11:55:08 -07:00
Zoë ee3be35359 Merge pull request #368 from duplexsystem/ver/7.0.0
git is being bad so I'm just pring
2022-08-23 12:58:36 -05:00
Zoë cb6dbe3ec9 fix format 2022-08-23 12:55:18 -05:00
Zoë c40fc4b844 Merge pull request #367 from duplexsystem/ver/7.0.0
fixes
2022-08-22 23:18:32 -05:00
Zoë 2e8bc8d561 sub structures use pos as origin 2022-08-22 22:55:28 -05:00
Zoë 08df8b1652 some fixes 2022-08-22 22:41:26 -05:00
Astrash 3dcfeb987f Add meta annotations 2022-08-23 11:06:32 +10:00
Astrash f0efb4c931 Add default 'from' values for linear map template 2022-08-23 11:02:17 +10:00
Astrash 82596a8ffd Implement linear map normalizer 2022-08-23 11:02:17 +10:00
dfsek 9aa124605c Merge pull request #364 from duplexsystem/ver/7.0.0
oop 2
2022-08-22 17:28:13 -07:00
Zoë ec7f0dacfa oop 2 2022-08-21 21:07:16 -05:00
dfsek 507895636e Merge pull request #363 from duplexsystem/ver/7.0.0
oops
2022-08-21 19:06:42 -07:00
Zoë 32ddc287f7 oops 2022-08-21 20:48:21 -05:00
dfsek 91766599c6 Merge remote-tracking branch 'origin/ver/7.0.0' into dev/pure
# Conflicts:
#	common/addons/biome-provider-pipeline/src/main/java/com/dfsek/terra/addons/biome/pipeline/BiomePipelineAddon.java
#	common/addons/config-distributors/src/main/java/com/dfsek/terra/addons/feature/distributor/DistributorAddon.java
#	common/addons/config-locators/src/main/java/com/dfsek/terra/addons/feature/locator/LocatorAddon.java
2022-08-21 13:40:57 -07:00
dfsek 710c00b0d8 annotate initialize method @NotNull 2022-08-21 13:40:19 -07:00
dfsek b6320c95ea Merge pull request #362 from duplexsystem/dev/enviroment
Dev/enviroment
2022-08-21 13:35:02 -07:00
Zoë 0b8524b08d remove comment 2022-08-21 14:33:57 -05:00
Zoë b5d081fde4 remove more random 2022-08-21 14:29:57 -05:00
Zoë b044b2c48e Merge remote-tracking branch 'origin/ver/7.0.0' into dev/enviroment 2022-08-21 12:30:15 -05:00
Zoë b627ce6e58 Update libs and use libs.versions.toml for dep management 2022-08-21 12:21:12 -05:00
dfsek fcffefe91d clean up PluginConfig 2022-08-21 01:06:24 -07:00
dfsek ec8564df2f remove most references to ConfigPack from API 2022-08-21 01:02:10 -07:00
dfsek 997d2204c7 create config-pack addon project 2022-08-21 00:55:03 -07:00
dfsek 4f687f7587 remove ConfigPack and related interfaces 2022-08-21 00:53:03 -07:00
dfsek 620ae7d1ff make Registry immutable, remove other registry implementations 2022-08-21 00:51:26 -07:00
dfsek 6a53a0c56b Merge pull request #355 from Astrashh/dev/pipeline-reimplementation
Biome pipeline reimplementation
2022-08-20 12:34:48 -07:00
Zoë 5d5408e142 terraScript random is no more 2022-08-19 23:18:42 -05:00
Astrash 2025fe6e90 Merge branch 'ver/7.0.0' into dev/pipeline-reimplementation 2022-08-20 13:05:12 +10:00
Zoë e658a5d917 fix enum to uppcases 2022-08-19 20:36:57 -05:00
Zoë 8c16225ed1 Update ModPlatform.java 2022-08-19 20:36:51 -05:00
Zoë 2d97c776fc Dim opts 2022-08-19 20:36:41 -05:00
Zoë 6cd91bcc1d Random Changes 2022-08-19 20:36:32 -05:00
Zoë 5f5c4f85c7 Fixes 2022-08-19 20:35:01 -05:00
Zoë 1702a46fda Merge remote-tracking branch 'origin/fix/scale-pipeline-264' into ver/7.0.0 2022-08-19 20:34:39 -05:00
Astrash 97b74508f8 Merge branch 'ver/7.0.0' into dev/pipeline-reimplementation 2022-08-19 11:37:55 +10:00
dfsek b04a4850da deprecare getByID 2022-08-18 16:54:16 -07:00
dfsek c8beb0f965 clean up unneeded injects 2022-08-18 16:52:46 -07:00
dfsek 74f9c4f9b1 convert all addons to use monad initialiser 2022-08-16 14:36:03 -07:00
dfsek 45c3729392 update OreAddon to use do notation 2022-08-15 11:12:10 -07:00
dfsek 8538ee6804 add simple do notation for monadic binding 2022-08-15 10:33:25 -07:00
dfsek ee64039f5f add vavr dependency 2022-08-15 10:11:38 -07:00
dfsek 0609a7cf6b implement MonadAddonInitializer 2022-08-15 10:06:29 -07:00
dfsek 97854e3037 create monad and functor interfaces 2022-08-14 19:14:47 -07:00
dfsek a6b193503d Merge pull request #358 from Astrashh/dev/dot-product-slant
Calculate noise3d generator slant with dot product
2022-08-14 19:03:45 -07:00
Astrash 7e6b4a0b74 Calculate slant with approx dot product rather than derivative 2022-08-15 10:34:29 +10:00
Astrash af4465196c Replace sout with logger debug calls 2022-08-07 14:53:13 +10:00
Astrash 68058e7dc6 Remove test class from source 2022-08-07 12:30:22 +10:00
Astrash e30ce62d86 Ephemeral -> Placeholder 2022-08-07 12:23:51 +10:00
Astrash 227a2362af Move reimplementation classes into main package 2022-08-07 12:15:50 +10:00
Astrash eb0c40aafd Handle resolution and biome blending 2022-08-07 11:46:55 +10:00
Astrash 3835533cc9 Working state for pipeline implementation 2022-08-06 22:15:15 +10:00
dfsek b83d4c21e0 factor in resolution 2022-07-16 04:22:29 -07:00
dfsek 145eed893a fix #264 with artifacting 2022-07-16 04:22:28 -07:00
dfsek 3dd3c047b4 Merge pull request #341 from duplexsystem/dev/enviroment
Remove vanilla key, Comminfy Some code, Minor Biome Enviroment Tweaks, Port all Enviroment Settings to Bukkit, and Implment Fertilization
2022-07-14 19:51:16 -07:00
Zoë 1003304fde Reformat 2022-07-14 19:50:25 -07:00
Zoë 04c6363469 Merge remote-tracking branch 'origin/dev/enviroment' into dev/enviroment 2022-07-14 19:43:56 -07:00
Zoë 4b518c28a0 Requested changes 2022-07-14 19:43:50 -07:00
Zoë 199360b981 Update LifecycleEntryPoint.java 2022-07-14 00:45:52 -07:00
Zoë f75880acac Bukkit update 2022-07-14 00:38:54 -07:00
Zoë dd9f421972 Growing 2022-07-12 18:46:32 -07:00
Zoë 5c2998c91c remove more 2022-07-12 13:39:52 -07:00
Zoë 09c0f0acc9 Remove unused config keys 2022-07-12 13:37:28 -07:00
Zoë 970a5c60d9 clean 2022-07-12 13:09:58 -07:00
Zoë d8285bc9a7 make bukkit growing better 2022-07-12 13:04:07 -07:00
Zoë 75b545b0be Bukkit Growing 2022-07-12 01:04:55 -07:00
Zoë 50377a1b89 Fabric/Quilt fertilization support 2022-07-11 21:49:16 -07:00
Zoë ba6d4649c6 remove bukkit 1.18 2022-07-11 15:16:54 -07:00
Zoë a286e26656 Bukkit 2022-07-11 14:57:43 -07:00
Zoë 526e655a8f remove unused key 2022-07-11 13:53:38 -07:00
Zoë f26cedd613 Remove Vanilla Key 2022-07-11 13:49:55 -07:00
Zoë b1b91726ef UX tweaks to biome config 2022-07-10 20:18:49 -07:00
Zoë 796f66e708 We do a little commonifying 2022-07-10 19:38:35 -07:00
dfsek a175601424 disable parallel build 2022-07-07 23:27:20 -07:00
Zoë 7d056bd88c try fix packs 2022-07-07 20:35:46 -07:00
dfsek eb79a6f762 create resources dir if not exist 2022-07-07 18:49:33 -07:00
Zoë 59af552be2 fix bukkit 2022-07-07 12:33:15 -07:00
dfsek d63606a9b1 maybe fix bukkit resource manifest building 2022-07-07 09:10:14 -07:00
dfsek fa0fb3cd15 specify exact arch loom version 2022-07-07 07:03:17 -07:00
dfsek 6c8c4f0e01 remove suspect options 2022-07-06 22:55:40 -07:00
dfsek 155349a00c dont run gradle tasks in parallel 2022-07-06 20:03:07 -07:00
dfsek 5f13536dc3 Merge pull request #329 from PolyhedralDev/ver/6.2.0
Minor version 6.2.0
2022-07-06 19:43:00 -07:00
dfsek 75a2dd7b6e revert formatting of PULL_REQUEST_TEMPLATE.md 2022-07-06 19:36:01 -07:00
dfsek 3cec404c6b specify platform in loom builds 2022-07-06 19:32:23 -07:00
dfsek b3a8f375bc reformat all code 2022-07-06 19:28:07 -07:00
Zoë dc5e71e3de fix tooling hell 2022-07-06 17:32:43 -07:00
dfsek 1d5abbcb6b specify mixin refmaps 2022-07-06 17:15:08 -07:00
dfsek a1acfef721 fix remapping 2022-07-06 16:42:32 -07:00
dfsek 7bef490125 increase Gradle memory 2022-07-06 16:10:29 -07:00
dfsek 8a2c54c85b Merge pull request #335 from duplexsystem/dev/enviroment
make villager biome types work and also quilt
2022-07-06 14:55:05 -07:00
Zoë ef4a28fd23 Revert "remove dep because we shade"
This reverts commit 19e46fbe4c.
2022-07-06 13:05:59 -07:00
Zoë 10d44ce217 Expand the AwfulHacks series 2022-07-06 00:51:47 -07:00
Zoë 36ceabd749 Refactor Mixin build setup 2022-07-06 00:26:42 -07:00
Zoë 29e1d05c71 quilt works! 2022-07-05 22:57:03 -07:00
dfsek f92ecb31a7 Merge remote-tracking branch 'Duplex/dev/enviroment' into dev/enviroment 2022-07-05 18:04:53 -07:00
dfsek b7343ca327 fix typo 2022-07-05 18:04:39 -07:00
Zoë b6d8453042 update QSL 2022-07-05 16:36:30 -07:00
Zoë 0ee359b0a3 Git ignore 2022-07-05 14:18:26 -07:00
Zoë 60046c4664 Revert "Quilt progress 2"
This reverts commit 639fc71f7a.
2022-07-05 14:18:01 -07:00
Zoë b31f917acf Fix cloud in dev env 2022-07-05 14:17:44 -07:00
Zoë 639fc71f7a Quilt progress 2 2022-07-05 12:54:27 -07:00
Zoë 8d19368999 quilt progress 2022-07-05 11:24:18 -07:00
Zoë 19e46fbe4c remove dep because we shade 2022-07-05 02:24:25 -07:00
Zoë d280e113e6 Villagers on lifecycle 2022-07-05 01:58:32 -07:00
Zoë 0e9f9bd2b0 Merge remote-tracking branch 'PolyhedralDev/ver/6.2.0' into dev/enviroment 2022-07-05 01:53:05 -07:00
Zoë 7e883ab5ce Villager Types 2022-07-05 01:52:24 -07:00
dfsek 892ba38fec specify fabric mixin in fabric-quilt shared code 2022-07-05 01:20:50 -07:00
dfsek 5da26e2b53 split most fabric and quilt code into common project 2022-07-05 01:11:32 -07:00
dfsek 2edf365781 create mixin-lifecycle project 2022-07-04 21:13:30 -07:00
dfsek 82920e570f add quilt platform implementation 2022-07-04 20:54:07 -07:00
dfsek f5da9d1dfb Merge pull request #330 from duplexsystem/dev/enviroment
moar biome settings 2: electric boogaloo
2022-07-03 22:11:26 -07:00
Zoë cdb957403e Change memory to align to 1024mb 2022-07-03 13:50:16 -07:00
Zoë 21d8be4726 abstract addon id 2022-07-03 13:44:53 -07:00
Zoë 7a4bf38cbc actually version ify burningwave 2022-06-30 22:00:21 -07:00
Zoë 18de2c3f99 Fix dev launch for fabric and forge 2022-06-30 21:58:11 -07:00
Zoë d7be33fa55 Merge remote-tracking branch 'origin/ver/6.2.0' into dev/enviroment 2022-06-29 14:18:00 -07:00
dfsek ca791026bd bump version 2022-06-27 20:20:23 -07:00
Zoë e21bb5c26d Refractor 2022-06-26 23:58:48 -07:00
Zoë 71aa42011f Spawning! 2022-06-26 23:43:15 -07:00
Zoë b0bf9d042e oops 2022-06-26 22:02:18 -07:00
Zoë dbd5edabae Imports 2022-06-26 21:48:38 -07:00
Zoë 4487be03f1 Merge remote-tracking branch 'duplexsystem/dev/enviroment' into ver/6.2.0 2022-06-26 21:46:18 -07:00
dfsek 3610230c71 Merge pull request #328 from PolyhedralDev/dev/architectury
Use Architectury to share mixins and mod code not dependent on mod loader
2022-06-25 13:34:10 -07:00
dfsek 6e6a378225 Merge pull request #326 from Astrashh/patch-1
Use correct dimensions in TS sampler function
2022-06-24 17:58:04 -07:00
dfsek b05852e074 make slf4j testImplementation 2022-06-24 17:50:40 -07:00
dfsek cffdf7aeeb use Fabric Loom 2022-06-24 16:00:47 -07:00
dfsek e4d05312aa ignore mixins from common package in AwfulForgeHacks 2022-06-24 16:00:35 -07:00
Astrashh 0997326aef Use correct dimensions in TS sampler function 2022-06-24 17:53:54 +10:00
dfsek 3139416b35 rename mod-common to mixin-common 2022-06-22 07:23:39 -07:00
dfsek 42cf7b9543 move DataPackContentsMixin to common 2022-06-22 06:31:38 -07:00
dfsek 2ae4f80351 move tagutil into common 2022-06-22 06:10:41 -07:00
dfsek 3b156586dc common-ify LifecycleUtil 2022-06-21 18:21:54 -07:00
dfsek 6ba4a48e29 move biomeutil stuff into common 2022-06-21 18:00:48 -07:00
dfsek 7c2908e5ca move most mod code into mod common 2022-06-21 17:53:46 -07:00
dfsek 2a24fa56d7 move seedhack into common 2022-06-21 16:01:59 -07:00
dfsek 2a6d130d20 move world handle into common module 2022-06-21 15:48:09 -07:00
dfsek 1a1000bbef fix forge build 2022-06-21 15:38:28 -07:00
dfsek e1cbb29ae4 begin splitting mixins into common 2022-06-21 14:46:50 -07:00
dfsek 37c358e3d1 rename all platform references 2022-06-21 11:12:35 -07:00
dfsek 32b2f15f3b fix chunk generator codec name 2022-06-21 10:26:58 -07:00
dfsek 752f57bbea fix addon ID 2022-06-21 10:26:20 -07:00
dfsek e2bb2d8712 refactor handles 2022-06-21 10:25:52 -07:00
dfsek aeb2da4ede refactor chunk generator wrapper name 2022-06-21 10:25:23 -07:00
dfsek 0c02e4cb9a rename architectury implementation util class 2022-06-21 09:59:54 -07:00
dfsek 546431bbef clean up adapter 2022-06-21 09:59:16 -07:00
dfsek 111eb6b593 fix NoiseConfigMixin 2022-06-21 07:22:07 -07:00
dfsek 7c2982aa0a use registerhelper to register biomes 2022-06-20 23:33:14 -07:00
dfsek e1656bac20 create registry sanity check 2022-06-20 23:25:03 -07:00
dfsek a0225d6ece legitimately evil hack to fix forge weirdness 2022-06-20 23:08:22 -07:00
dfsek 13497a02a4 register stuff with events 2022-06-20 21:46:06 -07:00
dfsek c120ab76d0 Revert "remove RegistryMixin"
This reverts commit 14273268
2022-06-20 21:35:32 -07:00
dfsek a47541cfeb use annotation event subscriptions 2022-06-20 21:34:52 -07:00
dfsek 14273268c8 remove RegistryMixin 2022-06-20 21:03:30 -07:00
dfsek cce9b69c45 load terra data on RegisterEvent 2022-06-20 20:05:02 -07:00
dfsek e85afd7dd6 convert most lifecycle mixins to event listeners 2022-06-20 19:37:17 -07:00
dfsek f3329bbff1 rename mixin configs 2022-06-20 18:33:28 -07:00
dfsek c6428cff66 make slf4j compileOnlyAPI 2022-06-20 13:58:45 -07:00
dfsek cb4c8f28ef clean up bukkit buildscript 2022-06-19 23:27:30 -07:00
dfsek 0829960232 simplify Fabric buildscript 2022-06-19 23:08:52 -07:00
dfsek 924783adb2 clean up buildscript 2022-06-19 22:47:06 -07:00
dfsek 86d34347db graceful fallback if resource cannot be loaded 2022-06-19 22:46:46 -07:00
dfsek ccb8adec10 architectury launches now 2022-06-19 22:11:12 -07:00
dfsek 98a9035ae8 begin architectury implementation 2022-06-19 21:24:22 -07:00
dfsek 536733911b meta annotate BiomeExtrusionTemplate 2022-06-19 17:50:47 -07:00
dfsek 865ec58d70 fix Column erroneously caching 2022-06-19 02:05:36 -07:00
dfsek 33ca98ccaf dont shade caffeine into pipeline addon 2022-06-19 01:01:12 -07:00
dfsek 41fc28e1e9 use biome query API in ReplaceExtrusion 2022-06-19 00:34:03 -07:00
dfsek abca785b1e refactor query addon package 2022-06-19 00:25:54 -07:00
dfsek 92d173cb89 rename tag addon to query addon 2022-06-19 00:20:42 -07:00
dfsek dff2388b37 implement biome query API 2022-06-19 00:19:07 -07:00
dfsek 2f2fb54dea create biome tag API module 2022-06-18 23:58:37 -07:00
dfsek 2daac81565 update to cloud 1.7.0 2022-06-18 23:53:48 -07:00
dfsek 901b58f56a use Caffeine cache in SamplerProvider 2022-06-18 23:52:27 -07:00
dfsek 3000547ee9 cache column in ChunkInterpolator 2022-06-18 23:31:52 -07:00
dfsek 15fec550c7 use column in ChunkInterpolator and NoiseChunkGenerator3D 2022-06-18 03:31:23 -07:00
dfsek c49202017f implement BaseBiomeColumn 2022-06-18 03:14:53 -07:00
dfsek 78d34498d9 add caching option to config pack 2022-06-18 02:33:25 -07:00
dfsek 8a2024e8d8 remove BiomeProviderHolder 2022-06-18 02:02:38 -07:00
dfsek 7de66fecf8 remove ChunkLocalCachingBiomeProvider 2022-06-18 02:01:06 -07:00
dfsek 642372eaa1 add caffeine as API 2022-06-18 01:28:48 -07:00
dfsek 6a95810e65 use max-1 as max Y in LazilyEvaluatedInterpolator 2022-06-18 01:16:36 -07:00
dfsek 4c6c284b93 properly clamp max Y in LazilyEvaluatedInterpolator 2022-06-18 01:10:18 -07:00
dfsek 1d8c012ae5 fix MatchPattern 2022-06-18 00:56:58 -07:00
dfsek 522d4e4d3a use vanilla getBaseColumn 2022-06-17 17:51:30 -07:00
dfsek 915dcf9b9b cache biome providers on Bukkit 2022-06-17 17:39:27 -07:00
dfsek 4dd43ea86d collapse single-entry probability collections to singletons 2022-06-17 16:28:32 -07:00
dfsek 21ec335db9 store cache between same column instances with different clamps 2022-06-17 01:44:21 -07:00
dfsek 46c03438b3 add optimization for AdjacentPatternLocator 2022-06-17 01:34:11 -07:00
dfsek 9ced14b813 clean up 2022-06-17 01:22:07 -07:00
dfsek d2055d60fd optimize caching biomes in CLIWorld 2022-06-17 00:53:34 -07:00
dfsek 529cd463de add cli run task 2022-06-17 00:40:49 -07:00
dfsek ab78bea9aa pull CLI versions to Versions.kt 2022-06-17 00:00:46 -07:00
dfsek 5df016e43e pull bukkit versions to Versions.kt 2022-06-16 23:58:25 -07:00
dfsek cacfd66cf7 pull all fabric versions to Versions.kt 2022-06-16 23:55:22 -07:00
dfsek fce8c823be bump fabric api version 2022-06-16 23:53:21 -07:00
dfsek 036a166909 fix ParserTest 2022-06-16 23:40:52 -07:00
dfsek 36682bc04c add biome sound configs 2022-06-16 22:02:08 -07:00
dfsek 7574c356a0 apply particles on Bukkit 2022-06-16 21:58:48 -07:00
dfsek e1ce5e117c apply vanilla biome particle config 2022-06-16 21:57:50 -07:00
dfsek ef0692977c bump terrascript addon version 2022-06-16 20:17:42 -07:00
dfsek cfdce200dd bump feature stage addon version 2022-06-16 20:17:11 -07:00
dfsek 727f7ce2fb bump locator addon version 2022-06-16 20:16:53 -07:00
dfsek bcae15225f fix matchpattern when min >= max 2022-06-16 17:47:54 -07:00
dfsek baccd04c8d use correct y value in LazilyEvaluatedInterpolator 2022-06-16 17:21:46 -07:00
dfsek 34b1aca556 fix Minecraft bee issue 2022-06-16 16:46:44 -07:00
dfsek ba179c0991 add BeeMoveGoalsUnsynchronizedRandomAccessFix 2022-06-16 16:37:14 -07:00
dfsek 01ba75a29b refactor mixins 2022-06-16 16:17:12 -07:00
dfsek c96e908a1e fix Fabric entity spawning 2022-06-16 15:59:25 -07:00
dfsek 355805347b fix feature context registration 2022-06-16 02:04:31 -07:00
dfsek e13f8163a2 simplify ChunkRegionMixin height accessors 2022-06-16 02:01:24 -07:00
dfsek 099d5f60c8 use propertykey for features 2022-06-16 01:56:44 -07:00
dfsek 80583e1596 add alternative methods for interacting with Context 2022-06-16 01:53:02 -07:00
dfsek c83924a7a4 remove unneeded resolution application 2022-06-15 23:38:29 -07:00
dfsek 9081f3a004 use resolution in CachingBiomeProviders 2022-06-15 23:08:12 -07:00
dfsek cfeeb432ea fully implement resolution in BiomeExtrusionProvider 2022-06-15 21:54:47 -07:00
dfsek c31925f383 add default #resolution method in BiomeProvider 2022-06-15 21:49:41 -07:00
dfsek 72ad5b65df remove unneeded floorToInt in BiomePipelineProvider 2022-06-15 21:49:24 -07:00
dfsek b7c381b0f9 dont use column in ChunkInterpolator 2022-06-15 21:46:20 -07:00
dfsek 7b23aa796f fix OOBE in NoiseChunkGenerator3D when using low res palette 2022-06-15 21:43:02 -07:00
dfsek 2c44857575 fix palette fuzz noise config 2022-06-15 20:23:05 -07:00
dfsek 2001b4c6f8 remove TerraScript PerformanceTest 2022-06-15 20:03:32 -07:00
dfsek d73872a1c6 properly access 3d biomes in LazilyEvaluatedInterpolator 2022-06-15 19:55:06 -07:00
dfsek 23a35f8097 implement blockstate cache in Column 2022-06-15 18:59:12 -07:00
dfsek df4636428c remove unneeded fabric permissions API dependency 2022-06-15 00:09:10 -07:00
dfsek 589e46477e fix low res column 2022-06-14 23:56:02 -07:00
dfsek 11cf4c3a95 add NetherFossilOptimization 2022-06-14 23:23:00 -07:00
dfsek 7d92d273cf dont use range iterator in MatchPattern 2022-06-14 22:42:10 -07:00
dfsek e5fa4fd1f1 remove decimal on whole numbers (keeps parity with old scripts) 2022-06-14 22:18:31 -07:00
dfsek 8c9afc4592 recursively update variable table size 2022-06-14 22:01:54 -07:00
dfsek 3122962dc1 fix Function#applyDouble 2022-06-14 21:54:19 -07:00
dfsek 14e035bf2e use applyDouble and applyBoolean in applicable ops 2022-06-14 21:51:05 -07:00
dfsek b2cc0d48aa use local variable table for terrascript 2022-06-14 21:30:58 -07:00
dfsek 613b96288a add primitive overrides to TerraScript items 2022-06-14 19:09:43 -07:00
dfsek 8b12dda604 fix OOBE with low res column 2022-06-14 18:57:01 -07:00
dfsek 61a40b4825 remove unneeded specialised column impl 2022-06-14 18:56:51 -07:00
dfsek eac8d3b4e8 add resolution parameter to Column#forRanges 2022-06-14 18:34:58 -07:00
dfsek 5799b81414 use chunklocal cache for misses in FabricChunkGeneratorWrapper 2022-06-14 18:32:43 -07:00
dfsek 1aa73bf742 optimise equals and hashCode of SeededVector 2022-06-14 09:07:41 -07:00
dfsek 9f6dcfd71b drastically optimize ChunkLocalCachingBiomeProvider 2022-06-13 23:13:41 -07:00
dfsek d80d653d3a optimization for when palette resolution is 1 2022-06-13 22:46:22 -07:00
dfsek 4f92205085 palette blend resolution default to 1 2022-06-13 22:45:31 -07:00
dfsek b62c4d742f drastically optimize ChunkInterpolator 2022-06-13 22:39:39 -07:00
dfsek 012209cfcf implement palette sparse sampling 2022-06-13 15:42:15 -07:00
dfsek 4d6d14a3d8 inject palette resolution options 2022-06-13 13:56:46 -07:00
dfsek 7f05933a1a add palette resolution config options 2022-06-13 13:54:10 -07:00
dfsek 29d8e7eed4 caching biome provider in BukkitProtoWorld 2022-06-13 10:07:08 -07:00
dfsek 3cf680ab88 Merge remote-tracking branch 'origin/ver/6.1.2' into ver/6.2.0
# Conflicts:
#	platforms/fabric/src/main/resources/terra.mixins.json
2022-06-13 09:57:18 -07:00
dfsek 9abac34b83 Merge pull request #323 from PolyhedralDev/ver/6.1.2
Reimplement Cloud and update Bukkit implementation to 1.19 with Paperweight
2022-06-12 22:26:43 -07:00
dfsek a94c0adeb5 bump versions 2022-06-12 22:22:50 -07:00
dfsek e2088bbbb8 implement stronghold hack on 1.19 bukkit 2022-06-12 22:20:47 -07:00
dfsek 1d7ddc2844 remove ReloadCommandMixin 2022-06-12 21:57:47 -07:00
dfsek 443b372736 reimplement Cloud in Fabric 2022-06-12 21:57:19 -07:00
dfsek 170b3d95ea fix vanilla features generating in terra biomes 2022-06-12 21:57:10 -07:00
dfsek ee88f9e75f apply downfall to 1.19 NMS biomes 2022-06-12 21:36:29 -07:00
dfsek fbc1a38a8d depend on Cloud again in Fabric 2022-06-12 21:33:45 -07:00
dfsek d333b186b1 update cloud to 1.70-SNAPSHOT 2022-06-12 21:31:12 -07:00
dfsek 2363ad8c6c fix reflection proxies 2022-06-12 21:24:19 -07:00
dfsek 55686e2704 shade reflection remapper 2022-06-12 21:20:35 -07:00
dfsek 5a445fefac fix bukkit reobf nms shadow 2022-06-12 20:47:59 -07:00
dfsek 2c85284cfb improve bukkit build 2022-06-12 20:27:14 -07:00
dfsek 0c2a8c6bbc use mapped 1.18 NMS 2022-06-12 18:13:00 -07:00
dfsek b3efaa4f6a use paperweight for 1.18.2 2022-06-12 17:33:14 -07:00
dfsek 69b994df0d 1.19 bukkit compiles now 2022-06-12 17:04:00 -07:00
dfsek 2141e7489e add 1.19 NMS module 2022-06-12 16:12:21 -07:00
dfsek f4f0dca3bd add papermc maven to build setting 2022-06-12 14:33:31 -07:00
dfsek 9d6ad582d8 more clear palette level logic 2022-06-12 01:41:39 -07:00
dfsek 0aadfdb356 allow meta on updatePalette 2022-06-12 01:14:35 -07:00
dfsek 7d6746ad47 allow metaconfiguration on PaletteLayerLoader 2022-06-12 01:02:16 -07:00
dfsek 5409725709 fix palette level when caves use palettes 2022-06-12 00:10:44 -07:00
dfsek 779834267e fix BiomeProviderHolder NPE 2022-06-11 23:56:28 -07:00
dfsek a33982a432 add carving.update-palette option 2022-06-11 23:30:53 -07:00
dfsek 881477c42f use ChunkLocalCachingBiomeProvider 2022-06-11 21:50:04 -07:00
dfsek d58eb699f1 create ChunkLocalCachingBiomeProvider 2022-06-11 21:39:15 -07:00
dfsek 1aa0c715b9 properly implement caching getColumn 2022-06-11 21:16:46 -07:00
dfsek db61729e11 pass caching provider through all stages 2022-06-11 21:11:20 -07:00
dfsek dbadef5672 add null check for biome provider 2022-06-11 20:58:41 -07:00
dfsek aac16414d9 attach caching biome provider to protochunk 2022-06-11 20:50:48 -07:00
dfsek 47d2b66046 fix getHeight again 2022-06-11 12:58:49 -07:00
dfsek e2ba671626 add replace extrusion 2022-06-11 02:46:59 -07:00
dfsek 0cb29e471e use column sampler in NoiseChunkGenerator3D 2022-06-11 02:33:51 -07:00
dfsek ad5435f69d use column in ChunkInterpolator 2022-06-11 02:27:45 -07:00
dfsek c9221ca64c implement feature stage resolution 2022-06-11 01:47:32 -07:00
dfsek e5f0e64cf3 fix ChunkInterpolator 3d biome fetching 2022-06-11 00:33:29 -07:00
dfsek 2c5567296d add extruded biomes to provider list 2022-06-10 18:56:00 -07:00
dfsek 2da54b9843 use base biome in ElevationInterpolator 2022-06-10 18:52:21 -07:00
dfsek 8126f3c2be implement getBaseBiome 2022-06-10 18:50:34 -07:00
dfsek 3b2f2ab679 add optional getBaseBiome method 2022-06-10 18:47:22 -07:00
dfsek ee6ecb9613 fix getHeight in air section 2022-06-10 18:33:58 -07:00
dfsek 12d51e3f27 fix extrusion registration 2022-06-10 18:31:10 -07:00
dfsek d71b1ca984 implement ExtrusionColumn 2022-06-10 18:18:31 -07:00
dfsek 37d98df8c3 use extrusions to calculate biomes 2022-06-10 17:36:16 -07:00
dfsek 132a200e43 create and register SetExtrusionTemplate 2022-06-10 17:33:41 -07:00
dfsek aa5947a9bd create BiomeExtrusionTemplate 2022-06-10 17:15:28 -07:00
dfsek deb6de3d6c implement ReplaceableBiome 2022-06-10 17:09:39 -07:00
dfsek b148401f0f null entity 2022-06-10 15:28:48 -07:00
dfsek 33a39cb237 optimize biome pipeline cache for 3 dimensions 2022-06-10 15:23:06 -07:00
dfsek 8f5d2c80f4 cache biome provider in chunkregion 2022-06-10 15:02:46 -07:00
dfsek 50f895c8f4 begin implementing BiomeExtrusionAddon 2022-06-10 14:48:59 -07:00
dfsek dad0a0bd29 create extrusion biome provider project 2022-06-10 14:15:25 -07:00
dfsek 4a3f21f8f7 add loom-quiltflower plugin 2022-06-10 13:51:35 -07:00
dfsek 47d2ec6bb0 update Loom run addon configuration 2022-06-10 13:39:04 -07:00
dfsek 0e815500d0 update Loom 2022-06-10 13:36:43 -07:00
dfsek 6d2a634686 registerChecked config packs 2022-06-09 23:23:44 -07:00
dfsek 158adb55af bound check SurfaceLocator 2022-06-09 16:09:54 -07:00
dfsek dc80fc1ffb fix BiomeProvider#getColumn 2022-06-09 16:09:46 -07:00
dfsek 09e7d58eaf add ColumnTest#testForRangesContiguous 2022-06-09 15:33:35 -07:00
dfsek cc9f9cc8d8 fix Column 2022-06-09 15:28:33 -07:00
dfsek 7ce8dfbc65 add ColumnTest#testForRangesIndividual 2022-06-09 15:24:43 -07:00
dfsek d95e998e5d add test for Column 2022-06-09 15:21:54 -07:00
dfsek 81023e1d67 bounds check 2022-06-09 14:44:21 -07:00
dfsek 6434b6b213 delegate constructor 2022-06-09 13:39:25 -07:00
dfsek 20c7f2f1fb fix SurfaceLocator 2022-06-09 13:21:48 -07:00
dfsek e5e926cf10 fix column iterator 2022-06-09 13:17:36 -07:00
dfsek 544b3767d2 remove column check 2022-06-09 13:04:05 -07:00
dfsek 876e4b86ae add y to exception message 2022-06-09 08:29:08 -07:00
dfsek 089710247b fix range sample 2022-06-09 08:29:00 -07:00
dfsek 0797c113a6 cache columns in BiomeProvider 2022-06-09 08:12:36 -07:00
dfsek 1e3cb91ed2 fix max/min assignment 2022-06-09 07:52:02 -07:00
dfsek dcc6f025a6 fix oobe in ChunkInterpolator 2022-06-08 23:06:01 -07:00
Zoë f23e7f29fd Merge remote-tracking branch 'origin/ver/6.2.0' into biomestuff 2022-06-08 22:18:49 -05:00
Zoë 3c94b5960d More environment settings for fabric 2022-06-08 22:18:21 -05:00
dfsek 245acde336 use 3d biomes in FeatureGenerationStage 2022-06-08 19:17:00 -07:00
dfsek 53df9a47fc add Column#clamp 2022-06-08 19:13:57 -07:00
dfsek f036bddf9e add Column#forRanges 2022-06-08 19:03:52 -07:00
dfsek 3d4e2e4263 use y-level in ChunkInterpolator 2022-06-08 18:53:57 -07:00
dfsek 111470c9f4 bump noise-chunk-generator-3d addon version 2022-06-08 18:39:45 -07:00
dfsek 8a1d329fd9 use biome y-level for palette in NoiseChunkGenerator3D 2022-06-08 18:39:19 -07:00
dfsek 2307138fa8 add IntObjConsumer and forEach implementation in Column 2022-06-08 18:35:49 -07:00
dfsek 84cb428b6c add BiomeProvider#getColumn 2022-06-08 18:33:31 -07:00
dfsek c46f84a00e create Column interface 2022-06-08 18:27:08 -07:00
527 changed files with 10749 additions and 7873 deletions
+4 -1
View File
@@ -245,4 +245,7 @@ nbdist/
/run/
**/testDir/
**/testDir/
platforms/**/run/**
+5 -2
View File
@@ -63,7 +63,8 @@ to [Terra global moderation team](CODE_OF_CONDUCT.md#Reporting).
## I don't want to read this whole thing I just have a question!!!
> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below.
> **Note:** Please don't file an issue to ask a question. You'll get faster
> results by using the resources below.
We have an official discord server where you can request help from various users
@@ -103,7 +104,9 @@ 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
+3 -3
View File
@@ -1,8 +1,8 @@
preRelease(true)
versionProjects(":common:api", version("6.1.1"))
versionProjects(":common:implementation", version("6.1.1"))
versionProjects(":platforms", version("6.1.1"))
versionProjects(":common:api", version("6.2.0"))
versionProjects(":common:implementation", version("6.2.0"))
versionProjects(":platforms", version("6.2.0"))
allprojects {
+10 -15
View File
@@ -3,25 +3,20 @@ plugins {
kotlin("jvm") version embeddedKotlinVersion
}
buildscript {
configurations.all {
resolutionStrategy {
force("org.ow2.asm:asm:9.3") // TODO: remove when ShadowJar updates ASM version
force("org.ow2.asm:asm-commons:9.3")
}
}
}
repositories {
mavenCentral()
gradlePluginPortal()
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
maven("https://repo.codemc.org/repository/maven-public") {
name = "CodeMC"
}
}
dependencies {
implementation("gradle.plugin.com.github.jengelman.gradle.plugins:shadow:+")
implementation("org.ow2.asm:asm:9.3")
implementation("org.ow2.asm:asm-tree:9.3")
implementation("com.dfsek.tectonic:common:4.2.0")
implementation("org.yaml:snakeyaml:1.27")
implementation(libs.libraries.internal.shadow)
implementation(libs.libraries.internal.asm)
implementation(libs.libraries.internal.asm.tree)
implementation(libs.libraries.tectonic)
implementation(libs.libraries.snakeyaml)
}
+7
View File
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
+22 -22
View File
@@ -12,30 +12,30 @@ import kotlin.streams.asStream
*/
fun Project.addonDir(dir: File, task: Task) {
val moveAddons = tasks.register("moveAddons" + task.name) {
dependsOn("compileAddons")
doLast {
dir.parentFile.mkdirs()
matchingAddons(dir) {
it.name.startsWith("Terra-") // Assume everything that starts with Terra- is a core addon.
}.forEach {
println("Deleting old addon: " + it.absolutePath)
it.delete()
}
forSubProjects(":common:addons") {
val jar = tasks.named("shadowJar").get() as ShadowJar
val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else ""
val target = File(dir, boot + jar.archiveFileName.get())
val base = "${jar.archiveBaseName.get()}-${version}"
println("Copying addon ${jar.archiveFileName.get()} to ${target.absolutePath}. Base name: $base")
jar.archiveFile.orNull?.asFile?.copyTo(target)
}
dependsOn("compileAddons")
doLast {
dir.parentFile.mkdirs()
matchingAddons(dir) {
it.name.startsWith("Terra-") // Assume everything that starts with Terra- is a core addon.
}.forEach {
println("Deleting old addon: " + it.absolutePath)
it.delete()
}
forSubProjects(":common:addons") {
val jar = tasks.named("shadowJar").get() as ShadowJar
val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else ""
val target = File(dir, boot + jar.archiveFileName.get())
val base = "${jar.archiveBaseName.get()}-${version}"
println("Copying addon ${jar.archiveFileName.get()} to ${target.absolutePath}. Base name: $base")
jar.archiveFile.orNull?.asFile?.copyTo(target)
}
}
}
task.dependsOn(moveAddons)
}
+31 -10
View File
@@ -5,6 +5,8 @@ import org.gradle.kotlin.dsl.getValue
import org.gradle.kotlin.dsl.getting
import org.gradle.kotlin.dsl.maven
import org.gradle.kotlin.dsl.repositories
import org.gradle.api.artifacts.VersionCatalog
import org.gradle.kotlin.dsl.apply
fun Project.configureDependencies() {
val testImplementation by configurations.getting
@@ -15,6 +17,8 @@ fun Project.configureDependencies() {
val shaded by configurations.creating
val libs = rootProject.project.versionCatalogs.libs
@Suppress("UNUSED_VARIABLE")
val shadedApi by configurations.creating {
shaded.extendsFrom(this)
@@ -30,18 +34,35 @@ fun Project.configureDependencies() {
repositories {
mavenCentral()
gradlePluginPortal()
maven("https://maven.fabricmc.net/")
maven("https://repo.codemc.org/repository/maven-public")
maven("https://repo.codemc.io/repository/nms/")
maven("https://papermc.io/repo/repository/maven-public/")
maven("https://maven.fabricmc.net/") {
name = "FabricMC"
}
maven("https://repo.codemc.org/repository/maven-public") {
name = "CodeMC"
}
maven("https://papermc.io/repo/repository/maven-public/") {
name = "PaperMC"
}
maven("https://files.minecraftforge.net/maven/") {
name = "Forge"
}
maven("https://maven.quiltmc.org/repository/release/") {
name = "Quilt"
}
maven("https://jitpack.io") {
name = "JitPack"
}
maven("https://api.modrinth.com/maven") {
name = "Modrinth"
}
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.7.0")
compileOnly("org.jetbrains:annotations:23.0.0")
compileOnly("com.google.guava:guava:30.0-jre")
testImplementation("com.google.guava:guava:30.0-jre")
testImplementation(libs.findLibrary("libraries.internal.junit.jupiter.api").get())
testImplementation(libs.findLibrary("libraries.internal.junit.jupiter.engine").get())
compileOnly(libs.findLibrary("libraries.internal.jetbrains.annotations").get())
compileOnly(libs.findLibrary("libraries.guava").get())
testImplementation(libs.findLibrary("libraries.guava").get())
}
}
+11 -7
View File
@@ -7,12 +7,9 @@ import java.nio.file.Files
import java.nio.file.StandardCopyOption
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.BasePluginExtension
import org.gradle.jvm.tasks.Jar
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.creating
import org.gradle.kotlin.dsl.extra
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.named
@@ -55,7 +52,7 @@ fun Project.configureDistribution() {
println("Packaging addon ${jar.archiveFileName.get()} to $dest. size: ${jar.archiveFile.get().asFile.length() / 1024}KB")
val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else ""
val addonPath = fs.getPath("/addons/$boot${jar.archiveFileName.get()}");
val addonPath = fs.getPath("/addons/$boot${jar.archiveFileName.get()}")
if (!Files.exists(addonPath)) {
Files.createDirectories(addonPath.parent)
@@ -70,7 +67,6 @@ fun Project.configureDistribution() {
val generateResourceManifest = tasks.create("generateResourceManifest") {
group = "terra"
dependsOn(downloadDefaultPacks)
doLast {
val resources = HashMap<String, MutableList<String>>()
val packsDir = File("${project.buildDir}/resources/main/packs/")
@@ -108,12 +104,20 @@ fun Project.configureDistribution() {
val manifest = File("${project.buildDir}/resources/main/resources.yml")
if (manifest.exists()) manifest.delete()
manifest.parentFile.mkdirs()
manifest.createNewFile()
yaml.dump(resources, FileWriter(manifest))
FileWriter(manifest).use {
yaml.dump(resources, it)
}
}
}
tasks["processResources"].dependsOn(generateResourceManifest)
tasks.named("processResources") {
generateResourceManifest.mustRunAfter(downloadDefaultPacks)
finalizedBy(downloadDefaultPacks)
finalizedBy(generateResourceManifest)
}
tasks.named<ShadowJar>("shadowJar") {
+12
View File
@@ -0,0 +1,12 @@
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.api.artifacts.VersionCatalog
import org.gradle.api.Project
import org.gradle.kotlin.dsl.*
internal
val Project.versionCatalogs: VersionCatalogsExtension
get() = the<VersionCatalogsExtension>()
internal
val VersionCatalogsExtension.libs: VersionCatalog
get() = named("libs")
-40
View File
@@ -1,40 +0,0 @@
object Versions {
object Libraries {
const val tectonic = "4.2.0"
const val paralithic = "0.7.0"
const val strata = "1.1.1"
const val cloud = "1.6.2"
const val slf4j = "1.7.36"
const val log4j_slf4j_impl = "2.14.1"
object Internal {
const val apacheText = "1.9"
const val jafama = "2.3.2"
const val apacheIO = "2.6"
const val fastutil = "8.5.6"
}
}
object Fabric {
const val fabricLoader = "0.14.2"
const val fabricAPI = "0.55.1+1.19"
const val minecraft = "1.19"
const val yarn = "$minecraft+build.1"
const val permissionsAPI = "0.1-SNAPSHOT"
const val mixin = "0.11.2+mixin.0.8.5"
const val loom = "0.11-SNAPSHOT"
}
object Bukkit {
const val paper = "1.18-R0.1-SNAPSHOT"
const val paperLib = "1.0.5"
}
object Sponge {
const val sponge = "9.0.0-SNAPSHOT"
const val mixin = "0.8.2"
const val minecraft = "1.17.1"
}
}
@@ -0,0 +1,6 @@
version = version("1.0.0")
dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader"))
compileOnlyApi(project(":common:addons:biome-query-api"))
}
@@ -0,0 +1,51 @@
package com.dfsek.terra.addons.biome.extrusion;
import com.dfsek.terra.api.util.Column;
import com.dfsek.terra.api.world.biome.Biome;
class BaseBiomeColumn implements Column<Biome> {
private final BiomeExtrusionProvider biomeProvider;
private final Biome base;
private final int min;
private final int max;
private final int x;
private final int z;
private final long seed;
protected BaseBiomeColumn(BiomeExtrusionProvider biomeProvider, Biome base, int min, int max, int x, int z, long seed) {
this.biomeProvider = biomeProvider;
this.base = base;
this.min = min;
this.max = max;
this.x = x;
this.z = z;
this.seed = seed;
}
@Override
public int getMinY() {
return min;
}
@Override
public int getMaxY() {
return max;
}
@Override
public int getX() {
return x;
}
@Override
public int getZ() {
return z;
}
@Override
public Biome get(int y) {
return biomeProvider.extrude(base, x, y, z, seed);
}
}
@@ -0,0 +1,69 @@
package com.dfsek.terra.addons.biome.extrusion;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import java.util.function.Supplier;
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
import com.dfsek.terra.addons.biome.extrusion.config.BiomeExtrusionTemplate;
import com.dfsek.terra.addons.biome.extrusion.config.ReplaceableBiomeLoader;
import com.dfsek.terra.addons.biome.extrusion.config.extrusions.ReplaceExtrusionTemplate;
import com.dfsek.terra.addons.biome.extrusion.config.extrusions.SetExtrusionTemplate;
import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.generic.Construct;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import org.jetbrains.annotations.NotNull;
public class BiomeExtrusionAddon implements MonadAddonInitializer {
public static final TypeKey<Supplier<ObjectTemplate<Extrusion>>> EXTRUSION_REGISTRY_KEY = new TypeKey<>() {
};
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
};
@Override
public @NotNull Monad<?, Init<?>> initialize() {
return Do.with(
Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
Get.addon(),
Get.platform(),
((functionalEventHandler, base, platform) -> Init.ofPure(Construct.construct(() -> {
functionalEventHandler.register(base, ConfigPackPostLoadEvent.class)
.then(event -> {
Registry<Biome> biomeRegistry = event.getPack().getRegistry(Biome.class);
event.getPack().applyLoader(ReplaceableBiome.class,
new ReplaceableBiomeLoader(biomeRegistry));
});
return functionalEventHandler.register(base, ConfigPackPreLoadEvent.class)
.then(event -> {
Registry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry =
event.getPack()
.createRegistry(PROVIDER_REGISTRY_KEY);
providerRegistry.register(base.key("EXTRUSION"), BiomeExtrusionTemplate::new);
})
.then(event -> {
Registry<Supplier<ObjectTemplate<Extrusion>>> extrusionRegistry =
event.getPack().createRegistry(
EXTRUSION_REGISTRY_KEY);
extrusionRegistry.register(base.key("SET"), SetExtrusionTemplate::new);
extrusionRegistry.register(base.key("REPLACE"), ReplaceExtrusionTemplate::new);
})
.failThrough();
}))
));
}
}
@@ -0,0 +1,67 @@
package com.dfsek.terra.addons.biome.extrusion;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
import com.dfsek.terra.api.util.Column;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class BiomeExtrusionProvider implements BiomeProvider {
private final BiomeProvider delegate;
private final Set<Biome> biomes;
private final List<Extrusion> extrusions;
private final int resolution;
public BiomeExtrusionProvider(BiomeProvider delegate, List<Extrusion> extrusions, int resolution) {
this.delegate = delegate;
this.biomes = delegate.stream().collect(Collectors.toSet());
extrusions.forEach(e -> biomes.addAll(e.getBiomes()));
this.extrusions = extrusions;
this.resolution = resolution;
}
@Override
public Biome getBiome(int x, int y, int z, long seed) {
Biome delegated = delegate.getBiome(x, y, z, seed);
return extrude(delegated, x, y, z, seed);
}
public Biome extrude(Biome original, int x, int y, int z, long seed) {
for(Extrusion extrusion : extrusions) {
original = extrusion.extrude(original, x, y, z, seed);
}
return original;
}
@Override
public Column<Biome> getColumn(int x, int z, long seed, int min, int max) {
return delegate.getBaseBiome(x, z, seed)
.map(base -> (Column<Biome>) new BaseBiomeColumn(this, base, min, max, x, z, seed))
.orElseGet(() -> BiomeProvider.super.getColumn(x, z, seed, min, max));
}
@Override
public Optional<Biome> getBaseBiome(int x, int z, long seed) {
return delegate.getBaseBiome(x, z, seed);
}
@Override
public Iterable<Biome> getBiomes() {
return biomes;
}
@Override
public int resolution() {
return resolution;
}
public BiomeProvider getDelegate() {
return delegate;
}
}
@@ -0,0 +1,12 @@
package com.dfsek.terra.addons.biome.extrusion.api;
import java.util.Collection;
import com.dfsek.terra.api.world.biome.Biome;
public interface Extrusion {
Biome extrude(Biome original, int x, int y, int z, long seed);
Collection<Biome> getBiomes();
}
@@ -0,0 +1,23 @@
package com.dfsek.terra.addons.biome.extrusion.api;
import com.dfsek.terra.api.world.biome.Biome;
final class PresentBiome implements ReplaceableBiome {
private final Biome biome;
PresentBiome(Biome biome) {
this.biome = biome;
}
@Override
public Biome get(Biome existing) {
return biome;
}
@Override
public boolean isSelf() {
return false;
}
}
@@ -0,0 +1,31 @@
package com.dfsek.terra.addons.biome.extrusion.api;
import java.util.Optional;
import com.dfsek.terra.api.world.biome.Biome;
/**
* Basically just a specialised implementation of {@link Optional} for biomes where a biome may be a "self" reference.
*/
public sealed interface ReplaceableBiome permits PresentBiome, SelfBiome {
static ReplaceableBiome of(Biome biome) {
return new PresentBiome(biome);
}
static ReplaceableBiome self() {
return SelfBiome.INSTANCE;
}
Biome get(Biome existing);
default Biome get() {
if(isSelf()) {
throw new IllegalStateException("Cannot get() self biome!");
}
return get(null);
}
boolean isSelf();
}
@@ -0,0 +1,21 @@
package com.dfsek.terra.addons.biome.extrusion.api;
import java.util.Objects;
import com.dfsek.terra.api.world.biome.Biome;
final class SelfBiome implements ReplaceableBiome {
public static final SelfBiome INSTANCE = new SelfBiome();
@Override
public Biome get(Biome existing) {
return Objects.requireNonNull(existing);
}
@Override
public boolean isSelf() {
return true;
}
}
@@ -0,0 +1,30 @@
package com.dfsek.terra.addons.biome.extrusion.config;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import java.util.List;
import com.dfsek.terra.addons.biome.extrusion.BiomeExtrusionProvider;
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class BiomeExtrusionTemplate implements ObjectTemplate<BiomeProvider> {
@Value("provider")
private @Meta BiomeProvider provider;
@Value("resolution")
@Default
private @Meta int resolution = 4;
@Value("extrusions")
private @Meta List<@Meta Extrusion> extrusions;
@Override
public BiomeProvider get() {
return new BiomeExtrusionProvider(provider, extrusions, resolution);
}
}
@@ -0,0 +1,32 @@
package com.dfsek.terra.addons.biome.extrusion.config;
import com.dfsek.tectonic.api.depth.DepthTracker;
import com.dfsek.tectonic.api.exception.LoadException;
import com.dfsek.tectonic.api.loader.ConfigLoader;
import com.dfsek.tectonic.api.loader.type.TypeLoader;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.AnnotatedType;
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.world.biome.Biome;
public class ReplaceableBiomeLoader implements TypeLoader<ReplaceableBiome> {
private final Registry<Biome> biomeRegistry;
public ReplaceableBiomeLoader(Registry<Biome> biomeRegistry) {
this.biomeRegistry = biomeRegistry;
}
@Override
public ReplaceableBiome load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker)
throws LoadException {
if(c.equals("SELF")) return ReplaceableBiome.self();
return biomeRegistry
.getByID((String) c)
.map(ReplaceableBiome::of)
.orElseThrow(() -> new LoadException("No such biome: " + c, depthTracker));
}
}
@@ -0,0 +1,23 @@
package com.dfsek.terra.addons.biome.extrusion.config.extrusions;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
import com.dfsek.terra.addons.biome.extrusion.extrusions.ReplaceExtrusion;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class ReplaceExtrusionTemplate extends SamplerExtrusionTemplate {
@Value("to")
private @Meta ProbabilityCollection<@Meta ReplaceableBiome> biomes;
@Value("from")
private @Meta String fromTag;
@Override
public Extrusion get() {
return new ReplaceExtrusion(sampler, range, biomes, fromTag);
}
}
@@ -0,0 +1,18 @@
package com.dfsek.terra.addons.biome.extrusion.config.extrusions;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.Range;
public abstract class SamplerExtrusionTemplate implements ObjectTemplate<Extrusion> {
@Value("sampler")
protected @Meta NoiseSampler sampler;
@Value("range")
protected @Meta Range range;
}
@@ -0,0 +1,20 @@
package com.dfsek.terra.addons.biome.extrusion.config.extrusions;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
import com.dfsek.terra.addons.biome.extrusion.extrusions.SetExtrusion;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class SetExtrusionTemplate extends SamplerExtrusionTemplate {
@Value("to")
private @Meta ProbabilityCollection<@Meta ReplaceableBiome> biomes;
@Override
public Extrusion get() {
return new SetExtrusion(sampler, range, biomes);
}
}
@@ -0,0 +1,52 @@
package com.dfsek.terra.addons.biome.extrusion.extrusions;
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
import com.dfsek.terra.addons.biome.query.api.BiomeQueries;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.Biome;
/**
* Sets biomes at locations based on a sampler.
*/
public class ReplaceExtrusion implements Extrusion {
private final NoiseSampler sampler;
private final Range range;
private final ProbabilityCollection<ReplaceableBiome> biomes;
private final Predicate<Biome> hasTag;
public ReplaceExtrusion(NoiseSampler sampler, Range range, ProbabilityCollection<ReplaceableBiome> biomes, String tag) {
this.sampler = sampler;
this.range = range;
this.biomes = biomes;
this.hasTag = BiomeQueries.has(tag);
}
@Override
public Biome extrude(Biome original, int x, int y, int z, long seed) {
if(hasTag.test(original)) {
return range.ifInRange(y, () -> biomes.get(sampler, x, y, z, seed).get(original), original);
}
return original;
}
@Override
public Collection<Biome> getBiomes() {
return biomes
.getContents()
.stream()
.filter(Predicate.not(ReplaceableBiome::isSelf))
.map(ReplaceableBiome::get)
.collect(Collectors.toSet());
}
}
@@ -0,0 +1,45 @@
package com.dfsek.terra.addons.biome.extrusion.extrusions;
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion;
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.Biome;
/**
* Sets biomes at locations based on a sampler.
*/
public class SetExtrusion implements Extrusion {
private final NoiseSampler sampler;
private final Range range;
private final ProbabilityCollection<ReplaceableBiome> biomes;
public SetExtrusion(NoiseSampler sampler, Range range, ProbabilityCollection<ReplaceableBiome> biomes) {
this.sampler = sampler;
this.range = range;
this.biomes = biomes;
}
@Override
public Biome extrude(Biome original, int x, int y, int z, long seed) {
return range.ifInRange(y, () -> biomes.get(sampler, x, y, z, seed).get(original), original);
}
@Override
public Collection<Biome> getBiomes() {
return biomes
.getContents()
.stream()
.filter(Predicate.not(ReplaceableBiome::isSelf))
.map(ReplaceableBiome::get)
.collect(Collectors.toSet());
}
}
@@ -0,0 +1,14 @@
schema-version: 1
contributors:
- Terra contributors
id: biome-provider-extrusion
version: @VERSION@
entrypoints:
- "com.dfsek.terra.addons.biome.extrusion.BiomeExtrusionAddon"
website:
issues: https://github.com/PolyhedralDev/Terra/issues
source: https://github.com/PolyhedralDev/Terra
docs: https://terra.polydev.org
license: MIT License
depends:
biome-query-api: "1.+"
@@ -2,10 +2,4 @@ version = version("1.0.0")
dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader"))
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
}
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
relocate("net.jafama", "com.dfsek.terra.addons.biome.image.lib.jafama")
}
@@ -13,6 +13,7 @@ import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import com.dfsek.terra.api.world.biome.Biome;
@@ -38,6 +39,10 @@ public class ImageBiomeProvider implements BiomeProvider {
@Override
public Biome getBiome(int x, int y, int z, long seed) {
return getBiome(x, z);
}
public Biome getBiome(int x, int z) {
x /= resolution;
z /= resolution;
Color color = align.getColor(image, x, z);
@@ -51,6 +56,11 @@ public class ImageBiomeProvider implements BiomeProvider {
}));
}
@Override
public Optional<Biome> getBaseBiome(int x, int z, long seed) {
return Optional.of(getBiome(x, z));
}
@Override
public Iterable<Biome> getBiomes() {
return colorBiomeMap.values();
@@ -11,39 +11,41 @@ import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import java.util.function.Supplier;
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import org.jetbrains.annotations.NotNull;
public class ImageBiomeProviderAddon implements AddonInitializer {
public class ImageBiomeProviderAddon implements MonadAddonInitializer {
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
};
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override
public void initialize() {
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(addon, ConfigPackPreLoadEvent.class)
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(
PROVIDER_REGISTRY_KEY);
providerRegistry.register(addon.key("IMAGE"),
() -> new ImageProviderTemplate(event.getPack().getRegistry(Biome.class)));
})
.failThrough();
public @NotNull Monad<?, Init<?>> initialize() {
return Do.with(
Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
Get.addon(),
Get.platform(),
((functionalEventHandler, base, platform) -> Init.ofPure(
functionalEventHandler.register(base, ConfigPackPreLoadEvent.class)
.then(event -> {
Registry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().createRegistry(
PROVIDER_REGISTRY_KEY);
providerRegistry.register(base.key("IMAGE"),
() -> new ImageProviderTemplate(event.getPack().getRegistry(Biome.class)));
})
.failThrough()))
);
}
}
@@ -1,14 +1,5 @@
version = version("1.0.0")
version = version("1.0.1")
dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader"))
implementation("com.github.ben-manes.caffeine:caffeine:3.1.0")
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
}
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
relocate("com.github.benmanes.caffeine", "com.dfsek.terra.addons.biome.pipeline.lib.caffeine")
relocate("net.jafama", "com.dfsek.terra.addons.biome.pipeline.lib.jafama")
}
@@ -1,94 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeExpander;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.util.vector.Vector2;
public class BiomeHolderImpl implements BiomeHolder {
private final Vector2.Mutable origin;
private final int width;
private final int offset;
private BiomeDelegate[][] biomes;
public BiomeHolderImpl(int width, Vector2.Mutable origin) {
width += 4;
this.width = width;
biomes = new BiomeDelegate[width][width];
this.origin = origin;
this.offset = 2;
}
private BiomeHolderImpl(BiomeDelegate[][] biomes, Vector2.Mutable origin, int width, int offset) {
this.biomes = biomes;
this.origin = origin;
this.width = width;
this.offset = 2 * offset;
}
@Override
public BiomeHolder expand(BiomeExpander expander, long seed) {
BiomeDelegate[][] old = biomes;
int newWidth = width * 2 - 1;
biomes = new BiomeDelegate[newWidth][newWidth];
for(int x = 0; x < width; x++) {
for(int z = 0; z < width; z++) {
biomes[x * 2][z * 2] = old[x][z];
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]);
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]);
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]);
}
}
return new BiomeHolderImpl(biomes, origin.setX(origin.getX() * 2 - 1).setZ(origin.getZ() * 2 - 1), newWidth, offset);
}
@Override
public void mutate(BiomeMutator mutator, long seed) {
for(int x = 0; x < width; x++) {
for(int z = 0; z < width; z++) {
BiomeMutator.ViewPoint viewPoint = new BiomeMutator.ViewPoint(this, x, z);
biomes[x][z] = mutator.mutate(viewPoint, x + origin.getX(), z + origin.getZ(), seed);
}
}
}
@Override
public void fill(BiomeSource source, long seed) {
for(int x = 0; x < width; x++) {
for(int z = 0; z < width; z++) {
biomes[x][z] = source.getBiome(origin.getX() + x, origin.getZ() + z, seed);
}
}
}
@Override
public BiomeDelegate getBiome(int x, int z) {
x += offset;
z += offset;
return getBiomeRaw(x, z);
}
@Override
public BiomeDelegate getBiomeRaw(int x, int z) {
if(x >= width || z >= width || x < 0 || z < 0) return null;
return biomes[x][z];
}
}
@@ -1,83 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.api.util.vector.Vector2;
public class BiomePipeline {
private final BiomeSource source;
private final List<Stage> stages;
private final int size;
private final int init;
private BiomePipeline(BiomeSource source, List<Stage> stages, int size, int init) {
this.source = source;
this.stages = stages;
this.size = size;
this.init = init;
}
/**
* Get biomes in a chunk
*
* @param x Chunk X coord
* @param z Chunk Z coord
*
* @return BiomeHolder containing biomes.
*/
public BiomeHolder getBiomes(int x, int z, long seed) {
BiomeHolder holder = new BiomeHolderImpl(init, Vector2.of(x * (init - 1), z * (init - 1)).mutable());
holder.fill(source, seed);
for(Stage stage : stages) holder = stage.apply(holder, seed);
return holder;
}
public BiomeSource getSource() {
return source;
}
public List<Stage> getStages() {
return Collections.unmodifiableList(stages);
}
public int getSize() {
return size;
}
public static final class BiomePipelineBuilder {
private final int init;
private final List<Stage> stages = new ArrayList<>();
private int expand;
public BiomePipelineBuilder(int init) {
this.init = init;
expand = init;
}
public BiomePipeline build(BiomeSource source) {
for(Stage stage : stages) {
if(stage.isExpansion()) expand = expand * 2 - 1;
}
return new BiomePipeline(source, stages, expand, init);
}
public BiomePipelineBuilder addStage(Stage stage) {
stages.add(stage);
return this;
}
}
}
@@ -11,79 +11,84 @@ import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import java.util.function.Supplier;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.config.BiomeDelegateLoader;
import com.dfsek.terra.addons.biome.pipeline.config.BiomePipelineTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.SamplerSourceTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.PipelineBiomeLoader;
import com.dfsek.terra.addons.biome.pipeline.config.source.SamplerSourceTemplate;
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.BorderMutatorTemplate;
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.SmoothMutatorTemplate;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.BorderListStageTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.BorderStageTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.ReplaceListStageTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.ReplaceStageTemplate;
import com.dfsek.terra.addons.biome.pipeline.config.stage.mutator.SmoothStageTemplate;
import com.dfsek.terra.addons.biome.pipeline.api.Source;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.generic.Construct;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class BiomePipelineAddon implements AddonInitializer {
public class BiomePipelineAddon implements MonadAddonInitializer {
public static final TypeKey<Supplier<ObjectTemplate<BiomeSource>>> SOURCE_REGISTRY_KEY = new TypeKey<>() {
public static final TypeKey<Supplier<ObjectTemplate<Source>>> 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<>() {
};
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override
public void initialize() {
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(addon, ConfigPackPreLoadEvent.class)
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(
PROVIDER_REGISTRY_KEY);
providerRegistry.register(addon.key("PIPELINE"), BiomePipelineTemplate::new);
})
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeSource>>> sourceRegistry = event.getPack().getOrCreateRegistry(
SOURCE_REGISTRY_KEY);
sourceRegistry.register(addon.key("SAMPLER"), SamplerSourceTemplate::new);
})
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<Stage>>> stageRegistry = event.getPack().getOrCreateRegistry(
STAGE_REGISTRY_KEY);
stageRegistry.register(addon.key("FRACTAL_EXPAND"), ExpanderStageTemplate::new);
stageRegistry.register(addon.key("SMOOTH"), SmoothMutatorTemplate::new);
stageRegistry.register(addon.key("REPLACE"), ReplaceMutatorTemplate::new);
stageRegistry.register(addon.key("REPLACE_LIST"), ReplaceListMutatorTemplate::new);
stageRegistry.register(addon.key("BORDER"), BorderMutatorTemplate::new);
stageRegistry.register(addon.key("BORDER_LIST"), BorderListMutatorTemplate::new);
})
.failThrough();
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(addon, ConfigPackPostLoadEvent.class)
.then(event -> {
Registry<Biome> biomeRegistry = event.getPack().getRegistry(Biome.class);
event.getPack().applyLoader(BiomeDelegate.class, new BiomeDelegateLoader(biomeRegistry));
});
public Monad<?, Init<?>> initialize() {
return Do.with(
Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
Get.addon(),
((functionalEventHandler, base) -> Init.ofPure(Construct.construct(() -> {
functionalEventHandler.register(base, ConfigPackPreLoadEvent.class)
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry =
event.getPack().getOrCreateRegistry(
PROVIDER_REGISTRY_KEY);
providerRegistry.register(base.key("PIPELINE"), BiomePipelineTemplate::new);
})
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<Source>>> sourceRegistry =
event.getPack().getOrCreateRegistry(
SOURCE_REGISTRY_KEY);
sourceRegistry.register(base.key("SAMPLER"), SamplerSourceTemplate::new);
})
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<Stage>>> stageRegistry =
event.getPack().getOrCreateRegistry(
STAGE_REGISTRY_KEY);
stageRegistry.register(base.key("FRACTAL_EXPAND"), ExpanderStageTemplate::new);
stageRegistry.register(base.key("SMOOTH"), SmoothStageTemplate::new);
stageRegistry.register(base.key("REPLACE"), ReplaceStageTemplate::new);
stageRegistry.register(base.key("REPLACE_LIST"), ReplaceListStageTemplate::new);
stageRegistry.register(base.key("BORDER"), BorderStageTemplate::new);
stageRegistry.register(base.key("BORDER_LIST"), BorderListStageTemplate::new);
})
.failThrough();
return functionalEventHandler.register(base, ConfigPackPostLoadEvent.class)
.then(event -> {
Registry<Biome> biomeRegistry = event.getPack().getRegistry(Biome.class);
event.getPack().applyLoader(PipelineBiome.class,
new PipelineBiomeLoader(biomeRegistry));
});
})))
);
}
}
@@ -0,0 +1,71 @@
package com.dfsek.terra.addons.biome.pipeline;
import java.util.function.Consumer;
import com.dfsek.terra.api.util.Column;
import com.dfsek.terra.api.util.function.IntIntObjConsumer;
import com.dfsek.terra.api.util.function.IntObjConsumer;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class BiomePipelineColumn implements Column<Biome> {
private final int min;
private final int max;
private final int x;
private final int z;
private final Biome biome;
protected BiomePipelineColumn(BiomeProvider biomeProvider, int min, int max, int x, int z, long seed) {
this.min = min;
this.max = max;
this.x = x;
this.z = z;
this.biome = biomeProvider.getBiome(x, 0, z, seed);
}
@Override
public int getMinY() {
return min;
}
@Override
public int getMaxY() {
return max;
}
@Override
public int getX() {
return x;
}
@Override
public int getZ() {
return z;
}
@Override
public Biome get(int y) {
return biome;
}
@Override
public void forRanges(int resolution, IntIntObjConsumer<Biome> consumer) {
consumer.accept(min, max, biome);
}
@Override
public void forEach(Consumer<Biome> consumer) {
for(int y = min; y < max; y++) {
consumer.accept(biome);
}
}
@Override
public void forEach(IntObjConsumer<Biome> consumer) {
for(int y = min; y < max; y++) {
consumer.accept(y, biome);
}
}
}
@@ -1,97 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import net.jafama.FastMath;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.StreamSupport;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.registry.key.StringIdentifiable;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class BiomePipelineProvider implements BiomeProvider {
private final LoadingCache<SeededVector, BiomeHolder> holderCache;
private final BiomePipeline pipeline;
private final int resolution;
private final NoiseSampler mutator;
private final double noiseAmp;
private final Set<Biome> biomes;
public BiomePipelineProvider(BiomePipeline pipeline, int resolution, NoiseSampler mutator, double noiseAmp) {
this.resolution = resolution;
this.mutator = mutator;
this.noiseAmp = noiseAmp;
holderCache = Caffeine.newBuilder()
.maximumSize(1024)
.build(key -> pipeline.getBiomes(key.x, key.z, key.seed));
this.pipeline = pipeline;
Set<BiomeDelegate> biomeSet = new HashSet<>();
pipeline.getSource().getBiomes().forEach(biomeSet::add);
Iterable<BiomeDelegate> result = biomeSet;
for(Stage stage : pipeline.getStages()) {
result = stage.getBiomes(result); // pass through all stages
}
this.biomes = new HashSet<>();
Iterable<BiomeDelegate> finalResult = result;
result.forEach(biomeDelegate -> {
if(biomeDelegate.isEphemeral()) {
StringBuilder biomeList = new StringBuilder("\n");
StreamSupport.stream(finalResult.spliterator(), false)
.sorted(Comparator.comparing(StringIdentifiable::getID))
.forEach(delegate -> biomeList
.append(" - ")
.append(delegate.getID())
.append(':')
.append(delegate.getClass().getCanonicalName())
.append('\n'));
throw new IllegalArgumentException("Biome Pipeline leaks ephemeral biome \"" + biomeDelegate.getID() +
"\". Ensure there is a stage to guarantee replacement of the ephemeral biome. Biomes: " +
biomeList);
}
this.biomes.add(biomeDelegate.getBiome());
});
}
@Override
public Biome getBiome(int x, int y, int z, long seed) {
x += mutator.noise(seed + 1, x, z) * noiseAmp;
z += mutator.noise(seed + 2, x, z) * noiseAmp;
x = FastMath.floorToInt(FastMath.floorDiv(x, resolution));
z = FastMath.floorToInt(FastMath.floorDiv(z, resolution));
int fdX = FastMath.floorDiv(x, pipeline.getSize());
int fdZ = FastMath.floorDiv(z, pipeline.getSize());
return holderCache.get(new SeededVector(fdX, fdZ, seed)).getBiome(x - fdX * pipeline.getSize(),
z - fdZ * pipeline.getSize()).getBiome();
}
@Override
public Iterable<Biome> getBiomes() {
return biomes;
}
private record SeededVector(int x, int z, long seed) {
}
}
@@ -0,0 +1,109 @@
package com.dfsek.terra.addons.biome.pipeline;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import net.jafama.FastMath;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.StreamSupport;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeChunk;
import com.dfsek.terra.addons.biome.pipeline.api.Pipeline;
import com.dfsek.terra.addons.biome.pipeline.api.SeededVector;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.registry.key.StringIdentifiable;
import com.dfsek.terra.api.util.Column;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class PipelineBiomeProvider implements BiomeProvider {
private final LoadingCache<SeededVector, BiomeChunk> biomeChunkCache;
private final int chunkSize;
private final int resolution;
private final NoiseSampler mutator;
private final double noiseAmp;
private final Set<Biome> biomes;
public PipelineBiomeProvider(Pipeline pipeline, int resolution, NoiseSampler mutator, double noiseAmp) {
this.resolution = resolution;
this.mutator = mutator;
this.noiseAmp = noiseAmp;
this.chunkSize = pipeline.getChunkSize();
this.biomeChunkCache = Caffeine.newBuilder()
.maximumSize(1024)
.build(pipeline::generateChunk);
Set<PipelineBiome> biomeSet = new HashSet<>();
pipeline.getSource().getBiomes().forEach(biomeSet::add);
Iterable<PipelineBiome> result = biomeSet;
for(Stage stage : pipeline.getStages()) {
result = stage.getBiomes(result);
}
this.biomes = new HashSet<>();
Iterable<PipelineBiome> finalResult = result;
result.forEach(pipelineBiome -> {
if(pipelineBiome.isPlaceholder()) {
StringBuilder biomeList = new StringBuilder("\n");
StreamSupport.stream(finalResult.spliterator(), false)
.sorted(Comparator.comparing(StringIdentifiable::getID))
.forEach(delegate -> biomeList
.append(" - ")
.append(delegate.getID())
.append(':')
.append(delegate.getClass().getCanonicalName())
.append('\n'));
throw new IllegalArgumentException("Biome Pipeline leaks placeholder biome \"" + pipelineBiome.getID() +
"\". Ensure there is a stage to guarantee replacement of the placeholder biome. Biomes: " +
biomeList);
}
this.biomes.add(pipelineBiome.getBiome());
});
}
@Override
public Biome getBiome(int x, int y, int z, long seed) {
return getBiome(x, z, seed);
}
public Biome getBiome(int x, int z, long seed) {
x += mutator.noise(seed + 1, x, z) * noiseAmp;
z += mutator.noise(seed + 2, x, z) * noiseAmp;
x /= resolution;
z /= resolution;
int chunkX = FastMath.floorDiv(x, chunkSize);
int chunkZ = FastMath.floorDiv(z, chunkSize);
int chunkWorldX = chunkX * chunkSize;
int chunkWorldZ = chunkZ * chunkSize;
int xInChunk = x - chunkWorldX;
int zInChunk = z - chunkWorldZ;
return biomeChunkCache.get(new SeededVector(seed, chunkWorldX, chunkWorldZ)).get(xInChunk, zInChunk).getBiome();
}
@Override
public Iterable<Biome> getBiomes() {
return biomes;
}
@Override
public Column<Biome> getColumn(int x, int z, long seed, int min, int max) {
return new BiomePipelineColumn(this, min, max, x, z, seed);
}
@Override
public int resolution() {
return resolution;
}
}
@@ -0,0 +1,10 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
public interface BiomeChunk {
PipelineBiome get(int xInChunk, int zInChunk);
}
@@ -1,26 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeExpander;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
public interface BiomeHolder {
BiomeHolder expand(BiomeExpander expander, long seed);
void mutate(BiomeMutator mutator, long seed);
void fill(BiomeSource source, long seed);
BiomeDelegate getBiome(int x, int z);
BiomeDelegate getBiomeRaw(int x, int z);
}
@@ -0,0 +1,29 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
/**
* Resizes the internal grid of a BiomeChunk when applied, serves the purpose of
* filling in null biomes as a result of this resizing.
*/
public interface Expander extends Stage {
PipelineBiome fillBiome(ViewPoint viewPoint);
@Override
default int maxRelativeReadDistance() {
return 0;
}
@Override
default PipelineBiome apply(ViewPoint viewPoint) {
PipelineBiome currentBiome = viewPoint.getBiome();
if(currentBiome == null) {
return fillBiome(viewPoint);
} else {
return currentBiome;
}
}
}
@@ -0,0 +1,14 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import java.util.List;
public interface Pipeline {
BiomeChunk generateChunk(SeededVector worldCoordinates);
int getChunkSize();
Source getSource();
List<Stage> getStages();
}
@@ -0,0 +1,19 @@
package com.dfsek.terra.addons.biome.pipeline.api;
public record SeededVector(long seed, int x, int z) {
@Override
public boolean equals(Object obj) {
if(obj instanceof SeededVector that) {
return this.z == that.z && this.x == that.x && this.seed == that.seed;
}
return false;
}
@Override
public int hashCode() {
int code = x;
code = 31 * code + z;
return 31 * code + ((int) (seed ^ (seed >>> 32)));
}
}
@@ -0,0 +1,11 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
public interface Source {
PipelineBiome get(long seed, int x, int z);
Iterable<PipelineBiome> getBiomes();
}
@@ -0,0 +1,15 @@
package com.dfsek.terra.addons.biome.pipeline.api;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
public interface Stage {
PipelineBiome apply(ViewPoint viewPoint);
int maxRelativeReadDistance();
default Iterable<PipelineBiome> getBiomes(Iterable<PipelineBiome> biomes) {
return biomes;
}
}
@@ -1,14 +1,14 @@
package com.dfsek.terra.addons.biome.pipeline.api.delegate;
package com.dfsek.terra.addons.biome.pipeline.api.biome;
import java.util.Set;
import com.dfsek.terra.api.world.biome.Biome;
final class DelegatedBiome implements BiomeDelegate {
public final class DelegatedPipelineBiome implements PipelineBiome {
private final Biome biome;
public DelegatedBiome(Biome biome) {
public DelegatedPipelineBiome(Biome biome) {
this.biome = biome;
}
@@ -24,7 +24,7 @@ final class DelegatedBiome implements BiomeDelegate {
@Override
public boolean equals(Object obj) {
if(!(obj instanceof DelegatedBiome that)) return false;
if(!(obj instanceof DelegatedPipelineBiome that)) return false;
return that.biome.equals(this.biome);
}
@@ -0,0 +1,35 @@
package com.dfsek.terra.addons.biome.pipeline.api.biome;
import java.util.Set;
import com.dfsek.terra.api.registry.key.StringIdentifiable;
import com.dfsek.terra.api.world.biome.Biome;
public interface PipelineBiome extends StringIdentifiable {
Biome getBiome();
static PipelineBiome placeholder(String id) {
return new PlaceholderPipelineBiome(id);
}
static PipelineBiome from(Biome biome) {
return new DelegatedPipelineBiome(biome);
}
static PipelineBiome self() {
return SelfPipelineBiome.INSTANCE;
}
Set<String> getTags();
default boolean isPlaceholder() {
return false;
}
default boolean isSelf() {
return false;
}
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.addons.biome.pipeline.api.delegate;
package com.dfsek.terra.addons.biome.pipeline.api.biome;
import java.util.HashSet;
import java.util.Set;
@@ -6,11 +6,11 @@ import java.util.Set;
import com.dfsek.terra.api.world.biome.Biome;
final class EphemeralBiomeDelegate implements BiomeDelegate {
final class PlaceholderPipelineBiome implements PipelineBiome {
private final Set<String> tags;
private final String id;
public EphemeralBiomeDelegate(String id) {
public PlaceholderPipelineBiome(String id) {
this.id = id;
tags = new HashSet<>();
tags.add(id);
@@ -19,7 +19,7 @@ final class EphemeralBiomeDelegate implements BiomeDelegate {
@Override
public Biome getBiome() {
throw new UnsupportedOperationException("Cannot get biome from ephemeral delegate");
throw new UnsupportedOperationException("Cannot get raw biome from placeholder pipeline biome");
}
@Override
@@ -33,7 +33,7 @@ final class EphemeralBiomeDelegate implements BiomeDelegate {
}
@Override
public boolean isEphemeral() {
public boolean isPlaceholder() {
return true;
}
@@ -44,7 +44,7 @@ final class EphemeralBiomeDelegate implements BiomeDelegate {
@Override
public boolean equals(Object obj) {
if(!(obj instanceof EphemeralBiomeDelegate that)) return false;
if(!(obj instanceof PlaceholderPipelineBiome that)) return false;
return this.id.equals(that.id);
}
@@ -1,4 +1,4 @@
package com.dfsek.terra.addons.biome.pipeline.api.delegate;
package com.dfsek.terra.addons.biome.pipeline.api.biome;
import java.util.Collections;
import java.util.Set;
@@ -6,10 +6,10 @@ import java.util.Set;
import com.dfsek.terra.api.world.biome.Biome;
final class SelfDelegate implements BiomeDelegate {
public static final SelfDelegate INSTANCE = new SelfDelegate();
final class SelfPipelineBiome implements PipelineBiome {
public static final SelfPipelineBiome INSTANCE = new SelfPipelineBiome();
private SelfDelegate() {
private SelfPipelineBiome() {
}
@@ -24,7 +24,7 @@ final class SelfDelegate implements BiomeDelegate {
}
@Override
public boolean isEphemeral() {
public boolean isPlaceholder() {
return true;
}
@@ -1,35 +0,0 @@
package com.dfsek.terra.addons.biome.pipeline.api.delegate;
import java.util.Set;
import com.dfsek.terra.api.registry.key.StringIdentifiable;
import com.dfsek.terra.api.world.biome.Biome;
public interface BiomeDelegate extends StringIdentifiable {
static BiomeDelegate ephemeral(String id) {
return new EphemeralBiomeDelegate(id);
}
static BiomeDelegate from(Biome biome) {
return new DelegatedBiome(biome);
}
static BiomeDelegate self() {
return SelfDelegate.INSTANCE;
}
Biome getBiome();
Set<String> getTags();
default boolean isEphemeral() {
return false;
}
default boolean isSelf() {
return false;
}
}
@@ -1,20 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.api.stage;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
public interface Stage {
BiomeHolder apply(BiomeHolder in, long seed);
boolean isExpansion();
Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes);
}
@@ -1,15 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.api.stage.type;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
public interface BiomeExpander {
BiomeDelegate getBetween(double x, double z, long seed, BiomeDelegate... others);
}
@@ -1,37 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.api.stage.type;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
public interface BiomeMutator {
BiomeDelegate mutate(ViewPoint viewPoint, double x, double z, long seed);
default Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) {
return biomes;
}
class ViewPoint {
private final BiomeHolder biomes;
private final int offX;
private final int offZ;
public ViewPoint(BiomeHolder biomes, int offX, int offZ) {
this.biomes = biomes;
this.offX = offX;
this.offZ = offZ;
}
public BiomeDelegate getBiome(int x, int z) {
return biomes.getBiomeRaw(x + offX, z + offZ);
}
}
}
@@ -10,45 +10,50 @@ package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Description;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import java.util.List;
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.Stage;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.addons.biome.pipeline.PipelineBiomeProvider;
import com.dfsek.terra.addons.biome.pipeline.pipeline.PipelineImpl;
import com.dfsek.terra.addons.biome.pipeline.api.Source;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@SuppressWarnings({ "FieldMayBeFinal", "unused" })
public class BiomePipelineTemplate extends BiomeProviderTemplate {
@Value("pipeline.initial-size")
public class BiomePipelineTemplate implements ObjectTemplate<BiomeProvider> {
@Value("resolution")
@Default
@Description("""
The initial size of biome chunks. This value must be at least 2.
<b>This is not the final size of biome chunks. Final chunks will be much larger</b>.
It is recommended to keep biome chunks' final size in the range of [50, 300]
to prevent performance issues. To calculate the size of biome chunks, simply
take initial-size and for each expand stage, multiply the running value by 2
and subtract 1. (The size is also printed to the server console if you
have debug mode enabled)""")
private @Meta int initialSize = 2;
The resolution at which to sample biomes.
Larger values are quadratically faster, but produce lower quality results.
For example, a value of 3 would sample every 3 blocks.""")
protected @Meta int resolution = 1;
@Value("pipeline.source")
@Description("The Biome Source to use for initial population of biomes.")
private @Meta BiomeSource source;
private @Meta Source source;
@Value("pipeline.stages")
@Description("A list of pipeline stages to apply to the result of #source")
private @Meta List<@Meta Stage> stages;
@Value("blend.sampler")
@Default
@Description("A sampler to use for blending the edges of biomes via domain warping.")
protected @Meta NoiseSampler blendSampler = NoiseSampler.zero();
@Value("blend.amplitude")
@Default
@Description("The amplitude at which to perform blending.")
protected @Meta double blendAmplitude = 0d;
@Override
public BiomeProvider get() {
BiomePipeline.BiomePipelineBuilder biomePipelineBuilder = new BiomePipeline.BiomePipelineBuilder(initialSize);
stages.forEach(biomePipelineBuilder::addStage);
BiomePipeline pipeline = biomePipelineBuilder.build(source);
return new BiomePipelineProvider(pipeline, resolution, blend, blendAmp);
return new PipelineBiomeProvider(new PipelineImpl(source, stages, resolution, 500), resolution, blendSampler, blendAmplitude);
}
}
@@ -1,37 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.config;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Description;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public abstract class BiomeProviderTemplate implements ObjectTemplate<BiomeProvider> {
@Value("resolution")
@Default
@Description("""
The resolution at which to sample biomes.
Larger values are quadratically faster, but produce lower quality results.
For example, a value of 3 would sample every 3 blocks.""")
protected @Meta int resolution = 1;
@Value("blend.sampler")
@Default
@Description("A sampler to use for blending the edges of biomes via domain warping.")
protected @Meta NoiseSampler blend = NoiseSampler.zero();
@Value("blend.amplitude")
@Default
@Description("The amplitude at which to perform blending.")
protected @Meta double blendAmp = 0d;
}
@@ -8,25 +8,25 @@ import org.jetbrains.annotations.NotNull;
import java.lang.reflect.AnnotatedType;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.world.biome.Biome;
public class BiomeDelegateLoader implements TypeLoader<BiomeDelegate> {
public class PipelineBiomeLoader implements TypeLoader<PipelineBiome> {
private final Registry<Biome> biomeRegistry;
public BiomeDelegateLoader(Registry<Biome> biomeRegistry) {
public PipelineBiomeLoader(Registry<Biome> biomeRegistry) {
this.biomeRegistry = biomeRegistry;
}
@Override
public BiomeDelegate load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker)
public PipelineBiome load(@NotNull AnnotatedType t, @NotNull Object c, @NotNull ConfigLoader loader, DepthTracker depthTracker)
throws LoadException {
if(c.equals("SELF")) return BiomeDelegate.self();
if(c.equals("SELF")) return PipelineBiome.self();
return biomeRegistry
.getByID((String) c)
.map(BiomeDelegate::from)
.orElseGet(() -> BiomeDelegate.ephemeral((String) c));
.map(PipelineBiome::from)
.orElseGet(() -> PipelineBiome.placeholder((String) c));
}
}
@@ -5,13 +5,13 @@
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.config;
package com.dfsek.terra.addons.biome.pipeline.config.source;
import com.dfsek.tectonic.api.config.template.annotations.Description;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.addons.biome.pipeline.api.Source;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.source.SamplerSource;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
@@ -25,10 +25,10 @@ public class SamplerSourceTemplate extends SourceTemplate {
@Value("biomes")
@Description("The biomes to be distributed.")
private @Meta ProbabilityCollection<@Meta BiomeDelegate> biomes;
private @Meta ProbabilityCollection<@Meta PipelineBiome> biomes;
@Override
public BiomeSource get() {
public Source get() {
return new SamplerSource(biomes, noise);
}
}
@@ -5,13 +5,13 @@
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.config;
package com.dfsek.terra.addons.biome.pipeline.config.source;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.terra.addons.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.addons.biome.pipeline.api.Source;
public abstract class SourceTemplate implements ObjectTemplate<BiomeSource> {
public abstract class SourceTemplate implements ObjectTemplate<Source> {
}
@@ -11,7 +11,7 @@ import com.dfsek.tectonic.api.config.template.annotations.Description;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.noise.NoiseSampler;
@@ -7,15 +7,14 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.expander;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
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.stages.ExpanderStage;
import com.dfsek.terra.addons.biome.pipeline.api.Expander;
import com.dfsek.terra.addons.biome.pipeline.stage.expander.FractalExpander;
public class ExpanderStageTemplate extends StageTemplate {
@Override
public Stage get() {
return new ExpanderStage(new FractalExpander(noise));
public Expander get() {
return new FractalExpander(noise);
}
}
@@ -11,17 +11,16 @@ import com.dfsek.tectonic.api.config.template.annotations.Value;
import java.util.Map;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
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.stages.MutatorStage;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.stage.mutators.BorderListStage;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
@SuppressWarnings("unused")
public class BorderListMutatorTemplate extends StageTemplate {
public class BorderListStageTemplate extends StageTemplate {
@Value("from")
private @Meta String from;
@@ -29,14 +28,14 @@ public class BorderListMutatorTemplate extends StageTemplate {
private @Meta String defaultReplace;
@Value("default-to")
private @Meta ProbabilityCollection<@Meta BiomeDelegate> defaultTo;
private @Meta ProbabilityCollection<@Meta PipelineBiome> defaultTo;
@Value("replace")
private @Meta Map<@Meta BiomeDelegate, @Meta ProbabilityCollection<@Meta BiomeDelegate>> replace;
private @Meta Map<@Meta PipelineBiome, @Meta ProbabilityCollection<@Meta PipelineBiome>> replace;
@Override
public Stage get() {
return new MutatorStage(new BorderListMutator(replace, from, defaultReplace, noise, defaultTo));
return new BorderListStage(replace, from, defaultReplace, noise, defaultTo);
}
}
@@ -9,17 +9,16 @@ package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
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.stages.MutatorStage;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.stage.mutators.BorderStage;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
@SuppressWarnings("unused")
public class BorderMutatorTemplate extends StageTemplate {
public class BorderStageTemplate extends StageTemplate {
@Value("from")
private @Meta String from;
@@ -27,10 +26,10 @@ public class BorderMutatorTemplate extends StageTemplate {
private @Meta String replace;
@Value("to")
private @Meta ProbabilityCollection<@Meta BiomeDelegate> to;
private @Meta ProbabilityCollection<@Meta PipelineBiome> to;
@Override
public Stage get() {
return new MutatorStage(new BorderMutator(from, replace, noise, to));
return new BorderStage(from, replace, noise, to);
}
}
@@ -11,28 +11,27 @@ import com.dfsek.tectonic.api.config.template.annotations.Value;
import java.util.Map;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
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.stages.MutatorStage;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.stage.mutators.ReplaceListStage;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
@SuppressWarnings("unused")
public class ReplaceListMutatorTemplate extends StageTemplate {
public class ReplaceListStageTemplate extends StageTemplate {
@Value("default-from")
private @Meta String defaultFrom;
@Value("default-to")
private @Meta ProbabilityCollection<@Meta BiomeDelegate> defaultTo;
private @Meta ProbabilityCollection<@Meta PipelineBiome> defaultTo;
@Value("to")
private @Meta Map<@Meta BiomeDelegate, @Meta ProbabilityCollection<@Meta BiomeDelegate>> replace;
private @Meta Map<@Meta PipelineBiome, @Meta ProbabilityCollection<@Meta PipelineBiome>> replace;
@Override
public Stage get() {
return new MutatorStage(new ReplaceListMutator(replace, defaultFrom, defaultTo, noise));
return new ReplaceListStage(replace, defaultFrom, defaultTo, noise);
}
}
@@ -9,25 +9,24 @@ package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
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.stages.MutatorStage;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.stage.mutators.ReplaceStage;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
@SuppressWarnings("unused")
public class ReplaceMutatorTemplate extends StageTemplate {
public class ReplaceStageTemplate extends StageTemplate {
@Value("from")
private @Meta String from;
@Value("to")
private @Meta ProbabilityCollection<@Meta BiomeDelegate> to;
private @Meta ProbabilityCollection<@Meta PipelineBiome> to;
@Override
public Stage get() {
return new MutatorStage(new ReplaceMutator(from, to, noise));
return new ReplaceStage(from, to, noise);
}
}
@@ -7,15 +7,14 @@
package com.dfsek.terra.addons.biome.pipeline.config.stage.mutator;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
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.stages.MutatorStage;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.stage.mutators.SmoothStage;
public class SmoothMutatorTemplate extends StageTemplate {
public class SmoothStageTemplate extends StageTemplate {
@Override
public Stage get() {
return new MutatorStage(new SmoothMutator(noise));
return new SmoothStage(noise);
}
}
@@ -1,27 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.expand;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeExpander;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.MathUtil;
public class FractalExpander implements BiomeExpander {
private final NoiseSampler sampler;
public FractalExpander(NoiseSampler sampler) {
this.sampler = sampler;
}
@Override
public BiomeDelegate getBetween(double x, double z, long seed, BiomeDelegate... others) {
return others[MathUtil.normalizeIndex(sampler.noise(seed, x, z), others.length)];
}
}
@@ -1,67 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.mutator;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class BorderListMutator implements BiomeMutator {
private final String border;
private final NoiseSampler noiseSampler;
private final ProbabilityCollection<BiomeDelegate> replaceDefault;
private final String defaultReplace;
private final Map<BiomeDelegate, ProbabilityCollection<BiomeDelegate>> replace;
public BorderListMutator(Map<BiomeDelegate, ProbabilityCollection<BiomeDelegate>> replace, String border, String defaultReplace,
NoiseSampler noiseSampler, ProbabilityCollection<BiomeDelegate> replaceDefault) {
this.border = border;
this.noiseSampler = noiseSampler;
this.replaceDefault = replaceDefault;
this.defaultReplace = defaultReplace;
this.replace = replace;
}
@Override
public BiomeDelegate mutate(ViewPoint viewPoint, double x, double z, long seed) {
BiomeDelegate origin = viewPoint.getBiome(0, 0);
if(origin.getTags().contains(defaultReplace)) {
for(int xi = -1; xi <= 1; xi++) {
for(int zi = -1; zi <= 1; zi++) {
if(xi == 0 && zi == 0) continue;
BiomeDelegate current = viewPoint.getBiome(xi, zi);
if(current != null && current.getTags().contains(border)) {
if(replace.containsKey(origin)) {
BiomeDelegate biome = replace.get(origin).get(noiseSampler, x, z, seed);
return biome.isSelf() ? origin : biome;
}
BiomeDelegate biome = replaceDefault.get(noiseSampler, x, z, seed);
return biome.isSelf() ? origin : biome;
}
}
}
}
return origin;
}
@Override
public Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) {
Set<BiomeDelegate> biomeSet = new HashSet<>();
biomes.forEach(biomeSet::add);
biomeSet.addAll(replaceDefault.getContents().stream().filter(Predicate.not(BiomeDelegate::isSelf)).toList());
replace.forEach((biome, collection) -> biomeSet.addAll(collection.getContents()));
return biomeSet;
}
}
@@ -1,66 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.mutator;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class BorderMutator implements BiomeMutator {
private final String border;
private final NoiseSampler noiseSampler;
private final ProbabilityCollection<BiomeDelegate> replace;
private final String replaceTag;
public BorderMutator(String border, String replaceTag, NoiseSampler noiseSampler, ProbabilityCollection<BiomeDelegate> replace) {
this.border = border;
this.noiseSampler = noiseSampler;
this.replace = replace;
this.replaceTag = replaceTag;
}
@Override
public BiomeDelegate mutate(ViewPoint viewPoint, double x, double z, long seed) {
BiomeDelegate origin = viewPoint.getBiome(0, 0);
if(origin.getTags().contains(replaceTag)) {
for(int xi = -1; xi <= 1; xi++) {
for(int zi = -1; zi <= 1; zi++) {
if(xi == 0 && zi == 0) continue;
BiomeDelegate current = viewPoint.getBiome(xi, zi);
if(current != null && current.getTags().contains(border)) {
BiomeDelegate biome = replace.get(noiseSampler, x, z, seed);
return biome.isSelf() ? origin : biome;
}
}
}
}
return origin;
}
@Override
public Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) {
Set<BiomeDelegate> biomeSet = new HashSet<>();
biomes.forEach(biomeSet::add);
biomeSet.addAll(
replace
.getContents()
.stream()
.filter(
Predicate.not(BiomeDelegate::isSelf)
)
.toList()
);
return biomeSet;
}
}
@@ -1,46 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.mutator;
import java.util.Objects;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.MathUtil;
public class SmoothMutator implements BiomeMutator {
private final NoiseSampler sampler;
public SmoothMutator(NoiseSampler sampler) {
this.sampler = sampler;
}
@Override
public BiomeDelegate mutate(ViewPoint viewPoint, double x, double z, long seed) {
BiomeDelegate top = viewPoint.getBiome(1, 0);
BiomeDelegate bottom = viewPoint.getBiome(-1, 0);
BiomeDelegate left = viewPoint.getBiome(0, 1);
BiomeDelegate right = viewPoint.getBiome(0, -1);
boolean vert = Objects.equals(top, bottom) && top != null;
boolean horiz = Objects.equals(left, right) && left != null;
if(vert && horiz) {
return MathUtil.normalizeIndex(sampler.noise(seed, x, z), 2) == 0 ? left : top;
}
if(vert) return top;
if(horiz) return left;
return viewPoint.getBiome(0, 0);
}
}
@@ -0,0 +1,218 @@
package com.dfsek.terra.addons.biome.pipeline.pipeline;
import net.jafama.FastMath;
import java.util.List;
import com.dfsek.terra.addons.biome.pipeline.api.SeededVector;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeChunk;
import com.dfsek.terra.addons.biome.pipeline.api.Expander;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
public class BiomeChunkImpl implements BiomeChunk {
private PipelineBiome[][] biomes;
private final SeededVector worldOrigin;
private final int chunkOriginArrayIndex;
private final int worldCoordinateScale;
public BiomeChunkImpl(SeededVector worldOrigin, PipelineImpl pipeline) {
this.worldOrigin = worldOrigin;
this.chunkOriginArrayIndex = pipeline.getChunkOriginArrayIndex();
this.worldCoordinateScale = pipeline.getResolution();
int size = pipeline.getArraySize();
int expanderCount = pipeline.getExpanderCount();
int expansionsApplied = 0;
// Allocate working arrays
this.biomes = new PipelineBiome[size][size];
PipelineBiome[][] lookupArray = new PipelineBiome[size][size];
// A second lookup array is required such that stage application doesn't affect lookups, otherwise application may cascade
// Construct working grid
int gridOrigin = 0;
int gridInterval = calculateGridInterval(expanderCount, expansionsApplied);
int gridSize = (size / gridInterval);
gridSize += expanderCount > 0 ? 1 : 0; // Add an extra border if expansion occurs
// Fill working grid with initial cells
for(int gridX = 0; gridX < gridSize; gridX++) {
for(int gridZ = 0; gridZ < gridSize; gridZ++) {
int xIndex = gridOrigin + gridX * gridInterval;
int zIndex = gridOrigin + gridZ * gridInterval;
biomes[xIndex][zIndex] = pipeline.getSource().get(worldOrigin.seed(), xIndexToWorldCoordinate(xIndex), zIndexToWorldCoordinate(zIndex));
}
}
for(Stage stage : pipeline.getStages()) {
if(stage instanceof Expander) {
// Shrink working grid size, the expander will fill in null cells (as a result of shrinking the grid) during mutation
expansionsApplied++;
gridInterval = calculateGridInterval(expanderCount, expansionsApplied);
gridSize = expandSize(gridSize);
}
int stageReadDistance = stage.maxRelativeReadDistance();
if(stageReadDistance > 0) {
// Discard edges such that adjacent lookups are only ran on valid cells
gridSize = contractBordersFromSize(gridSize, stageReadDistance);
gridOrigin += stageReadDistance * gridInterval;
}
// Cycle arrays, the previously populated array is swapped to be used for lookups, and the result of the stage application
// overwrites the previous lookup array. This saves having to allocate a new array copy each time
PipelineBiome[][] tempArray = biomes;
biomes = lookupArray;
lookupArray = tempArray;
// Apply stage to working grid
for(int gridZ = 0; gridZ < gridSize; gridZ = gridZ + 1) {
for(int gridX = 0; gridX < gridSize; gridX = gridX + 1) {
int xIndex = gridOrigin + gridX * gridInterval;
int zIndex = gridOrigin + gridZ * gridInterval;
biomes[xIndex][zIndex] = stage.apply(new ViewPoint(this, gridInterval, gridX, gridZ, xIndex, zIndex, lookupArray));
}
}
}
}
@Override
public PipelineBiome get(int xInChunk, int zInChunk) {
int xIndex = xInChunk + chunkOriginArrayIndex;
int zIndex = zInChunk + chunkOriginArrayIndex;
return biomes[xIndex][zIndex];
}
private int xIndexToWorldCoordinate(int xIndex) {
return (worldOrigin.x() + xIndex - chunkOriginArrayIndex) * worldCoordinateScale;
}
private int zIndexToWorldCoordinate(int zIndex) {
return (worldOrigin.z() + zIndex - chunkOriginArrayIndex) * worldCoordinateScale;
}
protected static int initialSizeToArraySize(int expanderCount, int initialSize) {
int size = initialSize;
for(int i = 0; i < expanderCount; i++) {
size = expandSize(size);
}
return size;
}
protected static int calculateChunkOriginArrayIndex(int totalExpanderCount, List<Stage> stages) {
int finalGridOrigin = calculateFinalGridOrigin(totalExpanderCount, stages);
int initialGridInterval = calculateGridInterval(totalExpanderCount, 0);
// Round the final grid origin up to the nearest multiple of initialGridInterval, such that each
// chunk samples points on the same overall grid.
// Without this, shared chunk borders (required because of adjacent cell reads) will not be identical
// because points would be sampled on grids at different offsets, resulting in artifacts at borders.
return FastMath.ceilToInt((double) finalGridOrigin / initialGridInterval) * initialGridInterval;
}
private static int calculateFinalGridOrigin(int totalExpanderCount, List<Stage> stages) {
int gridOrigin = 0;
int expansionsApplied = 0;
int gridInterval = calculateGridInterval(totalExpanderCount, expansionsApplied);
for (Stage stage : stages) {
if (stage instanceof Expander) {
expansionsApplied++;
gridInterval = calculateGridInterval(totalExpanderCount, expansionsApplied);
}
gridOrigin += stage.maxRelativeReadDistance() * gridInterval;
}
return gridOrigin;
}
protected static int calculateChunkSize(int arraySize, int chunkOriginArrayIndex, int totalExpanderCount) {
return contractBordersFromSize(arraySize, chunkOriginArrayIndex) - (totalExpanderCount > 0 ? 1 : 0);
}
private static int expandSize(int size) {
return size * 2 - 1;
}
private static int contractBordersFromSize(int size, int border) {
return size - border * 2;
}
private static int calculateGridInterval(int totalExpansions, int expansionsApplied) {
return 1 << (totalExpansions - expansionsApplied);
}
private SeededVector getOrigin() {
return worldOrigin;
}
/**
* Represents a point on the operating grid within the biomes array
*/
public static class ViewPoint {
private final BiomeChunkImpl chunk;
private final PipelineBiome biome;
private final int gridInterval;
private final int gridX;
private final int gridZ;
private final int xIndex;
private final int zIndex;
private final PipelineBiome[][] lookupArray;
private ViewPoint(BiomeChunkImpl chunk, int gridInterval, int gridX, int gridZ, int xIndex, int zIndex, PipelineBiome[][] lookupArray) {
this.chunk = chunk;
this.gridInterval = gridInterval;
this.gridX = gridX;
this.gridZ = gridZ;
this.xIndex = xIndex;
this.zIndex = zIndex;
this.lookupArray = lookupArray;
this.biome = lookupArray[xIndex][zIndex];
}
public PipelineBiome getRelativeBiome(int x, int z) {
int lookupXIndex = this.xIndex + x * gridInterval;
int lookupZIndex = this.zIndex + z * gridInterval;
return lookupArray[lookupXIndex][lookupZIndex];
}
public PipelineBiome getBiome() {
return biome;
}
/**
* @return X position of the point relative to the operating grid
*/
public int gridX() {
return gridX;
}
/**
* @return Z position of the point relative to the operating grid
*/
public int gridZ() {
return gridZ;
}
/**
* @return X position of the point in the world
*/
public int worldX() {
return chunk.xIndexToWorldCoordinate(xIndex);
}
/**
* @return Z position of the point in the world
*/
public int worldZ() {
return chunk.zIndexToWorldCoordinate(zIndex);
}
public long worldSeed() {
return chunk.getOrigin().seed();
}
}
}
@@ -0,0 +1,92 @@
package com.dfsek.terra.addons.biome.pipeline.pipeline;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeChunk;
import com.dfsek.terra.addons.biome.pipeline.api.Expander;
import com.dfsek.terra.addons.biome.pipeline.api.Pipeline;
import com.dfsek.terra.addons.biome.pipeline.api.SeededVector;
import com.dfsek.terra.addons.biome.pipeline.api.Source;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
public class PipelineImpl implements Pipeline {
private static final Logger logger = LoggerFactory.getLogger(PipelineImpl.class);
private final Source source;
private final List<Stage> stages;
private final int chunkSize;
private final int expanderCount;
private final int arraySize;
private final int chunkOriginArrayIndex;
private final int resolution;
public PipelineImpl(Source source, List<Stage> stages, int resolution, int idealChunkArraySize) {
this.source = source;
this.stages = stages;
this.resolution = resolution;
this.expanderCount = (int) stages.stream().filter(s -> s instanceof Expander).count();
// Optimize for the ideal array size
int arraySize;
int chunkOriginArrayIndex;
int chunkSize;
int initialSize = 1;
while (true) {
arraySize = BiomeChunkImpl.initialSizeToArraySize(expanderCount, initialSize);
chunkOriginArrayIndex = BiomeChunkImpl.calculateChunkOriginArrayIndex(expanderCount, stages);
chunkSize = BiomeChunkImpl.calculateChunkSize(arraySize, chunkOriginArrayIndex, expanderCount);
if (chunkSize > 1 && arraySize >= idealChunkArraySize) break;
initialSize++;
}
this.arraySize = arraySize;
this.chunkOriginArrayIndex = chunkOriginArrayIndex;
this.chunkSize = chunkSize;
logger.debug("Initialized a new biome pipeline:");
logger.debug("Array size: {} (Target: {})", arraySize, idealChunkArraySize);
logger.debug("Internal array origin: {}", chunkOriginArrayIndex);
logger.debug("Chunk size: {}", chunkSize);
}
@Override
public BiomeChunk generateChunk(SeededVector worldCoordinates) {
return new BiomeChunkImpl(worldCoordinates, this);
}
@Override
public int getChunkSize() {
return chunkSize;
}
@Override
public Source getSource() {
return source;
}
@Override
public List<Stage> getStages() {
return stages;
}
protected int getExpanderCount() {
return expanderCount;
}
protected int getArraySize() {
return arraySize;
}
protected int getChunkOriginArrayIndex() {
return chunkOriginArrayIndex;
}
protected int getResolution() {
return resolution;
}
}
@@ -1,17 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.source;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
public interface BiomeSource {
BiomeDelegate getBiome(double x, double z, long seed);
Iterable<BiomeDelegate> getBiomes();
}
@@ -1,33 +1,27 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.source;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.Source;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class SamplerSource implements BiomeSource {
private final ProbabilityCollection<BiomeDelegate> biomes;
public class SamplerSource implements Source {
private final ProbabilityCollection<PipelineBiome> biomes;
private final NoiseSampler sampler;
public SamplerSource(ProbabilityCollection<BiomeDelegate> biomes, NoiseSampler sampler) {
public SamplerSource(ProbabilityCollection<PipelineBiome> biomes, NoiseSampler sampler) {
this.biomes = biomes;
this.sampler = sampler;
}
@Override
public BiomeDelegate getBiome(double x, double z, long seed) {
public PipelineBiome get(long seed, int x, int z) {
return biomes.get(sampler, x, z, seed);
}
@Override
public Iterable<BiomeDelegate> getBiomes() {
public Iterable<PipelineBiome> getBiomes() {
return biomes.getContents();
}
}
@@ -0,0 +1,27 @@
package com.dfsek.terra.addons.biome.pipeline.source;
import java.util.Collections;
import java.util.Set;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.addons.biome.pipeline.api.Source;
public class SingleSource implements Source {
private final PipelineBiome biome;
public SingleSource(PipelineBiome biome) {
this.biome = biome;
}
@Override
public PipelineBiome get(long seed, int x, int z) {
return biome;
}
@Override
public Set<PipelineBiome> getBiomes() {
return Collections.singleton(biome);
}
}
@@ -0,0 +1,37 @@
package com.dfsek.terra.addons.biome.pipeline.stage.expander;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.Expander;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
public class FractalExpander implements Expander {
private final NoiseSampler sampler;
public FractalExpander(NoiseSampler sampler) {
this.sampler = sampler;
}
@Override
public PipelineBiome fillBiome(ViewPoint viewPoint) {
int xMod2 = viewPoint.gridX() % 2;
int zMod2 = viewPoint.gridZ() % 2;
double roll = sampler.noise(viewPoint.worldSeed(), viewPoint.worldX(), viewPoint.worldZ());
if (xMod2 == 1 && zMod2 == 0) { // Pick one of 2 neighbors on X axis randomly
return roll > 0 ? viewPoint.getRelativeBiome(-1, 0) : viewPoint.getRelativeBiome(1, 0);
} else if (xMod2 == 0 && zMod2 == 1) { // Pick one of 2 neighbors on Z axis randomly
return roll > 0 ? viewPoint.getRelativeBiome(0, -1) : viewPoint.getRelativeBiome(0, 1);
} else { // Pick one of 4 corners randomly
return roll > 0 ?
roll > 0.25 ? viewPoint.getRelativeBiome(-1, 1) : viewPoint.getRelativeBiome(1, 1) :
roll > -0.25 ? viewPoint.getRelativeBiome(-1, -1) : viewPoint.getRelativeBiome(1, -1);
}
}
}
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.stage.mutators;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.vector.Vector2Int;
public class BorderListStage implements Stage {
private final String border;
private final NoiseSampler noiseSampler;
private final ProbabilityCollection<PipelineBiome> replaceDefault;
private final String defaultReplace;
private final Map<PipelineBiome, ProbabilityCollection<PipelineBiome>> replace;
private final Vector2Int[] borderPoints;
public BorderListStage(Map<PipelineBiome, ProbabilityCollection<PipelineBiome>> replace, String border, String defaultReplace,
NoiseSampler noiseSampler, ProbabilityCollection<PipelineBiome> replaceDefault) {
this.border = border;
this.noiseSampler = noiseSampler;
this.replaceDefault = replaceDefault;
this.defaultReplace = defaultReplace;
this.replace = replace;
List<Vector2Int> points = new ArrayList<>();
for(int x = -1; x <= 1; x++) {
for(int z = -1; z <= 1; z++) {
if(x == 0 && z == 0) continue;
points.add(Vector2Int.of(x, z));
}
}
this.borderPoints = points.toArray(new Vector2Int[0]);
}
@Override
public Iterable<PipelineBiome> getBiomes(Iterable<PipelineBiome> biomes) {
Set<PipelineBiome> biomeSet = new HashSet<>();
biomes.forEach(biomeSet::add);
biomeSet.addAll(replaceDefault.getContents().stream().filter(Predicate.not(PipelineBiome::isSelf)).toList());
replace.forEach((biome, collection) -> biomeSet.addAll(collection.getContents()));
return biomeSet;
}
@Override
public PipelineBiome apply(ViewPoint viewPoint) {
PipelineBiome center = viewPoint.getBiome();
if(center.getTags().contains(defaultReplace)) {
for(Vector2Int point : borderPoints) {
PipelineBiome current = viewPoint.getRelativeBiome(point.getX(), point.getZ());
if(current != null && current.getTags().contains(border)) {
if(replace.containsKey(center)) {
PipelineBiome replacement = replace.get(center).get(noiseSampler, viewPoint.worldX(), viewPoint.worldZ(),
viewPoint.worldSeed());
return replacement.isSelf() ? center : replacement;
}
PipelineBiome replacement = replaceDefault.get(noiseSampler, viewPoint.worldX(), viewPoint.worldZ(), viewPoint.worldSeed());
return replacement.isSelf() ? center : replacement;
}
}
}
return center;
}
@Override
public int maxRelativeReadDistance() {
return 1;
}
}
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.stage.mutators;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.api.util.vector.Vector2Int;
public class BorderStage implements Stage {
private final String border;
private final NoiseSampler noiseSampler;
private final ProbabilityCollection<PipelineBiome> replace;
private final String replaceTag;
private final Vector2Int[] borderPoints;
public BorderStage(String border, String replaceTag, NoiseSampler noiseSampler, ProbabilityCollection<PipelineBiome> replace) {
this.border = border;
this.noiseSampler = noiseSampler;
this.replace = replace;
this.replaceTag = replaceTag;
List<Vector2Int> points = new ArrayList<>();
for(int x = -1; x <= 1; x++) {
for(int z = -1; z <= 1; z++) {
if(x == 0 && z == 0) continue;
points.add(Vector2Int.of(x, z));
}
}
this.borderPoints = points.toArray(new Vector2Int[0]);
}
@Override
public PipelineBiome apply(ViewPoint viewPoint) {
PipelineBiome center = viewPoint.getBiome();
if(center.getTags().contains(replaceTag)) {
for(Vector2Int point : borderPoints) {
PipelineBiome current = viewPoint.getRelativeBiome(point.getX(), point.getZ());
if(current != null && current.getTags().contains(border)) {
PipelineBiome replacement = replace.get(noiseSampler, viewPoint.worldX(), viewPoint.worldZ(), viewPoint.worldSeed());
return replacement.isSelf() ? center : replacement;
}
}
}
return center;
}
@Override
public Iterable<PipelineBiome> getBiomes(Iterable<PipelineBiome> biomes) {
Set<PipelineBiome> biomeSet = new HashSet<>();
biomes.forEach(biomeSet::add);
biomeSet.addAll(
replace
.getContents()
.stream()
.filter(
Predicate.not(PipelineBiome::isSelf)
)
.toList()
);
return biomeSet;
}
@Override
public int maxRelativeReadDistance() {
return 1;
}
}
@@ -5,27 +5,28 @@
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.mutator;
package com.dfsek.terra.addons.biome.pipeline.stage.mutators;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class ReplaceListMutator implements BiomeMutator {
private final Map<BiomeDelegate, ProbabilityCollection<BiomeDelegate>> replace;
public class ReplaceListStage implements Stage {
private final Map<PipelineBiome, ProbabilityCollection<PipelineBiome>> replace;
private final NoiseSampler sampler;
private final ProbabilityCollection<BiomeDelegate> replaceDefault;
private final ProbabilityCollection<PipelineBiome> replaceDefault;
private final String defaultTag;
public ReplaceListMutator(Map<BiomeDelegate, ProbabilityCollection<BiomeDelegate>> replace, String defaultTag,
ProbabilityCollection<BiomeDelegate> replaceDefault, NoiseSampler sampler) {
public ReplaceListStage(Map<PipelineBiome, ProbabilityCollection<PipelineBiome>> replace, String defaultTag,
ProbabilityCollection<PipelineBiome> replaceDefault, NoiseSampler sampler) {
this.replace = replace;
this.sampler = sampler;
this.defaultTag = defaultTag;
@@ -33,24 +34,29 @@ public class ReplaceListMutator implements BiomeMutator {
}
@Override
public BiomeDelegate mutate(ViewPoint viewPoint, double x, double z, long seed) {
BiomeDelegate center = viewPoint.getBiome(0, 0);
public PipelineBiome apply(ViewPoint viewPoint) {
PipelineBiome center = viewPoint.getBiome();
if(replace.containsKey(center)) {
BiomeDelegate biome = replace.get(center).get(sampler, x, z, seed);
return biome.isSelf() ? viewPoint.getBiome(0, 0) : biome;
PipelineBiome biome = replace.get(center).get(sampler, viewPoint.worldX(), viewPoint.worldZ(), viewPoint.worldSeed());
return biome.isSelf() ? viewPoint.getBiome() : biome;
}
if(viewPoint.getBiome(0, 0).getTags().contains(defaultTag)) {
BiomeDelegate biome = replaceDefault.get(sampler, x, z, seed);
return biome.isSelf() ? viewPoint.getBiome(0, 0) : biome;
if(viewPoint.getBiome().getTags().contains(defaultTag)) {
PipelineBiome biome = replaceDefault.get(sampler, viewPoint.worldX(), viewPoint.worldZ(), viewPoint.worldSeed());
return biome.isSelf() ? viewPoint.getBiome() : biome;
}
return center;
}
@Override
public Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) {
Set<BiomeDelegate> biomeSet = new HashSet<>();
public int maxRelativeReadDistance() {
return 0;
}
@Override
public Iterable<PipelineBiome> getBiomes(Iterable<PipelineBiome> biomes) {
Set<PipelineBiome> biomeSet = new HashSet<>();
Set<BiomeDelegate> reject = new HashSet<>();
Set<PipelineBiome> reject = new HashSet<>();
biomes.forEach(biome -> {
if(!biome.getTags().contains(defaultTag) && !replace.containsKey(biome)) {
@@ -5,42 +5,48 @@
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.mutator;
package com.dfsek.terra.addons.biome.pipeline.stage.mutators;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
public class ReplaceMutator implements BiomeMutator {
public class ReplaceStage implements Stage {
private final String replaceableTag;
private final ProbabilityCollection<BiomeDelegate> replace;
private final ProbabilityCollection<PipelineBiome> replace;
private final NoiseSampler sampler;
public ReplaceMutator(String replaceable, ProbabilityCollection<BiomeDelegate> replace, NoiseSampler sampler) {
public ReplaceStage(String replaceable, ProbabilityCollection<PipelineBiome> replace, NoiseSampler sampler) {
this.replaceableTag = replaceable;
this.replace = replace;
this.sampler = sampler;
}
@Override
public BiomeDelegate mutate(ViewPoint viewPoint, double x, double z, long seed) {
if(viewPoint.getBiome(0, 0).getTags().contains(replaceableTag)) {
BiomeDelegate biome = replace.get(sampler, x, z, seed);
return biome.isSelf() ? viewPoint.getBiome(0, 0) : biome;
public PipelineBiome apply(ViewPoint viewPoint) {
if(viewPoint.getBiome().getTags().contains(replaceableTag)) {
PipelineBiome biome = replace.get(sampler, viewPoint.worldX(), viewPoint.worldZ(), viewPoint.worldSeed());
return biome.isSelf() ? viewPoint.getBiome() : biome;
}
return viewPoint.getBiome(0, 0);
return viewPoint.getBiome();
}
@Override
public Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) {
Set<BiomeDelegate> biomeSet = new HashSet<>();
Set<BiomeDelegate> reject = new HashSet<>();
public int maxRelativeReadDistance() {
return 0;
}
@Override
public Iterable<PipelineBiome> getBiomes(Iterable<PipelineBiome> biomes) {
Set<PipelineBiome> biomeSet = new HashSet<>();
Set<PipelineBiome> reject = new HashSet<>();
biomes.forEach(biome -> {
if(!biome.getTags().contains(replaceableTag)) {
biomeSet.add(biome);
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.stage.mutators;
import java.util.Objects;
import com.dfsek.terra.addons.biome.pipeline.pipeline.BiomeChunkImpl.ViewPoint;
import com.dfsek.terra.addons.biome.pipeline.api.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.biome.PipelineBiome;
import com.dfsek.terra.api.noise.NoiseSampler;
public class SmoothStage implements Stage {
private final NoiseSampler sampler;
public SmoothStage(NoiseSampler sampler) {
this.sampler = sampler;
}
@Override
public PipelineBiome apply(ViewPoint viewPoint) {
PipelineBiome top = viewPoint.getRelativeBiome(1, 0);
PipelineBiome bottom = viewPoint.getRelativeBiome(-1, 0);
PipelineBiome left = viewPoint.getRelativeBiome(0, 1);
PipelineBiome right = viewPoint.getRelativeBiome(0, -1);
double roll = sampler.noise(viewPoint.worldSeed(), viewPoint.worldX(), viewPoint.worldZ());
boolean vert = Objects.equals(top, bottom);
boolean horiz = Objects.equals(left, right);
if(vert && horiz) {
return roll > 0 ?
roll > 0.25 ? left : right :
roll > -0.25 ? top : bottom;
}
if(vert) {
return roll > 0 ? top : bottom;
}
if(horiz) {
return roll > 0 ? left : right;
}
return viewPoint.getBiome();
}
@Override
public int maxRelativeReadDistance() {
return 1;
}
}
@@ -1,37 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.stages;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeExpander;
public class ExpanderStage implements Stage {
private final BiomeExpander expander;
public ExpanderStage(BiomeExpander expander) {
this.expander = expander;
}
@Override
public BiomeHolder apply(BiomeHolder in, long seed) {
return in.expand(expander, seed);
}
@Override
public boolean isExpansion() {
return true;
}
@Override
public Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) {
return biomes;
}
}
@@ -1,46 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.biome.pipeline.stages;
import com.dfsek.terra.addons.biome.pipeline.api.BiomeHolder;
import com.dfsek.terra.addons.biome.pipeline.api.delegate.BiomeDelegate;
import com.dfsek.terra.addons.biome.pipeline.api.stage.Stage;
import com.dfsek.terra.addons.biome.pipeline.api.stage.type.BiomeMutator;
public class MutatorStage implements Stage {
private final BiomeMutator mutator;
public MutatorStage(BiomeMutator mutator) {
this.mutator = mutator;
}
@Override
public BiomeHolder apply(BiomeHolder in, long seed) {
in.mutate(mutator, seed);
return in;
}
@Override
public boolean isExpansion() {
return false;
}
@Override
public Iterable<BiomeDelegate> getBiomes(Iterable<BiomeDelegate> biomes) {
return mutator.getBiomes(biomes);
}
public enum Type {
REPLACE,
REPLACE_LIST,
BORDER,
BORDER_LIST,
SMOOTH
}
}
@@ -8,6 +8,7 @@
package com.dfsek.terra.addons.biome.single;
import java.util.Collections;
import java.util.Optional;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@@ -25,6 +26,11 @@ public class SingleBiomeProvider implements BiomeProvider {
return biome;
}
@Override
public Optional<Biome> getBaseBiome(int x, int z, long seed) {
return Optional.of(biome);
}
@Override
public Iterable<Biome> getBiomes() {
return Collections.singleton(biome);
@@ -11,37 +11,38 @@ import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
import java.util.function.Supplier;
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.registry.CheckedRegistry;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.reflection.TypeKey;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import org.jetbrains.annotations.NotNull;
public class SingleBiomeProviderAddon implements AddonInitializer {
public class SingleBiomeProviderAddon implements MonadAddonInitializer {
public static final TypeKey<Supplier<ObjectTemplate<BiomeProvider>>> PROVIDER_REGISTRY_KEY = new TypeKey<>() {
};
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override
public void initialize() {
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(addon, ConfigPackPreLoadEvent.class)
.then(event -> {
CheckedRegistry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().getOrCreateRegistry(
PROVIDER_REGISTRY_KEY);
providerRegistry.register(addon.key("SINGLE"), SingleBiomeProviderTemplate::new);
})
.failThrough();
public @NotNull Monad<?, Init<?>> initialize() {
return Do.with(
Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
Get.addon(),
Get.platform(),
((handler, base, platform) -> Init.ofPure(
handler.register(base, ConfigPackPreLoadEvent.class)
.then(event -> {
Registry<Supplier<ObjectTemplate<BiomeProvider>>> providerRegistry = event.getPack().createRegistry(
PROVIDER_REGISTRY_KEY);
providerRegistry.register(base.key("SINGLE"), SingleBiomeProviderTemplate::new);
})
.failThrough()))
);
}
}
+4
View File
@@ -0,0 +1,4 @@
# Biome Query API
This addon contains an API to allow other addons to quickly query
Biome data, by baking queries and using Contexts on biomes.
@@ -0,0 +1,5 @@
version = version("1.0.0")
dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader"))
}
@@ -0,0 +1,48 @@
package com.dfsek.terra.addons.biome.query;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import com.dfsek.terra.addons.biome.query.impl.BiomeTagFlattener;
import com.dfsek.terra.addons.biome.query.impl.BiomeTagHolder;
import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.properties.PropertyKey;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.world.biome.Biome;
public class BiomeQueryAPIAddon implements MonadAddonInitializer {
public static PropertyKey<BiomeTagHolder> BIOME_TAG_KEY = Context.create(BiomeTagHolder.class);
@Override
public @NotNull Monad<?, Init<?>> initialize() {
return Do.with(
Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
Get.addon(),
((functionalEventHandler, base) -> Init.ofPure(
functionalEventHandler.register(base, ConfigPackPostLoadEvent.class)
.then(event -> {
Collection<Biome> biomes = event
.getPack()
.getRegistry(Biome.class)
.entries();
BiomeTagFlattener flattener = new BiomeTagFlattener(
biomes.stream()
.flatMap(biome -> biome.getTags().stream())
.toList());
biomes.forEach(biome -> biome.getContext()
.put(BIOME_TAG_KEY, new BiomeTagHolder(biome, flattener)));
})
.global()
)));
}
}
@@ -0,0 +1,17 @@
package com.dfsek.terra.addons.biome.query.api;
import java.util.function.Predicate;
import com.dfsek.terra.addons.biome.query.impl.SingleTagQuery;
import com.dfsek.terra.api.world.biome.Biome;
public final class BiomeQueries {
private BiomeQueries() {
}
public static Predicate<Biome> has(String tag) {
return new SingleTagQuery(tag);
}
}
@@ -0,0 +1,20 @@
package com.dfsek.terra.addons.biome.query.impl;
import java.util.List;
public class BiomeTagFlattener {
private final List<String> tags;
public BiomeTagFlattener(List<String> tags) {
this.tags = tags;
}
public int index(String tag) {
return tags.indexOf(tag);
}
public int size() {
return tags.size();
}
}
@@ -0,0 +1,26 @@
package com.dfsek.terra.addons.biome.query.impl;
import com.dfsek.terra.api.properties.Properties;
import com.dfsek.terra.api.world.biome.Biome;
public class BiomeTagHolder implements Properties {
private final boolean[] tags;
private final BiomeTagFlattener flattener;
public BiomeTagHolder(Biome biome, BiomeTagFlattener flattener) {
this.tags = new boolean[flattener.size()];
this.flattener = flattener;
for(String tag : biome.getTags()) {
tags[flattener.index(tag)] = true;
}
}
boolean get(int index) {
return tags[index];
}
public BiomeTagFlattener getFlattener() {
return flattener;
}
}
@@ -0,0 +1,31 @@
package com.dfsek.terra.addons.biome.query.impl;
import java.util.function.Predicate;
import com.dfsek.terra.addons.biome.query.BiomeQueryAPIAddon;
import com.dfsek.terra.api.world.biome.Biome;
public class SingleTagQuery implements Predicate<Biome> {
private final String tag;
private int tagIndex = -1;
public SingleTagQuery(String tag) {
this.tag = tag;
}
@Override
public boolean test(Biome biome) {
if(tagIndex < 0) {
tagIndex = biome
.getContext()
.get(BiomeQueryAPIAddon.BIOME_TAG_KEY)
.getFlattener()
.index(tag);
}
return biome
.getContext()
.get(BiomeQueryAPIAddon.BIOME_TAG_KEY)
.get(tagIndex);
}
}
@@ -0,0 +1,12 @@
schema-version: 1
contributors:
- Terra contributors
id: biome-query-api
version: @VERSION@
entrypoints:
- "com.dfsek.terra.addons.biome.query.BiomeQueryAPIAddon"
website:
issues: https://github.com/PolyhedralDev/Terra/issues
source: https://github.com/PolyhedralDev/Terra
docs: https://terra.polydev.org
license: MIT License
@@ -1,12 +1,5 @@
version = version("1.0.0")
version = version("1.1.0")
dependencies {
compileOnlyApi(project(":common:addons:manifest-addon-loader"))
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
}
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
relocate("net.jafama", "com.dfsek.terra.addons.chunkgenerator.lib.jafama")
}
@@ -9,54 +9,63 @@ package com.dfsek.terra.addons.chunkgenerator;
import com.dfsek.terra.addons.chunkgenerator.config.NoiseChunkGeneratorPackConfigTemplate;
import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseConfigTemplate;
import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties;
import com.dfsek.terra.addons.chunkgenerator.config.palette.BiomePaletteTemplate;
import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.config.palette.SlantLayer;
import com.dfsek.terra.addons.chunkgenerator.generation.NoiseChunkGenerator3D;
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
import com.dfsek.terra.addons.manifest.api.MonadAddonInitializer;
import com.dfsek.terra.addons.manifest.api.monad.Do;
import com.dfsek.terra.addons.manifest.api.monad.Get;
import com.dfsek.terra.addons.manifest.api.monad.Init;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.properties.PropertyKey;
import com.dfsek.terra.api.util.function.monad.Monad;
import com.dfsek.terra.api.util.generic.Construct;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.chunk.generation.util.provider.ChunkGeneratorProvider;
import org.jetbrains.annotations.NotNull;
public class NoiseChunkGenerator3DAddon implements AddonInitializer {
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
public class NoiseChunkGenerator3DAddon implements MonadAddonInitializer {
@Override
public void initialize() {
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(addon, ConfigPackPreLoadEvent.class)
.then(event -> {
NoiseChunkGeneratorPackConfigTemplate config = event.loadTemplate(new NoiseChunkGeneratorPackConfigTemplate());
event.getPack()
.getOrCreateRegistry(ChunkGeneratorProvider.class)
.register(addon.key("NOISE_3D"),
pack -> new NoiseChunkGenerator3D(platform, config.getElevationBlend(), config.getHorizontalRes(),
config.getVerticalRes()));
event.getPack()
.applyLoader(SlantLayer.class, SlantLayer::new);
})
.failThrough();
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(addon, ConfigurationLoadEvent.class)
.then(event -> {
if(event.is(Biome.class)) {
event.getLoadedObject(Biome.class).getContext().put(event.load(new BiomePaletteTemplate(platform)).get());
event.getLoadedObject(Biome.class).getContext().put(event.load(new BiomeNoiseConfigTemplate()).get());
}
})
.failThrough();
public @NotNull Monad<?, Init<?>> initialize() {
PropertyKey<PaletteInfo> paletteInfoPropertyKey = Context.create(PaletteInfo.class);
PropertyKey<BiomeNoiseProperties> noisePropertiesPropertyKey = Context.create(BiomeNoiseProperties.class);
return Do.with(
Get.eventManager().map(eventManager -> eventManager.getHandler(FunctionalEventHandler.class)),
Get.addon(),
Get.platform(),
((handler, base, platform) -> Init.ofPure(Construct.construct(() -> {
handler.register(base, ConfigPackPreLoadEvent.class)
.priority(1000)
.then(event -> {
NoiseChunkGeneratorPackConfigTemplate config = event.loadTemplate(new NoiseChunkGeneratorPackConfigTemplate());
event.getPack()
.createRegistry(ChunkGeneratorProvider.class)
.register(base.key("NOISE_3D"),
pack -> new NoiseChunkGenerator3D(pack, platform, config.getElevationBlend(),
config.getHorizontalRes(),
config.getVerticalRes(), noisePropertiesPropertyKey,
paletteInfoPropertyKey));
event.getPack()
.applyLoader(SlantLayer.class, SlantLayer::new);
})
.failThrough();
return handler.register(base, ConfigurationLoadEvent.class)
.then(event -> {
if(event.is(Biome.class)) {
event.getLoadedObject(Biome.class).getContext().put(paletteInfoPropertyKey,
event.load(new BiomePaletteTemplate(platform)).get());
event.getLoadedObject(Biome.class).getContext().put(noisePropertiesPropertyKey,
event.load(new BiomeNoiseConfigTemplate()).get());
}
})
.failThrough();
}))));
}
}
@@ -39,6 +39,6 @@ public class BiomeNoiseConfigTemplate implements ObjectTemplate<BiomeNoiseProper
@Override
public BiomeNoiseProperties get() {
return new BiomeNoiseProperties(baseSampler, elevationSampler, carvingSampler, blendDistance, blendStep, blendWeight,
elevationWeight);
elevationWeight, new ThreadLocalNoiseHolder());
}
}
@@ -10,6 +10,6 @@ public record BiomeNoiseProperties(NoiseSampler base,
int blendDistance,
int blendStep,
double blendWeight,
double elevationWeight) implements Properties {
double elevationWeight,
ThreadLocalNoiseHolder noiseHolder) implements Properties {
}
@@ -0,0 +1,32 @@
package com.dfsek.terra.addons.chunkgenerator.config.noise;
import com.dfsek.terra.api.noise.NoiseSampler;
public class ThreadLocalNoiseHolder {
private final ThreadLocal<Holder> holder = ThreadLocal.withInitial(Holder::new);
public double getNoise(NoiseSampler sampler, int x, int y, int z, long seed) {
Holder holder = this.holder.get();
if(holder.init && holder.y == y && holder.z == z && holder.x == x && holder.seed == seed) {
return holder.noise;
}
double noise = sampler.noise(seed, x, y, z);
holder.noise = noise;
holder.x = x;
holder.y = y;
holder.z = z;
holder.seed = seed;
holder.init = true;
return noise;
}
private static final class Holder {
int x, y, z;
boolean init = false;
long seed;
double noise;
}
}
@@ -59,6 +59,10 @@ public class BiomePaletteTemplate implements ObjectTemplate<PaletteInfo> {
}
};
@Value("carving.update-palette")
@Default
private @Meta boolean updatePalette = false;
public BiomePaletteTemplate(Platform platform) { this.platform = platform; }
@Override
@@ -71,14 +75,15 @@ public class BiomePaletteTemplate implements ObjectTemplate<PaletteInfo> {
}
TreeMap<Double, PaletteHolder> slantLayers = new TreeMap<>();
double minThreshold = Double.MAX_VALUE;
double maxThreshold = Double.MIN_VALUE;
for(SlantLayer layer : slant) {
double threshold = layer.getThreshold();
if(threshold < minThreshold) minThreshold = threshold;
if(threshold > maxThreshold) maxThreshold = threshold;
slantLayers.put(threshold, layer.getPalette());
}
return new PaletteInfo(builder.build(), SlantHolder.of(slantLayers, minThreshold), oceanPalette, seaLevel, slantDepth);
return new PaletteInfo(builder.build(), SlantHolder.of(slantLayers, maxThreshold), oceanPalette, seaLevel, slantDepth,
updatePalette);
}
}
@@ -17,5 +17,6 @@ public record PaletteInfo(PaletteHolder paletteHolder,
SlantHolder slantHolder,
Palette ocean,
int seaLevel,
int maxSlantDepth) implements Properties {
int maxSlantDepth,
boolean updatePaletteWhenCarving) implements Properties {
}
@@ -11,6 +11,7 @@ package com.dfsek.terra.addons.chunkgenerator.generation;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties;
import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.generation.math.PaletteUtil;
import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.LazilyEvaluatedInterpolator;
@@ -18,6 +19,8 @@ import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.SamplerProvider;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.properties.PropertyKey;
import com.dfsek.terra.api.util.Column;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
@@ -36,13 +39,28 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
private final int carverHorizontalResolution;
private final int carverVerticalResolution;
public NoiseChunkGenerator3D(Platform platform, int elevationBlend, int carverHorizontalResolution,
int carverVerticalResolution) {
private final PropertyKey<PaletteInfo> paletteInfoPropertyKey;
private final PropertyKey<BiomeNoiseProperties> noisePropertiesKey;
public NoiseChunkGenerator3D(ConfigPack pack, Platform platform, int elevationBlend, int carverHorizontalResolution,
int carverVerticalResolution,
PropertyKey<BiomeNoiseProperties> noisePropertiesKey,
PropertyKey<PaletteInfo> paletteInfoPropertyKey) {
this.platform = platform;
this.air = platform.getWorldHandle().air();
this.carverHorizontalResolution = carverHorizontalResolution;
this.carverVerticalResolution = carverVerticalResolution;
this.samplerCache = new SamplerProvider(platform, elevationBlend);
this.paletteInfoPropertyKey = paletteInfoPropertyKey;
this.noisePropertiesKey = noisePropertiesKey;
int maxBlend = pack
.getBiomeProvider()
.stream()
.map(biome -> biome.getContext().get(noisePropertiesKey))
.mapToInt(properties -> properties.blendDistance() * properties.blendStep())
.max()
.orElse(0);
this.samplerCache = new SamplerProvider(platform, elevationBlend, noisePropertiesKey, maxBlend);
}
@Override
@@ -62,7 +80,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
chunkX,
chunkZ,
world.getMaxHeight(),
world.getMinHeight(),
noisePropertiesKey, world.getMinHeight(),
carverHorizontalResolution,
carverVerticalResolution,
seed);
@@ -73,23 +91,28 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
int cx = xOrig + x;
int cz = zOrig + z;
Biome biome = biomeProvider.getBiome(cx, 0, cz, seed);
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
int sea = paletteInfo.seaLevel();
Palette seaPalette = paletteInfo.ocean();
BlockState data;
Column<Biome> biomeColumn = biomeProvider.getColumn(cx, cz, world);
for(int y = world.getMaxHeight() - 1; y >= world.getMinHeight(); y--) {
Biome biome = biomeColumn.get(y);
PaletteInfo paletteInfo = biome.getContext().get(paletteInfoPropertyKey);
int sea = paletteInfo.seaLevel();
Palette seaPalette = paletteInfo.ocean();
if(sampler.sample(x, y, z) > 0) {
if(carver.sample(x, y, z) <= 0) {
data = PaletteUtil.getPalette(x, y, z, sampler, paletteInfo, paletteLevel).get(paletteLevel, cx, y, cz,
seed);
data = PaletteUtil
.getPalette(x, y, z, sampler, paletteInfo, paletteLevel)
.get(paletteLevel, cx, y, cz, seed);
chunk.setBlock(x, y, z, data);
paletteLevel++;
} else if(paletteInfo.updatePaletteWhenCarving()) {
paletteLevel = 0;
} else {
paletteLevel++;
}
paletteLevel++;
} else if(y <= sea) {
chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, y, z + zOrig, seed));
paletteLevel = 0;
@@ -107,7 +130,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
Biome biome = biomeProvider.getBiome(x, y, z, world.getSeed());
Sampler3D sampler = samplerCache.get(x, z, world, biomeProvider);
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
PaletteInfo paletteInfo = biome.getContext().get(paletteInfoPropertyKey);
int fdX = FastMath.floorMod(x, 16);
int fdZ = FastMath.floorMod(z, 16);
@@ -128,7 +151,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
@Override
public Palette getPalette(int x, int y, int z, WorldProperties world, BiomeProvider biomeProvider) {
return biomeProvider.getBiome(x, y, z, world.getSeed()).getContext().get(PaletteInfo.class).paletteHolder().getPalette(y);
return biomeProvider.getBiome(x, y, z, world.getSeed()).getContext().get(paletteInfoPropertyKey).paletteHolder().getPalette(y);
}
public SamplerProvider samplerProvider() {
@@ -10,6 +10,7 @@ package com.dfsek.terra.addons.chunkgenerator.generation.math;
import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.chunk.generation.util.Palette;
@@ -22,25 +23,32 @@ public final class PaletteUtil {
public static Palette getPalette(int x, int y, int z, Sampler3D sampler, PaletteInfo paletteInfo, int depth) {
SlantHolder slant = paletteInfo.slantHolder();
if(!slant.isEmpty() && depth <= paletteInfo.maxSlantDepth()) {
double slope = derivative(sampler, x, y, z);
if(slope > slant.getMinSlope()) {
return slant.getPalette(slope).getPalette(y);
double dot = surfaceNormalDotProduct(sampler, x, y, z);
if(dot <= slant.getMaxSlant()) {
return slant.getPalette(dot).getPalette(y);
}
}
return paletteInfo.paletteHolder().getPalette(y);
}
public static double derivative(Sampler3D sampler, double x, double y, double z) {
double baseSample = sampler.sample(x, y, z);
double xVal1 = (sampler.sample(x + DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST;
double xVal2 = (sampler.sample(x - DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST;
double zVal1 = (sampler.sample(x, y, z + DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST;
double zVal2 = (sampler.sample(x, y, z - DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST;
double yVal1 = (sampler.sample(x, y + DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST;
double yVal2 = (sampler.sample(x, y - DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST;
return Math.sqrt(((xVal2 - xVal1) * (xVal2 - xVal1)) + ((zVal2 - zVal1) * (zVal2 - zVal1)) + ((yVal2 - yVal1) * (yVal2 - yVal1)));
private static final Vector3[] samplePoints = {
Vector3.of(0, 0, -DERIVATIVE_DIST),
Vector3.of(0, 0, DERIVATIVE_DIST),
Vector3.of(0, -DERIVATIVE_DIST, 0),
Vector3.of(0, DERIVATIVE_DIST, 0),
Vector3.of(-DERIVATIVE_DIST, 0, 0),
Vector3.of(DERIVATIVE_DIST, 0, 0),
};
private static final Vector3 direction = Vector3.of(0, 1, 0);
public static double surfaceNormalDotProduct(Sampler3D sampler, double x, double y, double z) {
Vector3.Mutable surfaceNormalApproximation = Vector3.Mutable.of(0, 0, 0);
for(Vector3 point : samplePoints) {
double scalar = -sampler.sample(x+point.getX(), y+point.getY(), z+point.getZ());
surfaceNormalApproximation.add(point.mutable().multiply(scalar));
}
return direction.dot(surfaceNormalApproximation.normalize());
}
}
@@ -9,11 +9,10 @@ package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import net.jafama.FastMath;
import java.util.HashMap;
import java.util.Map;
import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.api.properties.PropertyKey;
import com.dfsek.terra.api.util.Column;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
@@ -23,7 +22,6 @@ import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
*/
public class ChunkInterpolator {
private final Interpolator3[][][] interpGrid;
private final long seed;
private final int min;
private final int max;
@@ -37,10 +35,10 @@ public class ChunkInterpolator {
* @param min
* @param max
*/
public ChunkInterpolator(long seed, int chunkX, int chunkZ, BiomeProvider provider, int min, int max) {
public ChunkInterpolator(long seed, int chunkX, int chunkZ, BiomeProvider provider, int min, int max,
PropertyKey<BiomeNoiseProperties> noisePropertiesKey, int maxBlend) {
this.min = min;
this.max = max;
this.seed = seed;
int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4;
@@ -53,28 +51,67 @@ public class ChunkInterpolator {
double[][][] noiseStorage = new double[5][5][size + 1];
int maxBlendAndChunk = 17 + 2 * maxBlend;
@SuppressWarnings("unchecked")
Column<Biome>[] columns = new Column[maxBlendAndChunk * maxBlendAndChunk];
for(int x = 0; x < 5; x++) {
int scaledX = x << 2;
int absoluteX = xOrigin + scaledX;
for(int z = 0; z < 5; z++) {
BiomeNoiseProperties generationSettings = provider.getBiome(xOrigin + (x << 2), 0, zOrigin + (z << 2), seed)
.getContext()
.get(BiomeNoiseProperties.class);
Map<BiomeNoiseProperties, MutableInteger> genMap = new HashMap<>();
int scaledZ = z << 2;
int absoluteZ = zOrigin + scaledZ;
int step = generationSettings.blendStep();
int blend = generationSettings.blendDistance();
int index = (scaledX + maxBlend) + maxBlendAndChunk * (scaledZ + maxBlend);
Column<Biome> biomeColumn = columns[index];
for(int xi = -blend; xi <= blend; xi++) {
for(int zi = -blend; zi <= blend; zi++) {
genMap.computeIfAbsent(
provider.getBiome(xOrigin + (x << 2) + (xi * step), 0, zOrigin + (z << 2) + (zi * step), seed)
.getContext()
.get(BiomeNoiseProperties.class),
g -> new MutableInteger(0)).increment(); // Increment by 1
}
if(biomeColumn == null) {
biomeColumn = provider.getColumn(absoluteX, absoluteZ, seed, min, max);
columns[index] = biomeColumn;
}
for(int y = 0; y < size + 1; y++) {
noiseStorage[x][z][y] = computeNoise(genMap, (x << 2) + xOrigin, (y << 2) + this.min, (z << 2) + zOrigin);
for(int y = 0; y < size; y++) {
int scaledY = (y << 2) + min;
BiomeNoiseProperties generationSettings = biomeColumn.get(scaledY)
.getContext()
.get(noisePropertiesKey);
int step = generationSettings.blendStep();
int blend = generationSettings.blendDistance();
double runningNoise = 0;
double runningDiv = 0;
for(int xi = -blend; xi <= blend; xi++) {
for(int zi = -blend; zi <= blend; zi++) {
int blendX = (xi * step);
int blendZ = (zi * step);
int localIndex = (scaledX + maxBlend + blendX) + maxBlendAndChunk * (scaledZ + maxBlend + blendZ);
Column<Biome> column = columns[localIndex];
if(column == null) {
column = provider.getColumn(absoluteX + blendX, absoluteZ + blendZ, seed, min, max);
columns[localIndex] = column;
}
BiomeNoiseProperties properties = column
.get(scaledY)
.getContext()
.get(noisePropertiesKey);
double sample = properties.noiseHolder().getNoise(properties.base(), absoluteX, scaledY, absoluteZ, seed);
runningNoise += sample * properties.blendWeight();
runningDiv += properties.blendWeight();
}
}
double noise = runningNoise / runningDiv;
noiseStorage[x][z][y] = noise;
if(y == size - 1) {
noiseStorage[x][z][size] = noise;
}
}
}
}
@@ -100,24 +137,6 @@ public class ChunkInterpolator {
return FastMath.max(FastMath.min(value, high), 0);
}
public double computeNoise(BiomeNoiseProperties generationSettings, double x, double y, double z) {
return generationSettings.base().noise(seed, x, y, z);
}
public double computeNoise(Map<BiomeNoiseProperties, MutableInteger> gens, double x, double y, double z) {
double n = 0;
double div = 0;
for(Map.Entry<BiomeNoiseProperties, MutableInteger> entry : gens.entrySet()) {
BiomeNoiseProperties gen = entry.getKey();
int weight = entry.getValue().get();
double noise = computeNoise(gen, x, y, z);
n += noise * weight;
div += gen.blendWeight() * weight;
}
return n / div;
}
/**
* Gets the noise at a pair of internal chunk coordinates.
*

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