diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml
index 456e54bd1..0619d1b15 100644
--- a/.github/workflows/build_release.yml
+++ b/.github/workflows/build_release.yml
@@ -140,4 +140,4 @@ jobs:
webhook_token: ${{ secrets.DISCORD_TOKEN }}
color: "#088c7d"
username: "Maykr Bot"
- message: "**:package: ${{ needs.changelog.outputs.tag }}**\n\n**Download**\n${{ fromJSON(steps.create_release.outputs.assets)[0].browser_download_url }}\n\n**Changelog**\n${{ steps.create_release.outputs.url }}"
+ message: "**:package: ${{ needs.changelog.outputs.tag }}**\n\n**Download**\n${{ fromJSON(steps.create_release.outputs.assets)[1].browser_download_url }}\n\n**Changelog**\n${{ steps.create_release.outputs.url }}"
diff --git a/.github/workflows/gh_release.yml b/.github/workflows/gh_release.yml
index da716af61..e47560d92 100644
--- a/.github/workflows/gh_release.yml
+++ b/.github/workflows/gh_release.yml
@@ -148,4 +148,4 @@ jobs:
webhook_token: ${{ secrets.DISCORD_TOKEN }}
color: "#088c7d"
username: "Maykr Bot"
- message: "**:package: ${{ needs.changelog.outputs.tag }}**\n\n**Download**\n${{ fromJSON(steps.create_release.outputs.assets)[0].browser_download_url }}\n\n**Changelog**\n${{ steps.create_release.outputs.url }}"
+ message: "**:package: ${{ needs.changelog.outputs.tag }}**\n\n**Download**\n${{ fromJSON(steps.create_release.outputs.assets)[1].browser_download_url }}\n\n**Changelog**\n${{ steps.create_release.outputs.url }}"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ea22e4cf6..69213db85 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,149 +1,84 @@
-## [2.0.0](https://github.com/Elenterius/Biomancy/compare/1.19.2-v2.1.13.0...1.19.2-v2.2.0.0) (2023-09-09)
+## [2.9.0](https://github.com/Elenterius/Biomancy/compare/1.19.2-v2.2.8.0...1.19.2-v2.2.9.0) (2023-12-29)
-### ⚠ BREAKING CHANGES
-
-* move menu package from inventory package into main package
-* rename item interfaces
-* **recipes:** change json structure and key names of recipes
-
### Features
-* add ability to "pet" Flesh Blobs ([377bff8](https://github.com/Elenterius/Biomancy/commit/377bff842406bc25c378ac202d82eb15e7050719))
-* add Caro Invitica font by Tyfin ([ccd2845](https://github.com/Elenterius/Biomancy/commit/ccd2845f53b65151e0ec17911013afce7568aef0))
-* add Chiseled Flesh block ([6597d23](https://github.com/Elenterius/Biomancy/commit/6597d234f1049dbb4f5940aa870fe02c61bc6f58))
-* add claws & fangs item tags for crafting ([3aa4eac](https://github.com/Elenterius/Biomancy/commit/3aa4eac074c19fb2482f9192be11f667f177de73))
-* add Corrosive Swipe Attack VFX to the Toxicus ([048c428](https://github.com/Elenterius/Biomancy/commit/048c4289ef5e874468598fa0a21a1be06bf1bfbe))
-* add Drowsy Status Effect which prevents Phantoms from attacking ([2a2449d](https://github.com/Elenterius/Biomancy/commit/2a2449d4c4507bd1bf232be5b2ab5064fc3091ea))
-* add Fibrous Flesh block ([fc0085e](https://github.com/Elenterius/Biomancy/commit/fc0085ea27157f6bdc6bdf2df535fddeb3815732))
-* add Fleshy Membrane block ([f9bf0ef](https://github.com/Elenterius/Biomancy/commit/f9bf0ef413ee86707eaf7c0ae12494dca53478c6))
-* add HUD for the serum amount inside an Injector ([62e17a2](https://github.com/Elenterius/Biomancy/commit/62e17a264ecc57e3ed12132678e39e15816784ca))
-* add item gui icon for the Ravenous Claws ([c0ca2b9](https://github.com/Elenterius/Biomancy/commit/c0ca2b9342d0d3e9817401fe4088d0cd52a0f7ad))
-* add item texture for the Flesh Spike ([666a5df](https://github.com/Elenterius/Biomancy/commit/666a5df3a6e5e46295eeecf093b024847cde23cb))
-* add item texture for the Tendon Chain ([d0c1110](https://github.com/Elenterius/Biomancy/commit/d0c1110285dcf0e403598f5d2294a039a706ff5b))
-* add malignant and primal flesh walls ([3c44be5](https://github.com/Elenterius/Biomancy/commit/3c44be5384846e25646ad173533c22941927557d))
-* add Malignant Flesh Block recipes ([f088d72](https://github.com/Elenterius/Biomancy/commit/f088d72928d84529aecee9ded5f80424950ee5c7))
-* add Ornate Flesh block ([82a222c](https://github.com/Elenterius/Biomancy/commit/82a222c43c6fdadfe7215796bbb40d63494543f7))
-* add Primal Flesh Block recipes ([bd4c5ff](https://github.com/Elenterius/Biomancy/commit/bd4c5ff44d4f6f45cbfc3227a5e37c9ae4e0ec86))
-* add primordial bio lantern ([c5ca95a](https://github.com/Elenterius/Biomancy/commit/c5ca95a5b3c5792eb6285a713332e74f28bcec48))
-* add specialised membrane variants for items, babies and adult mobs ([c472856](https://github.com/Elenterius/Biomancy/commit/c472856fb97a4f791ace1a6097c063141d3b8fbd))
-* add Toxicus ([ed0a733](https://github.com/Elenterius/Biomancy/commit/ed0a7333607301a48ec4e92d447c39c3ce93767b))
-* add Tubular Flesh block ([26216e3](https://github.com/Elenterius/Biomancy/commit/26216e3bb7e5190caca141eb831e6a7223f8212d))
-* buff Flesh Plunderer damage from 10 to 12 and durability from 60 to 250 ([a8b7219](https://github.com/Elenterius/Biomancy/commit/a8b721969427f17da3422fc75725aff8b1c47142))
-* change injector item icon texture ([cddccb0](https://github.com/Elenterius/Biomancy/commit/cddccb0c5a4a9b2cc6b92c6580cb522d41665bc4))
-* enable shading for tendon chain & hanging bio lantern model ([d68742e](https://github.com/Elenterius/Biomancy/commit/d68742eaef58710ddd00a5fe191a88e5e9c2f360))
-* fix and improve malignant flesh spreading mechanics ([ba6d415](https://github.com/Elenterius/Biomancy/commit/ba6d41594ce6af3b25379d70a0df5256d34a1a53))
-* fix Injector not reloading with max serum amount ([bf641d9](https://github.com/Elenterius/Biomancy/commit/bf641d9089d83094ab1c7ba3b46e92095f9c2396))
-* fix primordial flesh blobs spawning with tumors when summoned via spawn eggs ([6ae6103](https://github.com/Elenterius/Biomancy/commit/6ae6103bfe6ee50c533618d990fe673a45a49909))
-* give creative players the ability to see all Bio-Forge recipe regardless of if they have unlocked them ([1e3cfd0](https://github.com/Elenterius/Biomancy/commit/1e3cfd09baf076569569b961a1874bdd205d5976))
-* increase Breeding Stimulant duration from 12 to 14 seconds ([1e5c5f0](https://github.com/Elenterius/Biomancy/commit/1e5c5f0dea6c43c2acb3c25c74907e01a1da5a5a))
-* make all Flesh Blob sounds resource pack driven ([7d896ff](https://github.com/Elenterius/Biomancy/commit/7d896ffa9c51fc2ca52dd2d59cccdb38f4ec6710))
-* make Cleansing Serum consume saturation ([2ec8754](https://github.com/Elenterius/Biomancy/commit/2ec8754b666439824757cb47b32f863fb215b1ae))
-* make crafting cost (nutrients) data driven by including them in recipes ([6b38c12](https://github.com/Elenterius/Biomancy/commit/6b38c1299cb7235ab51b80fa63155167997122db))
-* make flesh plunderer magic outline emissive ([a75f2b9](https://github.com/Elenterius/Biomancy/commit/a75f2b911b1e142d0c41f77590834222075c6bfa))
-* make Flesh Spikes fall-on damage scale with the spike amount ([845e38e](https://github.com/Elenterius/Biomancy/commit/845e38eefcac1f4adfff61da01a11c3f159ad74a))
-* make Insomnia Cure serum apply the Drowsy status effect ([9e894cd](https://github.com/Elenterius/Biomancy/commit/9e894cdd1f815c9535b33f76fe70082538dc8ceb))
-* make Malignant Veins harvestable with silk touch tools (additionally to shears) ([2a0d2fc](https://github.com/Elenterius/Biomancy/commit/2a0d2fcc7c69c2922fa5267f7940642e82cf5a98))
-* make membrane block deal reduced fall damage ([d595417](https://github.com/Elenterius/Biomancy/commit/d595417fbd678c726a9d5d662926fdb7c2c0bd72))
-* make part of the Primordial Core item emissive ([2717963](https://github.com/Elenterius/Biomancy/commit/271796386426284c082c214e8e513c64fb621c3b))
-* mirco-buff Ravenous Claws ([ae231b2](https://github.com/Elenterius/Biomancy/commit/ae231b2f3699041b099c1c7ec8834f9a13780542))
-* **mod-compat:** add Create compacting recipes for flesh blocks ([47c2148](https://github.com/Elenterius/Biomancy/commit/47c21482dfce02d4d95c63d401d822b8e3494555))
-* obfuscate primal and malignant flesh block tooltips ([7ccefc8](https://github.com/Elenterius/Biomancy/commit/7ccefc8f79c31710097fd4535298cb22a6a8e1ca))
-* **recipes:** add Claw recipe to Bio-Forge ([c9912b6](https://github.com/Elenterius/Biomancy/commit/c9912b689f37c408e8705e677df011017c00332b))
-* **recipes:** add Fang recipe to Bio-Forge ([0cb2708](https://github.com/Elenterius/Biomancy/commit/0cb2708397b889cf99fe4c89058bd3339af06d14))
-* **recipes:** buff decomposing recipe of Golden Apples ([146a7ae](https://github.com/Elenterius/Biomancy/commit/146a7ae0af4481b669515cb639de1197072aba01))
-* **recipes:** change json structure and key names of recipes ([f488a0f](https://github.com/Elenterius/Biomancy/commit/f488a0f4ba48413e0144922af70df01285d7cb96))
-* **recipes:** nerf Flesh Spike recipe ([85489f9](https://github.com/Elenterius/Biomancy/commit/85489f9a5815942a28dae3f24bc91b1e870f49e8))
-* **recipes:** nerf kelp decomposing recipe ([a773441](https://github.com/Elenterius/Biomancy/commit/a773441f543baf86bee03986f277a14aa5c53b43))
-* **recipes:** nerf kelp digesting recipe ([85e843c](https://github.com/Elenterius/Biomancy/commit/85e843c9e1426390fbc5e3472f15e4c7e4ec9d80))
-* **recipes:** nerf Ravenous Claws recipe ([6205b23](https://github.com/Elenterius/Biomancy/commit/6205b2398914f55744125034ebff47f3561978b2))
-* **recipes:** remove Primordial Cradle recipe from Bio-Forge ([26ac3eb](https://github.com/Elenterius/Biomancy/commit/26ac3eb47f0d0773f03fbcc7de050ebb861e42af))
-* remove experimental Item-Membrane block ([9d2e108](https://github.com/Elenterius/Biomancy/commit/9d2e10826fffe0f67a4752a12b96fffae7a88921))
-* remove name tag for legacy flesh blob texture (legacy flesh blob is now a cradle easter egg) ([0750904](https://github.com/Elenterius/Biomancy/commit/075090440e940f883ccf0db5badf82841c9cae98))
-* remove trash slot from Bio-Lab UI ([dd94f80](https://github.com/Elenterius/Biomancy/commit/dd94f80d5f0aec87965e8507e9fcfb042ba4e461))
-* remove unused corrupted primal flesh block ([817861b](https://github.com/Elenterius/Biomancy/commit/817861b5f049d00918662015b335b31ab40b0597))
-* replace Malignant Flesh Blob with Primordial Flesh Blob variants ([5dc5d3e](https://github.com/Elenterius/Biomancy/commit/5dc5d3e1b49de6ff4f36a8f6a6504700b34955e0))
-* rework Cradle sacrifice system to prefer to spawn hostile mobs and occasionally anomalies ([cde0e36](https://github.com/Elenterius/Biomancy/commit/cde0e361a0461da44076488db0c7fcdfc585ef99))
-* tweak Adult-Membrane color ([67383e4](https://github.com/Elenterius/Biomancy/commit/67383e4e458672a038bd93c31b1ced09055f0587))
-* tweak flesh block recipes ([382948c](https://github.com/Elenterius/Biomancy/commit/382948c8d315eabfe4b2530dad1e402a53dc6acb))
-* tweak tooltip colors ([7a47e29](https://github.com/Elenterius/Biomancy/commit/7a47e29537647c76f9c811a6747f1939f1ae1ef9))
-* update flesh blob troll texture ([96152b6](https://github.com/Elenterius/Biomancy/commit/96152b64b42fc8891d1dd871d9c874c3506b739c))
-* update Flesh Block variant textures ([34557eb](https://github.com/Elenterius/Biomancy/commit/34557eb48dc866c77b24d9ae71b6ec71bfaf481a))
-
-
-### Bug Fixes
+* **flesh-mound:** add bone pillar generation ([6c65cc1](https://github.com/Elenterius/Biomancy/commit/6c65cc17cf131864d5129b6052a07f7efaf43958))
+* **flesh-mound:** allow destruction of melons, pumpkins and moss ([f7acee8](https://github.com/Elenterius/Biomancy/commit/f7acee8d751e00fc07b7790f8928b615b69fe6f4))
+* **flesh-mound:** make mounds slightly smaller ([0448cd8](https://github.com/Elenterius/Biomancy/commit/0448cd8c30cf00f499a8a4efa637b8f7dada1028))
+* **flesh-mound:** make Primal Membrane self-spreading inside flesh mounds ([3db8c25](https://github.com/Elenterius/Biomancy/commit/3db8c256584c2ac8d1dd664e77fb2d12fa810aa5))
+* make primal membrane consider golems as not alive ([6435e3a](https://github.com/Elenterius/Biomancy/commit/6435e3aafbf866698f42d52ecad25f6e13c798fd))
-* fix alex's mobs kangaroo and moose ribs decomposer recipes (remove nutrients output) ([77e0baa](https://github.com/Elenterius/Biomancy/commit/77e0baa705baffa1c71807c915a4395a2dc5c736))
-* fix buggy Vial Holder block breaking ([c190dc4](https://github.com/Elenterius/Biomancy/commit/c190dc49125193468caaa88b58f30778ab6a0ebc))
-* fix critical hits not being detected ([0e89f24](https://github.com/Elenterius/Biomancy/commit/0e89f24f182f0771bae1f25ea65b8d6cf8653687))
-* fix Flesh Spike block not dropping the correct amount of spikes ([f91c641](https://github.com/Elenterius/Biomancy/commit/f91c641d346f52da6a49d6738c48468b5970571c))
-* fix Flesh Spikes destroying Items ([0a6f1f6](https://github.com/Elenterius/Biomancy/commit/0a6f1f661e7fba3f1ea7c22b62c06df4f8786a5c))
-* fix inability to inject tamed mobs with Serums ([310af51](https://github.com/Elenterius/Biomancy/commit/310af512857c87dbd64df3626d37a817d6b715cd))
-* fix incompatibility with outdated versions of Create by simply not setting up any compat for it (min. Create version is now 0.5.0) ([0c98e12](https://github.com/Elenterius/Biomancy/commit/0c98e123ad91dfc0dfbe295aa8399ffb4590e3ce))
-* fix Insomnia Cure "not sleepy" check not working properly ([7c628e5](https://github.com/Elenterius/Biomancy/commit/7c628e565e611eb945eaff129e99d001d407a5d3))
-* fix Primordial Cradle consuming Tetra tools ([9ee49e4](https://github.com/Elenterius/Biomancy/commit/9ee49e4853a6bf052e13c33e69040f3acd3356e9))
-* fix Primordial Cradle not being marked as changed when the spread charge is consumed ([faffc4d](https://github.com/Elenterius/Biomancy/commit/faffc4d99c67e716964fbd3ee5f01e401dc6eeb5))
-* fix SacrificeHandler incorrectly tracking if it has any modifiers applied ([674e703](https://github.com/Elenterius/Biomancy/commit/674e703a77637a965cc0d6043c13a2241efcfa85))
-* fix white line on the bottom of the Flesh Door model ([2a774b2](https://github.com/Elenterius/Biomancy/commit/2a774b27089abf21f58955a1789d3f0a142faacc))
+## [2.8.0](https://github.com/Elenterius/Biomancy/compare/1.19.2-v2.2.7.0...1.19.2-v2.2.8.0) (2023-12-24)
-### Performance Improvements
-
-* use cached animations for Flesh Blobs ([002def3](https://github.com/Elenterius/Biomancy/commit/002def3110d3913ba117eab56e56ab185d88b476))
-
-
-### Miscellaneous Chores
+### Features
-* rename item interfaces ([19ea1db](https://github.com/Elenterius/Biomancy/commit/19ea1db2ba4e314e939f3eb5ef5bf62a72a4e699))
+* **acid:** reduce probability for acid particles to produce fizzling smoke when landing on ground ([df8e315](https://github.com/Elenterius/Biomancy/commit/df8e31512cc59eada311f5d7584daec4d6673e53))
+* add bloomlight recipe ([2de5134](https://github.com/Elenterius/Biomancy/commit/2de51343c0140e8fe6dbc827f1c3020371e55eb0))
+* buff strength of `FleshyBone` material (increase destroy time from 3 to 4 and explosion resistance from 3 to 6) ([9b7bf5c](https://github.com/Elenterius/Biomancy/commit/9b7bf5cd45e08f88da93ba9984335c455095a8ae))
+* change Primordial Lantern recipe to require a Sapberry ([33f3c25](https://github.com/Elenterius/Biomancy/commit/33f3c25cff5bad886656e8cbf55a0a032c0824d9))
+* change the block material of Flesh Pillar, Chiseled Flesh and Ornate Flesh to `FleshyBone` material ([2c9074a](https://github.com/Elenterius/Biomancy/commit/2c9074af6775f61db591d025e6864940f4d07894))
+* **flesh-mound:** add chamber decorations such as pillars, orifices, etc. ([8f0bdb2](https://github.com/Elenterius/Biomancy/commit/8f0bdb2c836c63dd6c7d47e6f61957c652de53f9))
+* increase explosion resistance of Packed Flesh from 6 to 12 ([cf05380](https://github.com/Elenterius/Biomancy/commit/cf05380ee3e8eb7b9a921517984657cc364b2f18))
+* **item-tag:** add `cannot_be_eaten_by_cradle` tag for items that should not be eaten by the Cradle ([52d2b60](https://github.com/Elenterius/Biomancy/commit/52d2b60e3f61c75ea849404549019fc09247d74f))
+* **item-tag:** add items to forge tags for doors, trapdoors and chests ([138f2f1](https://github.com/Elenterius/Biomancy/commit/138f2f1ed6a68eaa4e6af9ea461f14faf340b53b))
+* make bony flesh blocks play flesh or bone sounds (with equal probability) ([648650c](https://github.com/Elenterius/Biomancy/commit/648650c3ee001f232fedc7ffb9bf71bf655234ee))
+* make primal orifices milk-able with empty buckets ([2949671](https://github.com/Elenterius/Biomancy/commit/2949671e004e770ec831bed03fd68e294c532010))
+* tweak decomposing recipe of bloomlight ([844b217](https://github.com/Elenterius/Biomancy/commit/844b21763b9dcc55673f87a79c20a45a3c572c81))
-### Code Refactoring
+### Bug Fixes
-* move menu package from inventory package into main package ([3b4796b](https://github.com/Elenterius/Biomancy/commit/3b4796b8d05d515117ce84f4ffccd476894160da))
+* prevent storage sac from being eaten by the Cradle ([d1e9c66](https://github.com/Elenterius/Biomancy/commit/d1e9c663a22917063e89459384582d468d16dad1))
-## [1.13.0](https://github.com/Elenterius/Biomancy/compare/1.19.2-v2.1.12.0...1.19.2-v2.1.13.0) (2023-07-29)
+## [2.7.0](https://github.com/Elenterius/Biomancy/compare/1.19.2-v2.2.6.0...1.19.2-v2.2.7.0) (2023-12-11)
### Features
-* enhance tooltip clarity and consistency ([bdbbcb9](https://github.com/Elenterius/Biomancy/commit/bdbbcb96bea8c5b7b8bbb1f2c9772be8ab98ab31))
-
-## [1.12.0](https://github.com/Elenterius/Biomancy/compare/1.19.2-v2.1.11.3...1.19.2-v2.1.12.0) (2023-07-18)
+* **acid:** add acid fluid ([61da539](https://github.com/Elenterius/Biomancy/commit/61da539e64936ad6d8020c95a4e408d67d60cd7c))
+* **acid:** add dripping acid particle ([dd32f9d](https://github.com/Elenterius/Biomancy/commit/dd32f9de834d39906799c357f77702a563a7c2a2))
+* **acid:** add fluid compat for open pipes from Create ([dc17391](https://github.com/Elenterius/Biomancy/commit/dc173912e85795326cc80b94c2fb209ae9314b20))
+* **acid:** add fluid interaction with lava & water ([050bf47](https://github.com/Elenterius/Biomancy/commit/050bf47bf08ab59297716c84f380f21cb57be3e7))
+* add primal orifice block ([02a2c84](https://github.com/Elenterius/Biomancy/commit/02a2c84e141bba509855cba92da8bebb30367b75))
+* change chiseled flesh block/texture ([be7e5d9](https://github.com/Elenterius/Biomancy/commit/be7e5d9273be27dd16849993419b1b580dea206e))
+* **flesh-mound:** make Malignant Bloom spawn less likely inside the mound and more likely at the edges or outside ([3acb916](https://github.com/Elenterius/Biomancy/commit/3acb91623456fb86f247a1dfb60857cc79d1976c))
+* **flesh-mound:** tweak default mound gen settings ([7f06b15](https://github.com/Elenterius/Biomancy/commit/7f06b15508f5c86aa85836a3ce391c88fba4084f))
-### Features
+### Bug Fixes
-* add attack reach indicator for the Ravenous Claws ([ccc850f](https://github.com/Elenterius/Biomancy/commit/ccc850fce7a7d08aa86a97676eb2068f9167009b))
-* add Spanish translation ([4c3c35b](https://github.com/Elenterius/Biomancy/commit/4c3c35ba18f09cf94b8c3a8581927ed809fada13))
-* add status effect version of Despoil for use by datapacks etc ([fe2ae46](https://github.com/Elenterius/Biomancy/commit/fe2ae46e524d0b862f5a7ccae769878436589259))
-* improve flesh spike tooltip ([4e4c042](https://github.com/Elenterius/Biomancy/commit/4e4c042654d80f0cc11dab20d3f18fbca87b6082))
-* make bio-machines retain their fuel when destroyed ([8ec768d](https://github.com/Elenterius/Biomancy/commit/8ec768dcf6a5e92717a9be2ac2d6336b8098bb2c))
-* make flesh block texture less repetitive (uses placeholder textures) ([20fb879](https://github.com/Elenterius/Biomancy/commit/20fb87945492eb2cef904b323487dd281bdb7ddc))
+* **flesh-mound:** fix flesh veins being unable to find the flesh mound when other types of shapes exist in the same area ([8750164](https://github.com/Elenterius/Biomancy/commit/8750164116ab17518679a615ed8b2e545ec79392))
+* **gradle:** fix build configuration not including the api sourceset in the primary build artifact ([95c32e7](https://github.com/Elenterius/Biomancy/commit/95c32e7f04836a4a0189b2b8321e4e4a9910dc67))
+## [2.6.0](https://github.com/Elenterius/Biomancy/compare/1.19.2-v2.2.5.0...1.19.2-v2.2.6.0) (2023-12-09)
-### Bug Fixes
-* fix full block slabs not dropping two slab blocks ([54bb038](https://github.com/Elenterius/Biomancy/commit/54bb038109267982d1b5594df40cbfe589f3de19))
-* fix inability to switch claw modes when holding down ctrl to sprint ([870a033](https://github.com/Elenterius/Biomancy/commit/870a03359169f68ef0d7cd20963b24182918e61f))
-* fix misleading fleshkin chest tooltip ([47b2758](https://github.com/Elenterius/Biomancy/commit/47b2758b5eee547d2bbe7d9eec01402f5ce38cf2))
+### Features
-### [1.11.3](https://github.com/Elenterius/Biomancy/compare/1.19.2-v2.1.11.2...1.19.2-v2.1.11.3) (2023-06-30)
+* add neural interceptor block ([4ecc094](https://github.com/Elenterius/Biomancy/commit/4ecc09448bedd3d2c3fcb9b7ba1f7a417d3991aa))
+* add primal membrane block for living mobs ([a0ea6e8](https://github.com/Elenterius/Biomancy/commit/a0ea6e87eb5a29014a5f9a24bedc7cc057615d81))
+* add undead-permeable membrane ([0902a3b](https://github.com/Elenterius/Biomancy/commit/0902a3b936ae782a4b43cc75591124c3c2a630f7))
+* **flesh-mound:** add bloomlight block as flesh type replacement of shroomlight in mounds ([bdfa12f](https://github.com/Elenterius/Biomancy/commit/bdfa12f363b72874f1009d1d8f3b80218f74e98a))
+* **flesh-mound:** allow flesh mounds to excavate chambers and convert the destroyed blocks into primal energy ([593f9c9](https://github.com/Elenterius/Biomancy/commit/593f9c92971a9e8fdb198aec97fbd8d02a4c0b03))
+* **flesh-mound:** create "Doors" between two adjacent chambers with Primal Membranes ([2680d0e](https://github.com/Elenterius/Biomancy/commit/2680d0ed802d75c0abb892627be786a64051e0cb))
+* **flesh-mound:** improve storage and lookup of mound shapes ([e127cf6](https://github.com/Elenterius/Biomancy/commit/e127cf622b0aac3eb1f892f3dcc02421e1386929))
+* **flesh-mound:** make mound shapes persist across unloaded chunks and store mound shape seed in primordial cradle block/item ([32c2efd](https://github.com/Elenterius/Biomancy/commit/32c2efd8a74fdea3e45cd67d231d27217ae2e042))
+* **flesh-mound:** prevent flesh veins from eating living flesh ([36b6e65](https://github.com/Elenterius/Biomancy/commit/36b6e65e96f8c0cc1eb2d973ba99dd16585b1481))
+* **flesh-mound:** prevent natural spawning of mobs inside flesh mounds ([0af5924](https://github.com/Elenterius/Biomancy/commit/0af592432e1ac3dc7f071ec3c3419242ce94328a))
### Bug Fixes
-* fix Ravenous Claws ability tooltips not using translation keys ([989ff50](https://github.com/Elenterius/Biomancy/commit/989ff50e67110b0037d145f3a804a5455124ae91))
+* **flesh-mound:** fix unintentional MoundShape removal when the Cradle BlockEntity is unloaded ([a5cb46b](https://github.com/Elenterius/Biomancy/commit/a5cb46b5f2a8112de9a240bf1b85b61ba02cb0db))
-### [1.11.2](https://github.com/Elenterius/Biomancy/compare/1.19.2-v2.1.11.1...1.19.2-v2.1.11.2) (2023-06-25)
+## [2.5.0](https://github.com/Elenterius/Biomancy/compare/1.19.2-v2.2.4.0...1.19.2-v2.2.5.0) (2023-11-19)
-### Bug Fixes
+### Features
-* add missing language key for missing blood charge ([478c585](https://github.com/Elenterius/Biomancy/commit/478c58549ac677f3f960c8bd95ee87ac06bcb69d))
-* fix Maw Hopper not inserting items on the correct block face ([db57423](https://github.com/Elenterius/Biomancy/commit/db57423c451de0caf7f7529cad2cffdf47e27762))
-* fix Ravenous Claws item name ([ea9f79c](https://github.com/Elenterius/Biomancy/commit/ea9f79ce56afbcb5896f8b90618ade0dee21270a))
-* fix Ravenous Claws recipe ([272071d](https://github.com/Elenterius/Biomancy/commit/272071db69a6f57bbc93c8d938e948ccaac06139))
-* fix wrong fleshkin chest recipe ([a6be325](https://github.com/Elenterius/Biomancy/commit/a6be3254b4d77deed47f8824bf735776f1b7701f))
-* make Ravenous Claws tooltip less confusing ([c8940a6](https://github.com/Elenterius/Biomancy/commit/c8940a62b88a10f59b7857dec73904fbeb5a6832))
-* make tooltip text for pressing the v key on living tools less confusing ([7c7160f](https://github.com/Elenterius/Biomancy/commit/7c7160fd8515a767ae027f75a8586a5e8b62007e))
+* add block tags to explicitly allow/disallow attachment of flesh veins to specific blocks ([77c1fee](https://github.com/Elenterius/Biomancy/commit/77c1feee17f736fe2a6768f24b210e072077aedd))
+* **flesh-mound:** add first iteration of the flesh mound growth to the primordial cradle ([8175714](https://github.com/Elenterius/Biomancy/commit/8175714e23668e19e0685edfa14e2b40f9fc22f8))
+* **flesh-mound:** decrease volume of growth ([e528ba8](https://github.com/Elenterius/Biomancy/commit/e528ba833adb903db90877fc5d93e1183a55e281))
diff --git a/README.md b/README.md
index e47d00c40..9e2011956 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ style.
* [Download]
* [Discord]
* [Wiki]
-* [Trello]
+* [Github Project]
## Tech Stack
@@ -73,7 +73,7 @@ the [Creative Commons Attribution-NonCommercial 4.0 International License](http:
### Maven
-Atm there is no dedicated maven, you can use https://www.cursemaven.com/ to include the mod as a dependency.
+Atm there is no dedicated maven, you can use [cursemaven](https://www.cursemaven.com/) or [Modrinth Maven](https://docs.modrinth.com/maven) to include the mod as a dependency.
### Contributing
@@ -84,7 +84,7 @@ request to join the dev team.
This will give you access to the private mod development channels and resources such as the biomancy design document and
concept board.
-You can track the development progress via our [Trello Board][Trello].
+You can track the development progress via our [Dev Board][Github Project].
This project uses **Conventional Commits Messages** (https://www.conventionalcommits.org/en/v1.0.0/) to automatically
genereate
@@ -96,7 +96,7 @@ If you need help feel free to [join our Discord][Discord].
## User Guide
The mod provides no ingame guide book but uses tooltip descriptions & flavor texts instead. If you need further information you can read the github [Wiki].
-Read the [Getting Started Guide](https://github.com/Elenterius/Biomancy/wiki/v2/Getting-Started) section if you don't know what to do at all.
+Read the [Getting Started Guide](https://github.com/Elenterius/Biomancy/wiki/Biomancy-2-Getting-Started) section if you don't know what to do at all.
### Recipes
To conveniently look up recipes ingame I recommend the use of the [JEI] mod.
@@ -104,8 +104,9 @@ To conveniently look up recipes ingame I recommend the use of the [JEI] mod.
[Download]: https://www.curseforge.com/minecraft/mc-mods/biomancy
[Discord]: https://discord.gg/424awTDdJJ
-[Wiki]: https://github.com/Elenterius/Biomancy/wiki/v2
-[Trello]: https://trello.com/b/GUKjOSAl
-[JitPack]: https://jitpack.io/#Elenterius/Biomancy
+
+[Wiki]: https://github.com/Elenterius/Biomancy/wiki/Biomancy-2
+
+[Github Project]: https://github.com/orgs/Creative-Chasm/projects/2/
[JEI]:https://www.curseforge.com/minecraft/mc-mods/jei
diff --git a/build.gradle b/build.gradle
index 7a097e3d4..a1e93e01f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,6 +6,8 @@ plugins {
id 'org.spongepowered.mixin' version '0.7-SNAPSHOT'
}
+jarJar.enable()
+
import groovy.json.JsonSlurper
import java.util.concurrent.TimeUnit
@@ -34,6 +36,7 @@ sourceSets {
main {
resources {
srcDir 'src/generated/resources' // Include resources generated by data generators
+ exclude '.cache/'
}
}
test {}
@@ -65,6 +68,10 @@ minecraft {
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
property 'forge.enabledGameTestNamespaces', 'biomancy'
+ // Hot-Swapping via JBR, includes schema changes
+ // Guide: https://forge.gemwire.uk/wiki/Hotswap#Applying_schema_changes
+ jvmArgs '-XX:+IgnoreUnrecognizedVMOptions', '-XX:+AllowEnhancedClassRedefinition'
+
mods {
biomancy {
source sourceSets.main
@@ -78,13 +85,6 @@ minecraft {
args '--username', 'Dev2'
}
- // Hot-Swapping via JBR, includes schema changes
- // Guide: https://forge.gemwire.uk/wiki/Hotswap#Applying_schema_changes
- clientWithJBR {
- parent runs.client
- jvmArg '-XX:+AllowEnhancedClassRedefinition'
- }
-
server {
workingDirectory project.file('run')
@@ -180,8 +180,10 @@ repositories {
maven { url = 'https://dl.cloudsmith.io/public/geckolib3/geckolib/maven/' }
maven { url = 'https://maven.blamejared.com' }
maven {
- name = "KliKli Maven (Modnomicon)"
- url = "https://repo.repsy.io/mvn/klikli-dev/mods"
+ url "https://dl.cloudsmith.io/public/klikli-dev/mods/maven/"
+ content {
+ includeGroup "com.klikli_dev"
+ }
}
maven {
name = 'tterrag maven'
@@ -206,8 +208,12 @@ dependencies {
implementation fg.deobf("software.bernie.geckolib:geckolib-forge-1.19:3.1.40")
datagenImplementation fg.deobf("software.bernie.geckolib:geckolib-forge-1.19:3.1.40")
- implementation fg.deobf("com.klikli_dev:modonomicon:1.19.2-1.30.2")
- datagenImplementation fg.deobf("com.klikli_dev:modonomicon:1.19.2-1.30.2")
+ //https://h2database.com/html/mvstore.html
+ minecraftLibrary(group: "com.h2database", name: "h2-mvstore", version: "2.2.224")
+ jarJar(group: "com.h2database", name: "h2-mvstore", version: "[2.2.220,3.0.0)")
+
+ implementation fg.deobf("com.klikli_dev:modonomicon-${mc_version}:1.34.0")
+ datagenImplementation fg.deobf("com.klikli_dev:modonomicon-${mc_version}:1.34.0")
compileOnly fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}")
compileOnly fg.deobf("mezz.jei:jei-${mc_version}-forge-api:${jei_version}") // compile against the JEI API but do not include it at runtime
@@ -230,6 +236,8 @@ dependencies {
// implementation fg.deobf("se.mickelus.mutil:mutil:1.19.2-5.1.0")
compileOnly fg.deobf("curse.maven:tetra-289712:4738567") // 1.19.2-5.5.0
+// runtimeOnly fg.deobf("maven.modrinth:nerb:ANmCMdMt") //NERB 0.3
+
//TODO: Morph Mod Integration?
// implementation fg.deobf("curse.maven:identity-391390:3807264") // https://www.curseforge.com/minecraft/mc-mods/identity
// runtimeOnly fg.deobf("curse.maven:architectury-419699:4040966")
@@ -240,7 +248,6 @@ dependencies {
}
processResources {
- exclude '.cache'
exclude '**/*.psd'
exclude '**/*.bbmodel'
exclude '**/*.pdn'
@@ -263,7 +270,14 @@ void minifyJsons(String fdir) {
printf "%7s sec, %s ms \n", (int) (ms / 1000), ms % 1000
}
+tasks.jarJar {
+ archiveClassifier = ''
+ from sourceSets.api.output
+ from { ["CREDITS.md", "LICENSE.txt"] } //copy files from the repository root into the jar
+}
+
jar {
+ archiveClassifier = "slim"
from sourceSets.api.output
// manifest properties for reading on runtime
@@ -281,10 +295,13 @@ jar {
from { ["CREDITS.md", "LICENSE.txt"] } //copy files from the repository root into the jar
}
-// This is the preferred method to reobfuscate your jar file
-jar.finalizedBy('reobfJar')
-// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
-//publish.dependsOn('reobfJar')
+reobf {
+ jarJar {}
+}
+
+//jar.finalizedBy('reobfJar')
+tasks.build.dependsOn tasks.jarJar
+jar.finalizedBy('reobfJarJar')
publishing {
publications {
diff --git a/mod_version.json b/mod_version.json
index 512051c82..d972fac93 100644
--- a/mod_version.json
+++ b/mod_version.json
@@ -1,4 +1,4 @@
{
"major": "2",
- "semantic": "2.0.0"
+ "semantic": "2.9.0"
}
\ No newline at end of file
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/DataGenerators.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/DataGenerators.java
index f1e5a09b1..96b86f0f8 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/DataGenerators.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/DataGenerators.java
@@ -60,7 +60,7 @@ public static void gatherData(final GatherDataEvent event) {
generator.addProvider(true, new ModAdvancementProvider(generator, existingFileHelper, translationProvider));
//guide book
- generator.addProvider(false, new GuideBookProvider(generator, translationProvider)); //TODO: re-enable when ready
+ generator.addProvider(true, new GuideBookProvider(generator, translationProvider)); //TODO: re-enable when ready
generator.addProvider(true, translationProvider);
}
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/ModSoundProvider.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/ModSoundProvider.java
index ddb527f83..41fcce36a 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/ModSoundProvider.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/ModSoundProvider.java
@@ -35,6 +35,12 @@ public void registerSounds() {
addSimpleSounds(ModSoundEvents.FLESH_BLOCK_BREAK, 4);
addSimpleSounds(ModSoundEvents.FLESH_BLOCK_FALL, 3);
+ addSimpleRedirects(ModSoundEvents.BONY_FLESH_BLOCK_HIT, ModSoundEvents.FLESH_BLOCK_HIT.get(), SoundEvents.BONE_BLOCK_HIT);
+ addSimpleRedirects(ModSoundEvents.BONY_FLESH_BLOCK_PLACE, ModSoundEvents.FLESH_BLOCK_PLACE.get(), SoundEvents.BONE_BLOCK_PLACE);
+ addSimpleRedirects(ModSoundEvents.BONY_FLESH_BLOCK_STEP, ModSoundEvents.FLESH_BLOCK_STEP.get(), SoundEvents.BONE_BLOCK_STEP);
+ addSimpleRedirects(ModSoundEvents.BONY_FLESH_BLOCK_BREAK, ModSoundEvents.FLESH_BLOCK_BREAK.get(), SoundEvents.BONE_BLOCK_BREAK);
+ addSimpleRedirects(ModSoundEvents.BONY_FLESH_BLOCK_FALL, ModSoundEvents.FLESH_BLOCK_FALL.get(), SoundEvents.BONE_BLOCK_FALL);
+
addSimpleSounds(ModSoundEvents.FLESH_DOOR_OPEN, 2);
addSimpleSounds(ModSoundEvents.FLESH_DOOR_CLOSE, 2);
@@ -82,7 +88,7 @@ public void registerSounds() {
addSimpleRedirect(ModSoundEvents.DIGESTER_CRAFTING_COMPLETED, SoundEvents.PLAYER_BURP, 1f, 1.25f);
addSimpleRedirect(ModSoundEvents.FLESH_BLOB_JUMP, SoundEvents.SLIME_JUMP);
- addSimpleRedirect(ModSoundEvents.FLESH_BLOB_HURT, ModSoundEvents.FLESH_BLOCK_BREAK.get(), 0.8f, 0.9f);
+ addSimpleRedirect(ModSoundEvents.FLESH_BLOB_HURT, ModSoundEvents.FLESH_BLOCK_BREAK, 0.8f, 0.9f);
addSimpleRedirect(ModSoundEvents.FLESH_BLOB_DEATH, SoundEvents.GENERIC_DEATH);
addSimpleSounds(ModSoundEvents.FLESH_BLOB_AMBIENT, 3, 0.8f, 0.9f);
addSimpleSound(ModSoundEvents.GENERIC_MEW_PURR, 0.7f, 0.45f);
@@ -169,4 +175,13 @@ protected void addSimpleRedirect(RegistryObject soundHolder, Registr
);
}
+ protected void addSimpleRedirects(RegistryObject soundHolder, SoundEvent... redirectTargets) {
+ SoundDefinition soundDefinition = definition().subtitle(translationKey(soundHolder));
+
+ for (SoundEvent redirectTarget : redirectTargets) {
+ soundDefinition.with().with(sound(redirectTarget.getLocation(), SoundDefinition.SoundType.EVENT));
+ }
+
+ add(soundHolder, soundDefinition);
+ }
}
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/advancements/AdvancementBuilder.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/advancements/AdvancementBuilder.java
index e597db322..605deef67 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/advancements/AdvancementBuilder.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/advancements/AdvancementBuilder.java
@@ -1,7 +1,7 @@
package com.github.elenterius.biomancy.datagen.advancements;
-import com.github.elenterius.biomancy.chat.ComponentUtil;
import com.github.elenterius.biomancy.datagen.lang.LangProvider;
+import com.github.elenterius.biomancy.util.ComponentUtil;
import net.minecraft.advancements.Advancement;
import net.minecraft.advancements.CriterionTriggerInstance;
import net.minecraft.advancements.FrameType;
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/lang/EnglishLangProvider.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/lang/EnglishLangProvider.java
index 9d3e8cf52..491dbf8e0 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/lang/EnglishLangProvider.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/lang/EnglishLangProvider.java
@@ -160,6 +160,7 @@ protected void addTranslations() {
addItemTranslations();
addBlockTranslations();
+ addFluidTranslations();
addEntityTranslations();
addEnchantmentTranslations();
addStatusEffectTranslations();
@@ -169,6 +170,7 @@ protected void addTranslations() {
addTooltip("empty", "Empty");
addTooltip("contains", "Contains: %1$s");
addTooltip("nutrients_fuel", "Nutrients");
+ addTooltip("primal_energy", "Primal Energy");
addTooltip("nutrients_consumes", "Consumes %1$s u");
addTooltip("consumption", "Consumption");
addTooltip("bile_fuel", "Bile");
@@ -252,6 +254,12 @@ private void addSoundTranslations() {
addSound(ModSoundEvents.FLESH_BLOCK_BREAK, "Break Fleshy Block");
addSound(ModSoundEvents.FLESH_BLOCK_FALL, "Fall on Fleshy Block");
+ addSound(ModSoundEvents.BONY_FLESH_BLOCK_HIT, "Hit Bony Flesh Block");
+ addSound(ModSoundEvents.BONY_FLESH_BLOCK_PLACE, "Place Bony Flesh Block");
+ addSound(ModSoundEvents.BONY_FLESH_BLOCK_STEP, "Step on Bony Flesh Block");
+ addSound(ModSoundEvents.BONY_FLESH_BLOCK_BREAK, "Break Bony Flesh Block");
+ addSound(ModSoundEvents.BONY_FLESH_BLOCK_FALL, "Fall on Bony Flesh Block");
+
addSound(ModSoundEvents.FLESH_DOOR_OPEN, "Open Fleshy Door");
addSound(ModSoundEvents.FLESH_DOOR_CLOSE, "Close Fleshy Door");
@@ -361,6 +369,7 @@ private void addItemTranslations() {
addItem(ModItems.NUTRIENTS, "Nutrients", "Very hard pellets rich in energy that almost look like vitamin pills.");
addItem(ModItems.NUTRIENT_PASTE, "Nutrient Paste", "Nutrients combined with Biotic Matter to moisten the hard pellets, producing a paste.\nIt almost looks like yellowish cake, and is a convenient source of energy.");
addItem(ModItems.NUTRIENT_BAR, "Nutrient Bar", "Nutrient Paste compressed into the shape of a bar. Looks edible, if a bit bland.");
+ addItem(ModItems.BLOOMBERRY, "Bloomberry", "An exotic delicacy which has a bioluminescent sheen and grants random potion effects when eaten.");
addItem(ModItems.REGENERATIVE_FLUID, "Regenerative Fluid", "A fluid with regenerative properties, used to concoct healing additives.");
addItem(ModItems.WITHERING_OOZE, "Withering Ooze", "A corrosive extract. It likely has uses in bio-alchemy.");
@@ -388,6 +397,7 @@ private void addItemTranslations() {
Looks like some objects are wrapped in an organic layer of skin. Might be filled with items or toxin if your language is set to German.
Right Click the Sac to retrieve the Items.""");
+ addItem(ModItems.ACID_BUCKET, "Acid Bucket");
addItem(ModItems.RAVENOUS_CLAWS, "Ravenous Claws", """
Extremely hungry and vicious Claws forged by starving living flesh and grafting claws onto it.
@@ -480,12 +490,16 @@ private void addBlockTranslations() {
addBlock(ModBlocks.FLESH_LADDER, "Flesh Ladder", "Ladder mainly made of bones and a little bit of flesh...");
addBlock(ModBlocks.YELLOW_BIO_LANTERN, "Yellow Bio-Lantern", "A bioluminescent light source that is energy-efficient and environmentally friendly.");
addBlock(ModBlocks.BLUE_BIO_LANTERN, "Blue Bio-Lantern", "A bioluminescent light source. This one is blue!");
- addBlock(ModBlocks.PRIMORDIAL_BIO_LANTERN, "Primordial Bio-Lantern", "A primal light source. This one is magenta!");
+ addBlock(ModBlocks.PRIMORDIAL_BIO_LANTERN, "Bloom-Lantern", "A magenta light source made from a bioluminescent berry.");
+ addBlock(ModBlocks.BLOOMLIGHT, "Bloomlight", "A malignant light source. This one is magenta as well!");
addBlock(ModBlocks.TENDON_CHAIN, "Tendon Chain", "A chain made of tendons.");
addBlock(ModBlocks.VIAL_HOLDER, "Vial Holder", "Display and organize your serums.");
addBlock(ModBlocks.IMPERMEABLE_MEMBRANE, "Impermeable Membrane", "Gelatinous-like membrane reinforced with elastic fibers.");
addBlock(ModBlocks.BABY_PERMEABLE_MEMBRANE, "Baby-Permeable Membrane", "Gelatinous-like membrane reinforced with elastic fibers.\n\nBaby mobs can diffuse through the membrane.");
addBlock(ModBlocks.ADULT_PERMEABLE_MEMBRANE, "Adult-Permeable Membrane", "Gelatinous-like membrane reinforced with elastic fibers.\n\nAdult mobs can diffuse through the membrane.");
+ addBlock(ModBlocks.PRIMAL_PERMEABLE_MEMBRANE, "Primal Membrane", "Gelatinous-like membrane reinforced with elastic fibers.\n\nOnly mobs that are alive can diffuse through the membrane.");
+ addBlock(ModBlocks.UNDEAD_PERMEABLE_MEMBRANE, "Phantom Membrane", "Gelatinous-like membrane reinforced with elastic fibers.\n\nOnly mobs that are undead can diffuse through the membrane.");
+ //addBlock(ModBlocks.NEURAL_INTERCEPTOR, "Neural Interceptor", "A psychic node that prevents natural mob spawning in a 48 block radius.");
addBlock(ModBlocks.PRIMAL_FLESH, "Primal Flesh Block", "Primitive and pure, you better not touch this with your dirty mitts.");
addBlock(ModBlocks.PRIMAL_FLESH_SLAB, "Primal Flesh Slab", "Primitive and pure, you better not touch this with your dirty mitts.");
@@ -496,6 +510,10 @@ private void addBlockTranslations() {
addBlock(ModBlocks.MALIGNANT_FLESH_STAIRS, "Malignant Flesh Stairs", "Stairs made of malignant flesh.\nLooks diseased...");
addBlock(ModBlocks.MALIGNANT_FLESH_WALL, "Malignant Flesh Wall", "Wall of malignant flesh.\nIt's coming for you! ;)");
addBlock(ModBlocks.MALIGNANT_FLESH_VEINS, "Malignant Flesh Veins", "They look almost feral...\nyou better not touch them.");
+ addBlock(ModBlocks.MALIGNANT_BLOOM, "Primal Bloom", "An exotic flower of primordial beauty.\n\nIt will spread itself by launching it's ripe berry into the air.\nOn impact the berry explodes and spreads malignant veins as well.");
+ addBlock(ModBlocks.PRIMAL_ORIFICE, "Primal Orifice", "A primitive piece full of holes. It seems to leak an acidic substance.");
+
+ addBlock(ModBlocks.ACID_FLUID_BLOCK, "Acid");
}
private void addEntityTranslations() {
@@ -506,4 +524,7 @@ private void addEntityTranslations() {
addEntityType(ModEntityTypes.PRIMORDIAL_HUNGRY_FLESH_BLOB, "Primordial Hungry Flesh Blob");
}
+ private void addFluidTranslations() {
+ addFluidType(ModFluids.ACID_TYPE, "Acid");
+ }
}
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/loot/ModBlockLoot.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/loot/ModBlockLoot.java
index eed42ff6e..3ddd54b16 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/loot/ModBlockLoot.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/loot/ModBlockLoot.java
@@ -57,6 +57,15 @@ protected static LootTable.Builder createNameableBioMachineTable(Block block) {
)));
}
+ protected static LootTable.Builder createPrimordialCradleTable(Block block) {
+ return LootTable.lootTable().withPool(applyExplosionCondition(block, LootPool.lootPool().setRolls(ConstantValue.exactly(1))
+ .add(LootItem.lootTableItem(block)
+ .apply(CopyNbtFunction.copyData(ContextNbtProvider.BLOCK_ENTITY).copy("PrimalEnergy", "BlockEntityTag.PrimalEnergy"))
+ .apply(CopyNbtFunction.copyData(ContextNbtProvider.BLOCK_ENTITY).copy("ProcGenValues", "BlockEntityTag.ProcGenValues"))
+ .apply(CopyNbtFunction.copyData(ContextNbtProvider.BLOCK_ENTITY).copy("SacrificeHandler", "BlockEntityTag.SacrificeHandler"))
+ )));
+ }
+
protected static LootTable.Builder dropWithInventory(Block block) {
return LootTable.lootTable().withPool(applyExplosionCondition(block, LootPool.lootPool().setRolls(ConstantValue.exactly(1))
.add(LootItem.lootTableItem(block)
@@ -104,9 +113,9 @@ protected static LootTable.Builder createFleshSpikeTable(FleshSpikeBlock block)
return LootTable.lootTable().withPool(LootPool.lootPool()
.setRolls(ConstantValue.exactly(1))
.add(applyExplosionDecay(block, LootItem.lootTableItem(block).apply(
- IntStream.range(FleshSpikeBlock.MIN_SPIKES + 1, FleshSpikeBlock.MAX_SPIKES + 1).boxed().toList(),
+ IntStream.range(FleshSpikeBlock.SPIKES.getMin() + 1, FleshSpikeBlock.SPIKES.getMax() + 1).boxed().toList(),
spikes -> SetItemCountFunction.setCount(ConstantValue.exactly(spikes))
- .when(LootItemBlockStatePropertyCondition.hasBlockStateProperties(block).setProperties(StatePropertiesPredicate.Builder.properties().hasProperty(FleshSpikeBlock.SPIKES, spikes)))
+ .when(LootItemBlockStatePropertyCondition.hasBlockStateProperties(block).setProperties(StatePropertiesPredicate.Builder.properties().hasProperty(FleshSpikeBlock.SPIKES.get(), spikes)))
))));
}
@@ -114,7 +123,7 @@ protected static LootTable.Builder createFleshSpikeTable(FleshSpikeBlock block)
protected void addTables() {
LOGGER.info(logMarker, "registering block loot...");
- dropSelf(ModBlocks.PRIMORDIAL_CRADLE.get());
+ add(ModBlocks.PRIMORDIAL_CRADLE.get(), ModBlockLoot::createPrimordialCradleTable);
dropSelf(ModBlocks.TONGUE.get());
dropSelf(ModBlocks.MAW_HOPPER.get());
add(ModBlocks.STORAGE_SAC.get(), ModBlockLoot::dropWithInventory);
@@ -155,17 +164,24 @@ protected void addTables() {
dropSelf(ModBlocks.MALIGNANT_FLESH_STAIRS.get());
dropSelf(ModBlocks.MALIGNANT_FLESH_WALL.get());
add(ModBlocks.MALIGNANT_FLESH_VEINS.get(), block -> createMultifaceBlockDrops(block, HAS_SHEARS_OR_SILK_TOUCH));
+ add(ModBlocks.MALIGNANT_BLOOM.get(), noDrop());
+ dropSelf(ModBlocks.PRIMAL_ORIFICE.get());
dropSelf(ModBlocks.VOICE_BOX.get());
dropSelf(ModBlocks.IMPERMEABLE_MEMBRANE.get());
dropSelf(ModBlocks.BABY_PERMEABLE_MEMBRANE.get());
dropSelf(ModBlocks.ADULT_PERMEABLE_MEMBRANE.get());
+ dropSelf(ModBlocks.PRIMAL_PERMEABLE_MEMBRANE.get());
+ dropSelf(ModBlocks.UNDEAD_PERMEABLE_MEMBRANE.get());
+ //dropSelf(ModBlocks.NEURAL_INTERCEPTOR.get());
+
dropSelf(ModBlocks.FLESH_IRIS_DOOR.get());
dropSelf(ModBlocks.FLESH_FENCE.get());
dropSelf(ModBlocks.FLESH_FENCE_GATE.get());
dropSelf(ModBlocks.FLESH_LADDER.get());
dropSelf(ModBlocks.YELLOW_BIO_LANTERN.get());
dropSelf(ModBlocks.PRIMORDIAL_BIO_LANTERN.get());
+ dropSelf(ModBlocks.BLOOMLIGHT.get());
dropSelf(ModBlocks.BLUE_BIO_LANTERN.get());
dropSelf(ModBlocks.TENDON_CHAIN.get());
dropSelf(ModBlocks.VIAL_HOLDER.get());
@@ -174,6 +190,8 @@ protected void addTables() {
addCustom(ModBlocks.FULL_FLESH_DOOR.get(), ModBlockLoot::createFleshDoorTable);
addCustom(ModBlocks.FLESH_SPIKE.get(), ModBlockLoot::createFleshSpikeTable);
+
+ add(ModBlocks.ACID_FLUID_BLOCK.get(), noDrop());
}
protected void addCustom(T block, Function function) {
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/models/ModBlockStateProvider.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/models/ModBlockStateProvider.java
index 86538541b..aae49d7e2 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/models/ModBlockStateProvider.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/models/ModBlockStateProvider.java
@@ -3,6 +3,8 @@
import com.github.elenterius.biomancy.BiomancyMod;
import com.github.elenterius.biomancy.block.*;
import com.github.elenterius.biomancy.block.fleshspike.FleshSpikeBlock;
+import com.github.elenterius.biomancy.block.malignantbloom.MalignantBloomBlock;
+import com.github.elenterius.biomancy.block.orifice.OrificeBlock;
import com.github.elenterius.biomancy.block.ownable.OwnablePressurePlateBlock;
import com.github.elenterius.biomancy.block.property.DirectionalSlabType;
import com.github.elenterius.biomancy.block.property.Orientation;
@@ -75,7 +77,7 @@ protected void registerStatesAndModels() {
axisBlockWithItem(ModBlocks.FLESH_PILLAR);
simpleBlockWithItem(ModBlocks.FIBROUS_FLESH);
- simpleBlockWithItem(ModBlocks.CHISELED_FLESH);
+ existingBlockWithItem(ModBlocks.CHISELED_FLESH);
axisBlockWithItem(ModBlocks.ORNATE_FLESH);
axisBlockWithItem(ModBlocks.TUBULAR_FLESH_BLOCK);
@@ -89,6 +91,8 @@ protected void registerStatesAndModels() {
stairsBlockWithItem(ModBlocks.MALIGNANT_FLESH_STAIRS, ModBlocks.MALIGNANT_FLESH);
wallBlock(ModBlocks.MALIGNANT_FLESH_WALL, ModBlocks.MALIGNANT_FLESH);
veinsBlock(ModBlocks.MALIGNANT_FLESH_VEINS);
+ malignantBloom(ModBlocks.MALIGNANT_BLOOM);
+ orifice(ModBlocks.PRIMAL_ORIFICE);
irisDoor(ModBlocks.FLESH_IRIS_DOOR, true);
fleshDoor(ModBlocks.FLESH_DOOR);
@@ -96,9 +100,15 @@ protected void registerStatesAndModels() {
translucentBlockWithItem(ModBlocks.IMPERMEABLE_MEMBRANE);
membraneWithItem(ModBlocks.BABY_PERMEABLE_MEMBRANE);
membraneWithItem(ModBlocks.ADULT_PERMEABLE_MEMBRANE);
+ membraneWithItem(ModBlocks.PRIMAL_PERMEABLE_MEMBRANE);
+ membraneWithItem(ModBlocks.UNDEAD_PERMEABLE_MEMBRANE);
+
+ //horizontalBlockWithItem(ModBlocks.NEURAL_INTERCEPTOR);
+
bioLantern(ModBlocks.YELLOW_BIO_LANTERN);
bioLantern(ModBlocks.BLUE_BIO_LANTERN);
bioLantern(ModBlocks.PRIMORDIAL_BIO_LANTERN);
+ simpleBlockWithItem(ModBlocks.BLOOMLIGHT);
tendonChain(ModBlocks.TENDON_CHAIN);
vialHolder(ModBlocks.VIAL_HOLDER);
@@ -283,6 +293,16 @@ public void existingBlockWithItem(Block block) {
simpleBlockItem(block, existingModel);
}
+ public void horizontalBlockWithItem(RegistryObject block) {
+ horizontalBlockWithItem(block.get());
+ }
+
+ public void horizontalBlockWithItem(Block block) {
+ ModelFile.ExistingModelFile existingModel = models().getExistingFile(blockAsset(block));
+ horizontalBlock(block, blockState -> existingModel);
+ simpleBlockItem(block, existingModel);
+ }
+
public void directionalBlockWithItem(Block block) {
ModelFile.ExistingModelFile existingModel = models().getExistingFile(blockAsset(block));
directionalBlock(block, blockState -> existingModel, BlockStateProperties.WATERLOGGED);
@@ -309,6 +329,53 @@ public void directionalBlock(Block block, Function modelF
}, ignored);
}
+ public void orifice(RegistryObject block) {
+ orifice(block.get());
+ }
+
+ public void orifice(OrificeBlock block) {
+ ResourceLocation model = blockAsset(block);
+
+ ModelFile.ExistingModelFile defaultModel = models().getExistingFile(model);
+ ModelFile.ExistingModelFile leakingModel = models().getExistingFile(extend(model, "_leaking"));
+
+ ModelFile.ExistingModelFile[] models = {
+ defaultModel,
+ defaultModel,
+ leakingModel
+ };
+
+ getVariantBuilder(block)
+ .forAllStatesExcept(blockState -> {
+ Integer age = OrificeBlock.AGE.getValue(blockState);
+ return ConfiguredModel.builder()
+ .modelFile(models[age])
+ .build();
+ });
+
+ simpleBlockItem(block, models[0]);
+ }
+
+ public void malignantBloom(RegistryObject block) {
+ malignantBloom(block.get());
+ }
+
+ public void malignantBloom(MalignantBloomBlock block) {
+ ResourceLocation model = blockAsset(block);
+
+ ModelFile.ExistingModelFile[] models = {
+ models().getExistingFile(extend(model, "_1")),
+ models().getExistingFile(extend(model, "_2")),
+ models().getExistingFile(extend(model, "_3")),
+ models().getExistingFile(extend(model, "_4")),
+ models().getExistingFile(extend(model, "_5"))
+ };
+
+ directionalBlock(block, blockState -> models[MalignantBloomBlock.getStage(blockState)], BlockStateProperties.WATERLOGGED);
+
+ simpleBlockItem(block, models[0]);
+ }
+
public void fleshSpikes(Block block) {
ResourceLocation model = blockAsset(block);
ModelFile.ExistingModelFile[] models = {
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/models/ModItemModelProvider.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/models/ModItemModelProvider.java
index cd4511e5d..511b90e53 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/models/ModItemModelProvider.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/models/ModItemModelProvider.java
@@ -86,6 +86,7 @@ protected void registerModels() {
basicItem(ModItems.CREATOR_MIX);
basicItem(ModItems.NUTRIENT_PASTE);
basicItem(ModItems.NUTRIENT_BAR);
+ basicItem(ModItems.BLOOMBERRY);
serumItem(ModItems.VIAL);
basicItem(ModItems.GIFT_SAC);
basicItem(ModItems.FERTILIZER);
@@ -102,6 +103,8 @@ protected void registerModels() {
flatBlockItem(ModItems.FLESH_LADDER);
flatBlockItem(ModItems.MALIGNANT_FLESH_VEINS);
+ dynamicBucket(ModItems.ACID_BUCKET.get());
+
//generate models for all eggs
ModItems.ITEMS.getEntries().stream().map(RegistryObject::get).filter(SpawnEggItem.class::isInstance).forEach(this::spawnEggItem);
}
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/modonomicon/GuideBookProvider.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/modonomicon/GuideBookProvider.java
index d1ac2d92d..d5e3c87e5 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/modonomicon/GuideBookProvider.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/modonomicon/GuideBookProvider.java
@@ -12,11 +12,15 @@
import com.klikli_dev.modonomicon.api.datagen.book.BookEntryModel;
import com.klikli_dev.modonomicon.api.datagen.book.BookEntryParentModel;
import com.klikli_dev.modonomicon.api.datagen.book.BookModel;
-import com.klikli_dev.modonomicon.api.datagen.book.page.*;
+import com.klikli_dev.modonomicon.api.datagen.book.page.BookCraftingRecipePageModel;
+import com.klikli_dev.modonomicon.api.datagen.book.page.BookEntityPageModel;
+import com.klikli_dev.modonomicon.api.datagen.book.page.BookSpotlightPageModel;
+import com.klikli_dev.modonomicon.api.datagen.book.page.BookTextPageModel;
import net.minecraft.data.DataGenerator;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.Ingredient;
+import net.minecraft.world.phys.Vec2;
public class GuideBookProvider extends AbstractBookProvider {
@@ -30,217 +34,222 @@ private ResourceLocation entryId(BookLangHelper helper) {
@Override
protected void generate() {
+ BookLangHelper langHelper = ModonomiconAPI.get().getLangHelper(modId);
- BookLangHelper helper = ModonomiconAPI.get().getLangHelper(modId);
- helper.book("guide_book");
+ langHelper.book("guide_book");
+ BookModel book = BookModel.create(GuideBookItem.GUIDE_BOOK_ID, langHelper.bookName())
+ .withTooltip(langHelper.bookTooltip())
+ .withCustomBookItem(ModItems.GUIDE_BOOK.getId()).withGenerateBookItem(false)
+ .withCraftingTexture(BiomancyMod.createRL("textures/gui/modonomicon/crafting_textures.png"))
+ .withBookContentTexture(BiomancyMod.createRL("textures/gui/modonomicon/book_content.png"))
+ .withBookOverviewTexture(BiomancyMod.createRL("textures/gui/modonomicon/book_overview.png"));
- BookCategoryModel featuresCategory = makeFeaturesCategory(helper);
+ lang.add(book.getName(), "Biomancy Index");
+ lang.add(book.getTooltip(), "A book to test Modonomicon features for Biomancy.");
- BookModel demoBook = BookModel.create(GuideBookItem.GUIDE_BOOK_ID, helper.bookName())
- .withTooltip(helper.bookTooltip())
- .withCustomBookItem(ModItems.GUIDE_BOOK.getId()).withGenerateBookItem(false)
- .withCategories(featuresCategory);
+ BookCategoryModel featuresCategory = makeFeaturesCategory(langHelper);
- lang.add(demoBook.getName(), "[PH] Biomancy Index");
- lang.add(demoBook.getTooltip(), "[PH] A book to test Modonomicon features for Biomancy.");
+ book.withCategories(featuresCategory);
- add(demoBook);
+ add(book);
}
- private BookCategoryModel makeFeaturesCategory(BookLangHelper helper) {
- helper.category("features");
+ private BookCategoryModel makeFeaturesCategory(BookLangHelper langHelper) {
+ langHelper.category("features");
- EntryLocationHelper entryHelper = ModonomiconAPI.get().getEntryLocationHelper();
- entryHelper.setMap(
+ EntryLocationHelper locationHelper = ModonomiconAPI.get().getEntryLocationHelper();
+ locationHelper.setMap(
+ "_____________________",
+ "__________e_d________",
"_____________________",
- "__m______________d___",
- "__________r__________",
- "__c__________________",
- "__________2___3___i__",
- "__s_____e____________"
+ "__c_______p__________",
+ "__s__________________",
+ "_____________________"
);
- var multiBlockEntry = makeMultiBlockEntry(helper, entryHelper, 'm');
+ BookEntryModel primordialCradleRecipe = makeCradleEntry(langHelper, locationHelper.get('p')).build();
- var recipeEntry = makeRecipeEntry(helper, entryHelper, 'c');
+ BookEntryModel spotlightTestEntry = makeSpotlightTestEntry(langHelper, locationHelper.get('s')).build();
- var spotlightEntry = makeSpotlightEntry(helper, entryHelper, 's')
- .withParent(BookEntryParentModel.builder().withEntryId(recipeEntry.getId()).build())
+ BookEntryModel fleshBlobEntry = makeFleshBlobEntry(langHelper, locationHelper.get('e'))
+ .withParent(BookEntryParentModel.builder().withEntryId(primordialCradleRecipe.getId()).build())
.build();
- var entityEntry = makeEntityEntry(helper, entryHelper, 'd');
-
- BookCategoryModel categoryModel = BookCategoryModel.create(modLoc(helper.category), helper.categoryName())
- .withIcon("minecraft:nether_star") //the icon for the category. In this case we simply use an existing item.
- .withEntries(multiBlockEntry)
- .withEntries(recipeEntry)
- .withEntries(spotlightEntry)
- .withEntries(entityEntry);
- lang.add(helper.categoryName(), "[PH] Features Category");
-
- return categoryModel;
- }
-
- private BookEntryModel makeRecipeEntry(BookLangHelper helper, EntryLocationHelper entryHelper, char location) {
- helper.entry("recipe");
-
- helper.page("intro");
- var introPage = BookTextPageModel.builder()
- .withText(helper.pageText())
- .withTitle(helper.pageTitle())
+ BookEntryModel decomposerEntry = makeDecomposerEntry(langHelper, locationHelper.get('d'))
+ .withParent(BookEntryParentModel.builder().withEntryId(fleshBlobEntry.getId()).build())
.build();
- lang.add(helper.pageTitle(), "[PH] Recipe Entry");
- lang.add(helper.pageText(), "[PH] Recipe pages allow to show recipes in the book.");
-
- helper.page("crafting");
- var crafting = BookCraftingRecipePageModel.builder()
- .withRecipeId1("minecraft:crafting_table")
- .withRecipeId2("minecraft:oak_planks")
- .withText(helper.pageText())
- .withTitle2("test.test.test")
- .build();
- lang.add(helper.pageText(), "[PH] A sample recipe page.");
- lang.add("test.test.test", "[PH] Book of Binding: Afrit (Bound)");
+ BookCategoryModel category = BookCategoryModel.create(modLoc(langHelper.category), langHelper.categoryName())
+ .withIcon(ModItems.LIVING_FLESH.get())
+ .withEntryTextures(BiomancyMod.createRL("textures/gui/modonomicon/entry_textures.png"))
+ .withBackground(BiomancyMod.createRL("textures/gui/modonomicon/main_background.png"))
+ .withEntries(primordialCradleRecipe, decomposerEntry, fleshBlobEntry)
+ .withEntries(spotlightTestEntry);
+ lang.add(langHelper.categoryName(), "Fleshy Constructs");
- helper.page("smelting");
- var smelting = BookSmeltingRecipePageModel.builder()
- .withRecipeId1("minecraft:charcoal")
- .withRecipeId2("minecraft:cooked_beef")
- .build();
- lang.add(helper.pageText(), "[PH] A smelting recipe page with one recipe and some text.");
-
- helper.page("blasting");
- var blasting = BookBlastingRecipePageModel.builder()
- .withRecipeId2("biomancy:glass_pane_from_blasting")
- .build();
-
- BookEntryModel entryModel = BookEntryModel.builder()
- .withId(entryId(helper))
- .withName(helper.entryName())
- .withDescription(helper.entryDescription())
- .withIcon("minecraft:crafting_table")
- .withLocation(entryHelper.get('c'))
- .withPages(introPage, crafting, smelting, blasting)
- .build();
- lang.add(helper.entryName(), "[PH] Recipe Entry");
- lang.add(helper.entryDescription(), "[PH] An entry showcasing recipe pages.");
-
- return entryModel;
+ return category;
}
- private BookEntryModel.Builder makeSpotlightEntry(BookLangHelper helper, EntryLocationHelper entryHelper, char location) {
- helper.entry("spotlight");
+ private BookEntryModel.Builder makeSpotlightTestEntry(BookLangHelper langHelper, Vec2 location) {
+ langHelper.entry("spotlight");
- helper.page("intro");
+ langHelper.page("intro");
var introPage = BookTextPageModel.builder()
- .withText(helper.pageText())
- .withTitle(helper.pageTitle())
+ .withText(langHelper.pageText())
+ .withTitle(langHelper.pageTitle())
.build();
- lang.add(helper.pageTitle(), "[PH] Spotlight Entry");
- lang.add(helper.pageText(), "[PH] Spotlight pages allow to show items (actually, ingredients).");
+ lang.add(langHelper.pageTitle(), "[PH] Spotlight Entry");
+ lang.add(langHelper.pageText(), "[PH] Spotlight pages allow to show items (actually, ingredients).");
- helper.page("spotlight1");
+ langHelper.page("spotlight1");
var spotlight1 = BookSpotlightPageModel.builder()
- .withTitle(helper.pageTitle())
- .withText(helper.pageText())
+ .withTitle(langHelper.pageTitle())
+ .withText(langHelper.pageText())
.withItem(Ingredient.of(Items.APPLE))
.build();
- lang.add(helper.pageTitle(), "[PH] Custom Title");
- lang.add(helper.pageText(), "[PH] A sample spotlight page with custom title.");
+ lang.add(langHelper.pageTitle(), "[PH] Custom Title");
+ lang.add(langHelper.pageText(), "[PH] A sample spotlight page with custom title.");
- helper.page("spotlight2");
+ langHelper.page("spotlight2");
var spotlight2 = BookSpotlightPageModel.builder()
- .withText(helper.pageText())
+ .withText(langHelper.pageText())
.withItem(Ingredient.of(Items.DIAMOND))
.build();
- lang.add(helper.pageText(), "[PH] A sample spotlight page with automatic title.");
-
- BookEntryModel.Builder builder = BookEntryModel.builder()
- .withId(entryId(helper))
- .withName(helper.entryName())
- .withDescription(helper.entryDescription())
- .withIcon("minecraft:beacon")
- .withLocation(entryHelper.get(location))
+ lang.add(langHelper.pageText(), "[PH] A sample spotlight page with automatic title.");
+
+ var builder = BookEntryModel.builder()
+ .withId(entryId(langHelper))
+ .withName(langHelper.entryName())
+ .withDescription(langHelper.entryDescription())
+ .withIcon(Items.BEACON)
+ .withLocation(location)
.withPages(introPage, spotlight1, spotlight2);
- lang.add(helper.entryName(), "[PH] Spotlight Entry");
- lang.add(helper.entryDescription(), "[PH] An entry showcasing spotlight pages.");
+
+ lang.add(langHelper.entryName(), "[PH] Spotlight Entry");
+ lang.add(langHelper.entryDescription(), "[PH] An entry showcasing spotlight pages.");
+
return builder;
}
- private BookEntryModel makeEntityEntry(BookLangHelper helper, EntryLocationHelper entryHelper, char location) {
- helper.entry("entity");
+ private BookEntryModel.Builder makeFleshBlobEntry(BookLangHelper langHelper, Vec2 location) {
+ langHelper.entry("mob");
- helper.page("intro");
- BookTextPageModel introPage = BookTextPageModel.builder()
- .withText(helper.pageText())
- .withTitle(helper.pageTitle())
+ langHelper.page("living_flesh_spotlight");
+ var livingFleshSpotlight = BookSpotlightPageModel.builder()
+ .withText(langHelper.pageText())
+ .withItem(Ingredient.of(ModItems.LIVING_FLESH.get()))
.build();
- lang.add(helper.pageTitle(), "[PH] Entity Entry");
- lang.add(helper.pageText(), "[PH] Entity pages allow to show entities.");
+ lang.add(langHelper.pageText(), """
+ Living Flesh is the remains of a Flesh Blob after is has been killed.
+ \\
+ It's most definitely alive, although it lacks any real intelligence or selfish will.
+ \\
+ ++That isn't necessarily a bad thing though...++""");
- helper.page("flesh_blob");
+ langHelper.page("flesh_blob");
BookEntityPageModel fleshBlobPage = BookEntityPageModel.builder()
- .withEntityName(helper.pageTitle())
.withEntityId(ModEntityTypes.FLESH_BLOB.getId().toString())
.withScale(1f)
.build();
- lang.add(helper.pageTitle(), "[PH] Flesh Blob");
- helper.page("hungry_flesh_blob");
+ langHelper.page("flesh_blob_page");
+ BookTextPageModel fleshBlobText = BookTextPageModel.builder()
+ .withText(langHelper.pageText())
+ .build();
+ lang.add(langHelper.pageText(), """
+ A regular Flesh Blob is formed with just typical raw meat and healing agents.
+ \\
+ Has no redeeming qualities, but makes for a good house pet.""");
+ langHelper.page("hungry_flesh_blob");
BookEntityPageModel hungryFleshBlobPage = BookEntityPageModel.builder()
- .withText(helper.pageText())
.withEntityId(ModEntityTypes.HUNGRY_FLESH_BLOB.getId().toString())
.withScale(1f)
.build();
- lang.add(helper.pageText(), "[PH] A sample entity page with automatic title.");
-
- BookEntryModel entryModel = BookEntryModel.builder()
- .withId(entryId(helper))
- .withName(helper.entryName())
- .withDescription(helper.entryDescription())
- .withIcon("minecraft:spider_eye")
- .withLocation(entryHelper.get(location))
- .withPages(introPage, fleshBlobPage, hungryFleshBlobPage)
- .build();
- lang.add(helper.entryName(), "[PH] Entity Entry");
- lang.add(helper.entryDescription(), "[PH] An entry showcasing entity pages.");
- return entryModel;
+ langHelper.page("hungry_flesh_blob_text");
+ BookTextPageModel hungryFleshBlobText = BookTextPageModel.builder()
+ .withText(langHelper.pageText())
+ .build();
+ lang.add(langHelper.pageText(), """
+ A Hungry Flesh Blob is formed by adding a few Sharp Fangs into the cradle with some raw meat and a healing agent.
+ \\
+ Maybe don't try petting this one...""");
+
+ var builder = BookEntryModel.builder()
+ .withId(entryId(langHelper))
+ .withName(langHelper.entryName())
+ .withDescription(langHelper.entryDescription())
+ .withIcon(ModItems.LIVING_FLESH.get())
+ .withLocation(location)
+ .withPages(
+ fleshBlobPage, fleshBlobText,
+ hungryFleshBlobPage, hungryFleshBlobText,
+ livingFleshSpotlight
+ );
+ lang.add(langHelper.entryName(), "Flesh Blobs");
+ lang.add(langHelper.entryDescription(), "Bouncy lil guys");
+
+ return builder;
}
- private BookEntryModel makeMultiBlockEntry(BookLangHelper helper, EntryLocationHelper entryHelper, char location) {
- helper.entry("multiblock");
+ private BookEntryModel.Builder makeDecomposerEntry(BookLangHelper langHelper, Vec2 location) {
+ langHelper.entry("decomposer");
- helper.page("intro");
- var introPage = BookTextPageModel.builder()
- .withText(helper.pageText())
- .withTitle(helper.pageTitle())
+ langHelper.page("spotlight");
+ var introPage = BookSpotlightPageModel.builder()
+ .withText(langHelper.pageText())
+ .withItem(Ingredient.of(ModItems.DECOMPOSER.get()))
.build();
- lang.add(helper.pageTitle(), "[PH] Multi-block Page");
- lang.add(helper.pageText(), "[PH] Multi-block pages allow to preview multi-blocks both in the book and in the world.");
-
- helper.page("preview");
- var multiBlockPreviewPage = BookMultiblockPageModel.builder()
- .withMultiblockId("modonomicon:blockentity") //sample multi-block from modonomicon
- .withMultiblockName("multiblocks.modonomicon.blockentity") //and the lang key for its name
- .withText(helper.pageText())
+ lang.add(langHelper.pageText(), "By giving a Living Flesh some more meat, a few Sharp Fangs, and a Bile Gland, you make a creature that will chew up items and give you useful components for the Bio-Forge");
+
+ langHelper.page("crafting");
+ var crafting = BookCraftingRecipePageModel.builder()
+ .withRecipeId1("biomancy:decomposer")
.build();
- lang.add("multiblocks.modonomicon.blockentity", "[PH] Blockentity Multi-Block.");
- lang.add(helper.pageText(), "[PH] A sample multi-block.");
-
- BookEntryModel entryModel = BookEntryModel.builder()
- .withId(entryId(helper))
- .withName(helper.entryName())
- .withDescription(helper.entryDescription())
- .withIcon("minecraft:furnace") //we use furnace as icon
- .withLocation(entryHelper.get(location)) //and we place it at the location we defined earlier in the entry helper mapping
- .withPages(introPage, multiBlockPreviewPage) //finally we add our pages to the entry
+
+ var builder = BookEntryModel.builder()
+ .withId(entryId(langHelper))
+ .withName(langHelper.entryName())
+ .withDescription(langHelper.entryDescription())
+ .withIcon(ModItems.DECOMPOSER.get())
+ .withLocation(location)
+ .withPages(introPage, crafting);
+ lang.add(langHelper.entryName(), "Decomposer");
+ lang.add(langHelper.entryDescription(), "Munch, munch!");
+
+ return builder;
+ }
+
+ private BookEntryModel.Builder makeCradleEntry(BookLangHelper langHelper, Vec2 location) {
+ langHelper.entry("primordial_cradle");
+
+ langHelper.page("intro");
+ var introPage = BookTextPageModel.builder()
+ .withText(langHelper.pageText())
+ .withTitle(langHelper.pageTitle())
.build();
- lang.add(helper.entryName(), "[PH] Multi-block Entry");
- lang.add(helper.entryDescription(), "[PH] An entry showcasing a multi-block.");
+ lang.add(langHelper.pageTitle(), "The Primordial Cradle");
+ lang.add(langHelper.pageText(), "By filling the cradle with raw flesh and a healing agent (Instant Health Potions, Healing Additive, or Regenerative Fluid) you gain the ability to form new living beings");
+
+ langHelper.page("crafting");
+ var crafting = BookCraftingRecipePageModel.builder()
+ .withRecipeId1("biomancy:primordial_core")
+ .withRecipeId2("biomancy:primordial_cradle")
+ .withText(langHelper.pageText())
+ .build();
+ lang.add(langHelper.pageText(), "Primordial Cradle Recipe");
+
+ var builder = BookEntryModel.builder()
+ .withId(entryId(langHelper))
+ .withName(langHelper.entryName())
+ .withDescription(langHelper.entryDescription())
+ .withIcon(ModItems.PRIMORDIAL_CRADLE.get())
+ .withLocation(location)
+ .withPages(introPage, crafting);
+ lang.add(langHelper.entryName(), "The Primordial Cradle");
+ lang.add(langHelper.entryDescription(), "The Fun Begins");
- return entryModel;
+ return builder;
}
}
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/particles/ModParticleSpriteProvider.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/particles/ModParticleSpriteProvider.java
index e908877f4..99b353d1f 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/particles/ModParticleSpriteProvider.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/particles/ModParticleSpriteProvider.java
@@ -6,6 +6,7 @@
import net.minecraftforge.common.data.ExistingFileHelper;
public class ModParticleSpriteProvider extends ParticleSpriteProvider {
+
public ModParticleSpriteProvider(DataGenerator generator, ExistingFileHelper fileHelper) {
super(generator, BiomancyMod.MOD_ID, fileHelper);
}
@@ -16,6 +17,9 @@ public void registerParticles() {
addParticle(ModParticleTypes.FALLING_BLOOD, "minecraft:drip_fall");
addParticle(ModParticleTypes.LANDING_BLOOD, "minecraft:drip_land");
addParticle(ModParticleTypes.CORROSIVE_SWIPE_ATTACK, 8, 1);
+ addParticle(ModParticleTypes.DRIPPING_ACID, "minecraft:drip_hang");
+ addParticle(ModParticleTypes.FALLING_ACID, "minecraft:drip_fall");
+ addParticle(ModParticleTypes.LANDING_ACID, "minecraft:drip_land");
}
}
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/BioForgeRecipeBuilder.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/BioForgeRecipeBuilder.java
index 4e1d6849d..ca575c5d4 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/BioForgeRecipeBuilder.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/BioForgeRecipeBuilder.java
@@ -1,11 +1,11 @@
package com.github.elenterius.biomancy.datagen.recipes;
import com.github.elenterius.biomancy.BiomancyMod;
+import com.github.elenterius.biomancy.crafting.recipe.DecomposerRecipe;
+import com.github.elenterius.biomancy.crafting.recipe.IngredientStack;
import com.github.elenterius.biomancy.init.ModBioForgeTabs;
import com.github.elenterius.biomancy.init.ModRecipes;
import com.github.elenterius.biomancy.menu.BioForgeTab;
-import com.github.elenterius.biomancy.recipe.DecomposerRecipe;
-import com.github.elenterius.biomancy.recipe.IngredientStack;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minecraft.advancements.Advancement;
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/BioLabRecipeBuilder.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/BioLabRecipeBuilder.java
index 42dba5415..d2a81ddcf 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/BioLabRecipeBuilder.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/BioLabRecipeBuilder.java
@@ -1,10 +1,10 @@
package com.github.elenterius.biomancy.datagen.recipes;
import com.github.elenterius.biomancy.BiomancyMod;
+import com.github.elenterius.biomancy.crafting.recipe.BioLabRecipe;
+import com.github.elenterius.biomancy.crafting.recipe.IngredientStack;
import com.github.elenterius.biomancy.init.ModItems;
import com.github.elenterius.biomancy.init.ModRecipes;
-import com.github.elenterius.biomancy.recipe.BioLabRecipe;
-import com.github.elenterius.biomancy.recipe.IngredientStack;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minecraft.advancements.Advancement;
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/DecomposerRecipeBuilder.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/DecomposerRecipeBuilder.java
index 3298195c0..d45a6e759 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/DecomposerRecipeBuilder.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/DecomposerRecipeBuilder.java
@@ -1,12 +1,12 @@
package com.github.elenterius.biomancy.datagen.recipes;
import com.github.elenterius.biomancy.BiomancyMod;
+import com.github.elenterius.biomancy.crafting.recipe.DecomposerRecipe;
+import com.github.elenterius.biomancy.crafting.recipe.IngredientStack;
+import com.github.elenterius.biomancy.crafting.recipe.ItemCountRange;
+import com.github.elenterius.biomancy.crafting.recipe.VariableProductionOutput;
import com.github.elenterius.biomancy.init.ModItems;
import com.github.elenterius.biomancy.init.ModRecipes;
-import com.github.elenterius.biomancy.recipe.DecomposerRecipe;
-import com.github.elenterius.biomancy.recipe.IngredientStack;
-import com.github.elenterius.biomancy.recipe.ItemCountRange;
-import com.github.elenterius.biomancy.recipe.VariableProductionOutput;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minecraft.advancements.Advancement;
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/DigesterRecipeBuilder.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/DigesterRecipeBuilder.java
index f2e6cb37d..43f02badb 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/DigesterRecipeBuilder.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/DigesterRecipeBuilder.java
@@ -1,9 +1,9 @@
package com.github.elenterius.biomancy.datagen.recipes;
import com.github.elenterius.biomancy.BiomancyMod;
+import com.github.elenterius.biomancy.crafting.recipe.DigesterRecipe;
import com.github.elenterius.biomancy.init.ModItems;
import com.github.elenterius.biomancy.init.ModRecipes;
-import com.github.elenterius.biomancy.recipe.DigesterRecipe;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minecraft.advancements.Advancement;
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/IRecipeBuilder.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/IRecipeBuilder.java
index e8729cf2c..10b65a1ef 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/IRecipeBuilder.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/IRecipeBuilder.java
@@ -46,6 +46,10 @@ private String getTagName(TagKey- tag) {
IRecipeBuilder unlockedBy(String name, CriterionTriggerInstance criterionTrigger);
+ default IRecipeBuilder unlockedBy(String name, ItemPredicate predicate) {
+ return unlockedBy(name, inventoryTrigger(predicate));
+ }
+
default IRecipeBuilder unlockedBy(ItemLike itemLike, CriterionTriggerInstance criterionTrigger) {
return unlockedBy("has_" + getItemName(itemLike), criterionTrigger);
}
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/ModRecipeProvider.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/ModRecipeProvider.java
index 9f03ad716..e0c9ad66b 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/ModRecipeProvider.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/recipes/ModRecipeProvider.java
@@ -3,11 +3,12 @@
import com.github.alexthe666.alexsmobs.AlexsMobs;
import com.github.alexthe666.alexsmobs.item.AMItemRegistry;
import com.github.elenterius.biomancy.BiomancyMod;
+import com.github.elenterius.biomancy.advancements.predicate.FoodItemPredicate;
+import com.github.elenterius.biomancy.crafting.recipe.FoodNutritionIngredient;
import com.github.elenterius.biomancy.init.ModBioForgeTabs;
import com.github.elenterius.biomancy.init.ModItems;
import com.github.elenterius.biomancy.init.tags.ModItemTags;
import com.github.elenterius.biomancy.item.weapon.RavenousClawsItem;
-import com.github.elenterius.biomancy.recipe.FoodNutritionIngredient;
import net.minecraft.advancements.critereon.InventoryChangeTrigger;
import net.minecraft.advancements.critereon.ItemPredicate;
import net.minecraft.data.DataGenerator;
@@ -148,15 +149,6 @@ private void registerWorkbenchRecipes(Consumer consumer) {
.pattern("MC ")
.unlockedBy(hasName(ModItems.PRIMORDIAL_CORE.get()), has(ModItems.PRIMORDIAL_CORE.get())).save(consumer);
- // WorkbenchRecipeBuilder.shapeless(ModItems.PRIMORDIAL_LIVING_OCULUS.get())
- // .requires(Items.SPIDER_EYE)
- // .requires(ModTags.Items.RAW_MEATS)
- // .requires(ModTags.Items.RAW_MEATS)
- // .requires(ModItems.MOB_SINEW.get())
- // .requires(ModItems.MOB_MARROW.get())
- // .requires(ModItems.PRIMORDIAL_LIVING_FLESH.get())
- // .unlockedBy(hasName(ModItems.PRIMORDIAL_LIVING_FLESH.get()), has(ModItems.PRIMORDIAL_LIVING_FLESH.get())).save(consumer);
- //
// WorkbenchRecipeBuilder.shapeless(ModItems.GUIDE_BOOK.get())
// .requires(ModItems.MOB_SINEW.get())
// .requires(Items.BOOK)
@@ -165,13 +157,6 @@ private void registerWorkbenchRecipes(Consumer consumer) {
// .requires(ModItems.MOB_FANG.get())
// .unlockedBy(hasName(ModItems.PRIMORDIAL_LIVING_FLESH.get()), has(ModItems.PRIMORDIAL_LIVING_FLESH.get())).save(consumer);
- // WorkbenchRecipeBuilder.shaped(ModItems.VIAL.get(), 8)
- // .define('G', Tags.Items.GLASS).define('T', Items.CLAY_BALL)
- // .pattern("GTG")
- // .pattern("G G")
- // .pattern(" G ")
- // .unlockedBy(hasName(Items.GLASS), has(Tags.Items.GLASS)).save(consumer);
-
// machines ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
WorkbenchRecipeBuilder.shaped(ModItems.PRIMORDIAL_CRADLE.get())
@@ -322,13 +307,14 @@ private void registerWorkbenchRecipes(Consumer consumer) {
stonecutterResultFromBase(consumer, ModItems.PRIMAL_FLESH_STAIRS.get(), ModItems.PRIMAL_FLESH_BLOCK.get());
stonecutterResultFromBase(consumer, ModItems.PRIMAL_FLESH_SLAB.get(), ModItems.PRIMAL_FLESH_BLOCK.get(), 2);
- WorkbenchRecipeBuilder.shaped(ModItems.PRIMAL_FLESH_BLOCK.get(), 8)
- .define('G', ModItems.WITHERING_OOZE.get())
- .define('F', ModItems.FLESH_BLOCK.get())
+ WorkbenchRecipeBuilder.shaped(ModItems.PRIMAL_FLESH_BLOCK.get(), 4)
+ .define('S', ModItems.STONE_POWDER.get())
+ .define('E', ModItems.EXOTIC_DUST.get())
+ .define('F', ModItemTags.RAW_MEATS)
.define('M', ModItems.MALIGNANT_FLESH_BLOCK.get())
+ .pattern("SME")
.pattern("MFM")
- .pattern("FGF")
- .pattern("MFM")
+ .pattern("EMS")
.unlockedBy(hasName(ModItems.MALIGNANT_FLESH_BLOCK.get()), has(ModItems.MALIGNANT_FLESH_BLOCK.get()))
.save(consumer);
@@ -350,49 +336,51 @@ private void registerWorkbenchRecipes(Consumer consumer) {
.save(consumer);
WorkbenchRecipeBuilder.shaped(ModItems.PRIMORDIAL_BIO_LANTERN.get())
- .define('F', ModItems.YELLOW_BIO_LANTERN.get())
+ .define('B', ModItems.BLOOMBERRY.get())
.define('V', ModItems.MALIGNANT_FLESH_VEINS.get())
- .pattern("VVV")
- .pattern("VFV")
- .pattern("VVV")
- .unlockedBy(hasName(ModItems.MALIGNANT_FLESH_VEINS.get()), has(ModItems.MALIGNANT_FLESH_VEINS.get()))
- .save(consumer, getConversionRecipeId(ModItems.PRIMORDIAL_BIO_LANTERN.get(), ModItems.YELLOW_BIO_LANTERN.get()));
+ .define('C', ModItems.TENDON_CHAIN.get())
+ .pattern(" C ")
+ .pattern("VBV")
+ .pattern(" V ")
+ .unlockedBy(hasName(ModItems.BLOOMBERRY.get()), has(ModItems.BLOOMBERRY.get()))
+ .save(consumer);
- WorkbenchRecipeBuilder.shaped(ModItems.PRIMORDIAL_BIO_LANTERN.get())
- .define('F', ModItems.BLUE_BIO_LANTERN.get())
+ WorkbenchRecipeBuilder.shaped(ModItems.BLOOMLIGHT.get(), 4)
+ .define('B', ModItems.BLOOMBERRY.get())
.define('V', ModItems.MALIGNANT_FLESH_VEINS.get())
- .pattern("VVV")
- .pattern("VFV")
- .pattern("VVV")
- .unlockedBy(hasName(ModItems.PRIMORDIAL_BIO_LANTERN.get()), has(ModItems.BLUE_BIO_LANTERN.get()))
+ .pattern("BVB")
+ .pattern("VBV")
+ .pattern("BVB")
+ .unlockedBy(hasName(ModItems.BLOOMBERRY.get()), has(ModItems.BLOOMBERRY.get()))
.save(consumer);
}
private void registerDigestingRecipes(Consumer consumer) {
+ FoodItemPredicate foodItemPredicate = new FoodItemPredicate();
DigesterRecipeBuilder.create(ModItems.NUTRIENT_PASTE.get(), 1, "poor_food")
.setIngredient(new FoodNutritionIngredient(0, 1))
- .unlockedBy(ModItemTags.POOR_BIOMASS).save(consumer);
+ .unlockedBy("has_food", foodItemPredicate).save(consumer);
DigesterRecipeBuilder.create(ModItems.NUTRIENT_PASTE.get(), 2, "average_food")
.setIngredient(new FoodNutritionIngredient(2, 3))
- .unlockedBy(ModItemTags.AVERAGE_BIOMASS).save(consumer);
+ .unlockedBy("has_food", foodItemPredicate).save(consumer);
DigesterRecipeBuilder.create(ModItems.NUTRIENT_PASTE.get(), 4, "good_food")
.setIngredient(new FoodNutritionIngredient(4, 5))
- .unlockedBy(ModItemTags.GOOD_BIOMASS).save(consumer);
+ .unlockedBy("has_food", foodItemPredicate).save(consumer);
DigesterRecipeBuilder.create(ModItems.NUTRIENT_PASTE.get(), 6, "superb_food")
.setIngredient(new FoodNutritionIngredient(6, 7))
- .unlockedBy(ModItemTags.SUPERB_BIOMASS).save(consumer);
+ .unlockedBy("has_food", foodItemPredicate).save(consumer);
DigesterRecipeBuilder.create(ModItems.NUTRIENT_PASTE.get(), 8, "excellent_food")
.setIngredient(new FoodNutritionIngredient(8, 9))
- .unlockedBy(ModItemTags.SUPERB_BIOMASS).save(consumer);
+ .unlockedBy("has_food", foodItemPredicate).save(consumer);
DigesterRecipeBuilder.create(ModItems.NUTRIENT_PASTE.get(), 10, "godly_food")
.setIngredient(new FoodNutritionIngredient(10, Integer.MAX_VALUE))
- .unlockedBy(ModItemTags.SUPERB_BIOMASS).save(consumer);
+ .unlockedBy("has_food", foodItemPredicate).save(consumer);
//////////////////////////
@@ -610,9 +598,23 @@ private void registerDecomposingRecipes(Consumer consumer) {
.addOutput(ModItems.EXOTIC_DUST.get(), 0, 2)
.unlockedBy(ModItems.LIVING_FLESH).save(consumer);
+ DecomposerRecipeBuilder.create().setIngredient(ModItems.BLOOMBERRY)
+ .addOutput(ModItems.BIO_LUMENS.get(), 0, 2)
+ .addOutput(ModItems.ORGANIC_MATTER.get(), 0, 1)
+ .addOutput(ModItems.EXOTIC_DUST.get(), 0, 3)
+ .addOutput(ModItems.BILE.get(), 1, 2)
+ .unlockedBy(ModItems.BLOOMBERRY).save(consumer);
+ DecomposerRecipeBuilder.create().setIngredient(ModItems.BLOOMLIGHT)
+ .addOutput(ModItems.BIO_LUMENS.get(), 5, 9)
+ .addOutput(ModItems.ORGANIC_MATTER.get(), 2, 3)
+ .addOutput(ModItems.EXOTIC_DUST.get(), 0, 4)
+ .addOutput(ModItems.BILE.get(), 1, 2)
+ .unlockedBy(Items.SHROOMLIGHT).save(consumer);
+
registerDecomposerRecipesFor119(consumer);
registerDecomposerRecipesForBiomesOPlenty(consumer);
registerDecomposerRecipesForAlexsMobs(consumer);
+ registerDecomposerRecipesForTetra(consumer);
}
private void registerDecomposerRecipesFor119(Consumer consumer) {
@@ -628,6 +630,14 @@ private void registerDecomposerRecipesForBiomesOPlenty(Consumer
DecomposerRecipeBuilder.create().ifModLoaded("biomesoplenty").setIngredient(new DatagenIngredient("biomesoplenty:flesh_tendons")).addOutput(ModItems.ELASTIC_FIBERS.get(), 4, 8).addOutput(ModItems.FLESH_BITS.get(), 1, 2).unlockedBy(ModItems.MOB_SINEW).save(consumer);
}
+ private void registerDecomposerRecipesForTetra(Consumer consumer) {
+ DecomposerRecipeBuilder.create().ifModLoaded("tetra").setIngredient(new DatagenIngredient("tetra:dragon_sinew"))
+ .addOutput(ModItems.ELASTIC_FIBERS.get(), 4, 8)
+ .addOutput(ModItems.TOUGH_FIBERS.get(), 1, 2)
+ .addOutput(ModItems.EXOTIC_DUST.get(), 4, 8)
+ .unlockedBy(ModItems.MOB_SINEW).save(consumer);
+ }
+
private void registerDecomposerRecipesForAlexsMobs(Consumer consumer) {
DecomposerRecipeBuilder.create().ifModLoaded(AlexsMobs.MODID)
.setIngredient(AMItemRegistry.ROADRUNNER_FEATHER)
@@ -947,6 +957,13 @@ private void registerBioForgeRecipes(Consumer consumer) {
.setCategory(ModBioForgeTabs.MISC)
.unlockedBy(ModItems.ELASTIC_FIBERS.get()).save(consumer);
+ BioForgeRecipeBuilder.create(ModItems.UNDEAD_PERMEABLE_MEMBRANE.get())
+ .addIngredient(ModItems.ELASTIC_FIBERS.get(), 4)
+ .addIngredient(ModItems.BILE.get(), 4)
+ .addIngredient(Items.PHANTOM_MEMBRANE, 1)
+ .setCategory(ModBioForgeTabs.MISC)
+ .unlockedBy(Items.PHANTOM_MEMBRANE).save(consumer);
+
BioForgeRecipeBuilder.create(ModItems.FLESH_FENCE.get(), 4)
.addIngredient(ModItems.FLESH_BITS.get(), fleshBlockCost)
.addIngredient(ModItems.BONE_FRAGMENTS.get(), 2)
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ForgeEntityTypeTagsProvider.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ForgeEntityTypeTagsProvider.java
index c9b3899e7..c6ead5d9a 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ForgeEntityTypeTagsProvider.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ForgeEntityTypeTagsProvider.java
@@ -3,21 +3,32 @@
import com.github.elenterius.biomancy.init.tags.ModEntityTags;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.tags.EntityTypeTagsProvider;
+import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.EntityType;
import net.minecraftforge.common.data.ExistingFileHelper;
+import net.minecraftforge.registries.ForgeRegistries;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
public class ForgeEntityTypeTagsProvider extends EntityTypeTagsProvider {
- public ForgeEntityTypeTagsProvider(DataGenerator pGenerator, @Nullable ExistingFileHelper existingFileHelper) {
- super(pGenerator, "forge", existingFileHelper);
+ public ForgeEntityTypeTagsProvider(DataGenerator generator, @Nullable ExistingFileHelper existingFileHelper) {
+ super(generator, "forge", existingFileHelper);
}
@Override
protected void addTags() {
- tag(ModEntityTags.FORGE_BOSSES).add(EntityType.WITHER, EntityType.ENDER_DRAGON);
+ tag(ModEntityTags.FORGE_BOSSES)
+ .add(EntityType.WITHER, EntityType.ENDER_DRAGON);
+
+ createTag(ModEntityTags.FORGE_GOLEMS)
+ .add(EntityType.IRON_GOLEM, EntityType.SNOW_GOLEM)
+ .addOptional("strawgolem:strawgolem", "strawgolem:strawnggolem");
+ }
+
+ protected EnhancedTagAppender> createTag(TagKey> tag) {
+ return new EnhancedTagAppender<>(tag(tag), ForgeRegistries.ENTITY_TYPES);
}
@Override
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ModBlockTagsProvider.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ModBlockTagsProvider.java
index 9b7dc9c9f..abb27e8dd 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ModBlockTagsProvider.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ModBlockTagsProvider.java
@@ -1,5 +1,7 @@
package com.github.elenterius.biomancy.datagen.tags;
+import com.github.elenterius.biomancy.block.FleshDoorBlock;
+import com.github.elenterius.biomancy.block.FullFleshDoorBlock;
import com.github.elenterius.biomancy.init.ModBlockMaterials;
import com.github.elenterius.biomancy.init.ModBlocks;
import com.github.elenterius.biomancy.init.tags.ModBlockTags;
@@ -10,13 +12,13 @@
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
-import net.minecraft.world.level.block.state.predicate.BlockMaterialPredicate;
import net.minecraftforge.common.Tags;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.registries.RegistryObject;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
+import java.util.function.Predicate;
import static com.github.elenterius.biomancy.BiomancyMod.MOD_ID;
@@ -39,21 +41,36 @@ public String getName() {
protected void addTags() {
addFleshyBlocksToHoeTag();
addCreateTags();
+ addQuarkTags();
- //CONVERTABLE_TO_PRIMAL_FLESH
- //CONVERTABLE_TO_MALIGNANT_FLESH
- tag(ModBlockTags.PRIMORDIAL_ECO_SYSTEM_REPLACEABLE)
+ tag(ModBlockTags.FLESH_REPLACEABLE)
.add(Blocks.CLAY).addTag(BlockTags.SAND).addTag(Tags.Blocks.GRAVEL)
.add(Blocks.SNOW_BLOCK, Blocks.SNOW)
.addTag(BlockTags.LEAVES)
- .add(
- Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL, Blocks.GRASS_BLOCK, Blocks.DIRT_PATH, Blocks.FARMLAND,
- Blocks.ROOTED_DIRT, Blocks.MUDDY_MANGROVE_ROOTS, Blocks.MUD
- );
+ .addTag(BlockTags.OVERWORLD_NATURAL_LOGS)
+ .addTag(BlockTags.DIRT)
+ .add(Blocks.DIRT_PATH, Blocks.FARMLAND, Blocks.MOSS_BLOCK, Blocks.VINE)
+ .add(Blocks.MELON, Blocks.PUMPKIN)
+ .addTag(BlockTags.FLOWERS);
+
+ tag(ModBlockTags.ALLOW_VEINS_TO_ATTACH)
+ .add(Blocks.DIRT_PATH, Blocks.FARMLAND, Blocks.VINE);
+
+ tag(ModBlockTags.DISALLOW_VEINS_TO_ATTACH).add(
+ ModBlocks.MALIGNANT_BLOOM.get(),
+ ModBlocks.PRIMAL_PERMEABLE_MEMBRANE.get()
+ );
+
+ tag(ModBlockTags.ACID_DESTRUCTIBLE)
+ .addTag(BlockTags.LEAVES)
+ .add(Blocks.MOSS_BLOCK, Blocks.VINE)
+ .addTag(BlockTags.FLOWERS);
tag(BlockTags.DOORS).add(ModBlocks.FLESH_DOOR.get()).add(ModBlocks.FULL_FLESH_DOOR.get());
tag(BlockTags.TRAPDOORS).add(ModBlocks.FLESH_IRIS_DOOR.get());
+ tag(Tags.Blocks.CHESTS).add(ModBlocks.FLESHKIN_CHEST.get());
+
tag(ModBlockTags.FLESHY_FENCES).add(ModBlocks.FLESH_FENCE.get());
tag(BlockTags.FENCES).addTag(ModBlockTags.FLESHY_FENCES);
tag(BlockTags.FENCE_GATES).add(ModBlocks.FLESH_FENCE_GATE.get());
@@ -86,14 +103,15 @@ protected void addTags() {
tag(BlockTags.IMPERMEABLE).add(
ModBlocks.IMPERMEABLE_MEMBRANE.get(),
ModBlocks.BABY_PERMEABLE_MEMBRANE.get(),
- ModBlocks.ADULT_PERMEABLE_MEMBRANE.get()
+ ModBlocks.ADULT_PERMEABLE_MEMBRANE.get(),
+ ModBlocks.PRIMAL_PERMEABLE_MEMBRANE.get(),
+ ModBlocks.UNDEAD_PERMEABLE_MEMBRANE.get()
);
}
private void addFleshyBlocksToHoeTag() {
- BlockMaterialPredicate predicate = BlockMaterialPredicate.forMaterial(ModBlockMaterials.FLESH_MATERIAL);
TagAppender tag = tag(BlockTags.MINEABLE_WITH_HOE);
- ModBlocks.BLOCKS.getEntries().stream().map(RegistryObject::get).filter(block -> predicate.test(block.defaultBlockState())).forEach(tag::add);
+ ModBlocks.BLOCKS.getEntries().stream().map(RegistryObject::get).filter(ModBlockMaterials.FLESH_PREDICATE).forEach(tag::add);
}
/**
@@ -110,4 +128,15 @@ private void addCreateTags() {
);
}
+ /**
+ * Quark Tags
+ */
+ private void addQuarkTags() {
+ String modId = "quark";
+
+ TagKey noDoubleDoor = tagKey(modId, "non_double_door");
+ TagAppender tag = tag(noDoubleDoor);
+ Predicate predicate = block -> block instanceof FleshDoorBlock || block instanceof FullFleshDoorBlock;
+ ModBlocks.BLOCKS.getEntries().stream().map(RegistryObject::get).filter(predicate).forEach(tag::add);
+ }
}
diff --git a/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ModItemTagsProvider.java b/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ModItemTagsProvider.java
index 51272d830..fd66763e6 100644
--- a/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ModItemTagsProvider.java
+++ b/src/datagen/java/com/github/elenterius/biomancy/datagen/tags/ModItemTagsProvider.java
@@ -10,7 +10,9 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.TagKey;
+import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
+import net.minecraft.world.level.block.ShulkerBoxBlock;
import net.minecraftforge.common.Tags;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.registries.ForgeRegistries;
@@ -25,6 +27,10 @@ public ModItemTagsProvider(DataGenerator dataGenerator, BlockTagsProvider blockT
super(dataGenerator, blockTagProvider, BiomancyMod.MOD_ID, existingFileHelper);
}
+ private static TagKey
- forgeTag(String path) {
+ return ItemTags.create(new ResourceLocation("forge", path));
+ }
+
@Override
protected void addTags() {
addBiomancyTags();
@@ -33,18 +39,12 @@ protected void addTags() {
}
private void addBiomancyTags() {
+
createTag(ModItemTags.SUGARS)
.add(SUGAR, COOKIE, CAKE, HONEYCOMB, HONEY_BLOCK, HONEYCOMB_BLOCK, HONEY_BOTTLE, SWEET_BERRIES, COCOA_BEANS, APPLE)
.addOptional("create:sweet_roll", "create:chocolate_glazed_berries", "create:honeyed_apple", "create:bar_of_chocolate")
.addOptional("createaddition:chocolate_cake");
- createTag(ModItemTags.POOR_BIOMASS);
- createTag(ModItemTags.AVERAGE_BIOMASS);
- createTag(ModItemTags.GOOD_BIOMASS);
- createTag(ModItemTags.SUPERB_BIOMASS);
- createTag(ModItemTags.BIOMASS)
- .addTag(ModItemTags.POOR_BIOMASS, ModItemTags.AVERAGE_BIOMASS, ModItemTags.GOOD_BIOMASS, ModItemTags.SUPERB_BIOMASS);
-
createTag(ModItemTags.RAW_MEATS)
.add(BEEF, PORKCHOP, CHICKEN, RABBIT, MUTTON, COD, SALMON, TROPICAL_FISH, PUFFERFISH)
.add(AMItemRegistry.MOOSE_RIBS.get(), AMItemRegistry.KANGAROO_MEAT.get(), AMItemRegistry.RAW_CATFISH.get(), AMItemRegistry.BLOBFISH.get(), AMItemRegistry.MAGGOT.get())
@@ -68,29 +68,49 @@ private void addBiomancyTags() {
createTag(ModItemTags.FANGS)
.add(ModItems.MOB_FANG.get())
.add(AMItemRegistry.BONE_SERPENT_TOOTH.get());
+
+ createTag(ModItemTags.CANNOT_BE_EATEN_BY_CRADLE)
+ .add(DRAGON_EGG, SPAWNER, HEART_OF_THE_SEA)
+ .add(NAME_TAG)
+ .addTag(ItemTags.MUSIC_DISCS)
+ .add(ELYTRA)
+ .addTag(Tags.Items.ARMORS, Tags.Items.TOOLS)
+ .addTag(Tags.Items.ORES_NETHERITE_SCRAP, Tags.Items.INGOTS_NETHERITE, Tags.Items.STORAGE_BLOCKS_NETHERITE)
+ .addTag(forgeTag("shulker_boxes"));
}
private void addMinecraftTags() {
// tag(ItemTags.FENCES).getInternalBuilder().addTag(ModTags.Blocks.FLESHY_FENCES.getName(), BiomancyMod.MOD_ID);
- }
- private static TagKey
- forgeTag(String path) {
- return ItemTags.create(new ResourceLocation("forge", path));
+ createTag(ItemTags.DOORS)
+ .add(ModItems.FLESH_DOOR.get(), ModItems.FULL_FLESH_DOOR.get());
+
+ createTag(ItemTags.TRAPDOORS)
+ .add(ModItems.FLESH_IRIS_DOOR.get());
}
private void addForgeTags() {
// tag(ModItemTags.FORGE_TOOLS_KNIVES);
TagKey
- clawsTag = forgeTag("tools/claws");
- tag(clawsTag)
+ createTag(clawsTag)
.add(ModItems.RAVENOUS_CLAWS.get());
- tag(Tags.Items.TOOLS_SWORDS)
+ createTag(Tags.Items.TOOLS_SWORDS)
.add(ModItems.DESPOIL_SICKLE.get(), ModItems.TOXICUS.get());
- tag(Tags.Items.TOOLS)
+ createTag(Tags.Items.TOOLS)
.addTag(clawsTag)
.add(ModItems.INJECTOR.get(), ModItems.BIO_EXTRACTOR.get());
+
+ createTag(Tags.Items.CHESTS).add(ModItems.FLESHKIN_CHEST.get());
+
+ EnhancedTagAppender
- shulkerBoxes = createTag(forgeTag("shulker_boxes"));
+ for (Item item : ForgeRegistries.ITEMS) {
+ if (item instanceof BlockItem blockItem && blockItem.getBlock() instanceof ShulkerBoxBlock) {
+ shulkerBoxes.add(item);
+ }
+ }
}
protected EnhancedTagAppender
- createTag(TagKey
- tag) {
diff --git a/src/generated/resources/assets/biomancy/lang/en_us.json b/src/generated/resources/assets/biomancy/lang/en_us.json
index cd361547e..45939d675 100644
--- a/src/generated/resources/assets/biomancy/lang/en_us.json
+++ b/src/generated/resources/assets/biomancy/lang/en_us.json
@@ -44,6 +44,8 @@
"item.biomancy.nutrient_paste.tooltip": "Nutrients combined with Biotic Matter to moisten the hard pellets, producing a paste.\nIt almost looks like yellowish cake, and is a convenient source of energy.",
"item.biomancy.nutrient_bar": "Nutrient Bar",
"item.biomancy.nutrient_bar.tooltip": "Nutrient Paste compressed into the shape of a bar. Looks edible, if a bit bland.",
+ "item.biomancy.sapberry": "Sapberry",
+ "item.biomancy.sapberry.tooltip": "An exotic delicacy which grants random potion effects.",
"item.biomancy.regenerative_fluid": "Regenerative Fluid",
"item.biomancy.regenerative_fluid.tooltip": "A fluid with regenerative properties, used to concoct healing additives.",
"item.biomancy.withering_ooze": "Withering Ooze",
@@ -76,6 +78,7 @@
"item.biomancy.fertilizer.tooltip": "Fertilizer that induces hyper-growth in plants, even for reeds, cactus, nether wart and chorus.",
"item.biomancy.gift_sac": "Gift Sac",
"item.biomancy.gift_sac.tooltip": "Looks like some objects are wrapped in an organic layer of skin. Might be filled with items or toxin if your language is set to German.\n\nRight Click the Sac to retrieve the Items.",
+ "item.biomancy.acid_bucket": "Acid Bucket",
"item.biomancy.ravenous_claws": "Ravenous Claws",
"item.biomancy.ravenous_claws.tooltip": "Extremely hungry and vicious Claws forged by starving living flesh and grafting claws onto it.\n\nRepair the famished claws by feeding them with food via the player inventory, as you would fill a bundle.\n\nKilling Mobs with these claws grants blood charges, which allow you to use the Awakened mode.",
"item.biomancy.dev_arm_cannon": "[Dev Tool] Arm Cannon",
@@ -197,6 +200,8 @@
"block.biomancy.bio_lantern_blue.tooltip": "A bioluminescent light source. This one is blue!",
"block.biomancy.primordial_bio_lantern": "Primordial Bio-Lantern",
"block.biomancy.primordial_bio_lantern.tooltip": "A primal light source. This one is magenta!",
+ "block.biomancy.bloomlight": "Bloomlight",
+ "block.biomancy.bloomlight.tooltip": "A malignant light source. This one is magenta as well!",
"block.biomancy.tendon_chain": "Tendon Chain",
"block.biomancy.tendon_chain.tooltip": "A chain made of tendons.",
"block.biomancy.vial_holder": "Vial Holder",
@@ -207,8 +212,12 @@
"block.biomancy.baby_permeable_membrane.tooltip": "Gelatinous-like membrane reinforced with elastic fibers.\n\nBaby mobs can diffuse through the membrane.",
"block.biomancy.adult_permeable_membrane": "Adult-Permeable Membrane",
"block.biomancy.adult_permeable_membrane.tooltip": "Gelatinous-like membrane reinforced with elastic fibers.\n\nAdult mobs can diffuse through the membrane.",
- "block.biomancy.item_permeable_membrane": "Item-Permeable Membrane",
- "block.biomancy.item_permeable_membrane.tooltip": "Gelatinous-like membrane reinforced with elastic fibers.\n\nItems can diffuse through the membrane.",
+ "block.biomancy.primal_permeable_membrane": "Primal Membrane",
+ "block.biomancy.primal_permeable_membrane.tooltip": "Gelatinous-like membrane reinforced with elastic fibers.\n\nOnly mobs that are alive can diffuse through the membrane.",
+ "block.biomancy.undead_permeable_membrane": "Phantom Membrane",
+ "block.biomancy.undead_permeable_membrane.tooltip": "Gelatinous-like membrane reinforced with elastic fibers.\n\nOnly mobs that are undead can diffuse through the membrane.",
+ "block.biomancy.neural_interceptor": "Neural Interceptor",
+ "block.biomancy.neural_interceptor.tooltip": "A psychic node that prevents natural mob spawning in a 48 block radius.",
"block.biomancy.primal_flesh": "Primal Flesh Block",
"block.biomancy.primal_flesh.tooltip": "Primitive and pure, you better not touch this with your dirty mitts.",
"block.biomancy.primal_flesh_slab": "Primal Flesh Slab",
@@ -227,6 +236,12 @@
"block.biomancy.malignant_flesh_wall.tooltip": "Wall of malignant flesh.\nIt's coming for you! ;)",
"block.biomancy.malignant_flesh_veins": "Malignant Flesh Veins",
"block.biomancy.malignant_flesh_veins.tooltip": "They look almost feral...\nyou better not touch them.",
+ "block.biomancy.malignant_bloom": "Malignant Bloom",
+ "block.biomancy.malignant_bloom.tooltip": "An exotic flower of primordial beauty.\n\nIt will spread itself by launching it's ripe berry into the air.\nOn impact the berry explodes and spreads malignant veins as well.",
+ "block.biomancy.primal_orifice": "Primal Orifice",
+ "block.biomancy.primal_orifice.tooltip": "A primitive piece full of holes. It seems to leak an acidic substance.",
+ "block.biomancy.acid_fluid_block": "Acid",
+ "fluid_type.biomancy.acid": "Acid",
"entity.biomancy.hungry_flesh_blob": "Hungry Flesh Blob",
"entity.biomancy.flesh_blob": "Flesh Blob",
"entity.biomancy.legacy_flesh_blob": "Legacy Flesh Blob",
@@ -257,6 +272,7 @@
"tooltip.biomancy.empty": "Empty",
"tooltip.biomancy.contains": "Contains: %1$s",
"tooltip.biomancy.nutrients_fuel": "Nutrients",
+ "tooltip.biomancy.primal_energy": "Primal Energy",
"tooltip.biomancy.nutrients_consumes": "Consumes %1$s u",
"tooltip.biomancy.consumption": "Consumption",
"tooltip.biomancy.bile_fuel": "Bile",
@@ -312,6 +328,11 @@
"sounds.biomancy.flesh_block.step": "Step on Fleshy Block",
"sounds.biomancy.flesh_block.break": "Break Fleshy Block",
"sounds.biomancy.flesh_block.fall": "Fall on Fleshy Block",
+ "sounds.biomancy.bony_flesh_block.hit": "Hit Bony Flesh Block",
+ "sounds.biomancy.bony_flesh_block.place": "Place Bony Flesh Block",
+ "sounds.biomancy.bony_flesh_block.step": "Step on Bony Flesh Block",
+ "sounds.biomancy.bony_flesh_block.break": "Break Bony Flesh Block",
+ "sounds.biomancy.bony_flesh_block.fall": "Fall on Bony Flesh Block",
"sounds.biomancy.flesh_door.open": "Open Fleshy Door",
"sounds.biomancy.flesh_door.close": "Close Fleshy Door",
"sounds.biomancy.claws.attack.strong": "Strong Claw Attack",
@@ -431,5 +452,28 @@
"advancements.biomancy.exotic_compounds.title": "Exotic Bio-Alchemy",
"advancements.biomancy.exotic_compounds.description": "Combine organic things with exotic compounds to create cures and cleansing fluids.",
"advancements.biomancy.genetic_compounds.title": "Genetic Bio-Alchemy",
- "advancements.biomancy.genetic_compounds.description": "Combine organic things with genetic compounds to create fluids that influence growth and fertility."
+ "advancements.biomancy.genetic_compounds.description": "Combine organic things with genetic compounds to create fluids that influence growth and fertility.",
+ "book.biomancy.guide_book.name": "Biomancy Index",
+ "book.biomancy.guide_book.tooltip": "A book to test Modonomicon features for Biomancy.",
+ "book.biomancy.guide_book.features.primordial_cradle.intro.title": "The Primordial Cradle",
+ "book.biomancy.guide_book.features.primordial_cradle.intro.text": "By filling the cradle with raw flesh and a healing agent (Instant Health Potions, Healing Additive, or Regenerative Fluid) you gain the ability to form new living beings",
+ "book.biomancy.guide_book.features.primordial_cradle.crafting.text": "Primordial Cradle Recipe",
+ "book.biomancy.guide_book.features.primordial_cradle.name": "The Primordial Cradle",
+ "book.biomancy.guide_book.features.primordial_cradle.description": "The Fun Begins",
+ "book.biomancy.guide_book.features.spotlight.intro.title": "[PH] Spotlight Entry",
+ "book.biomancy.guide_book.features.spotlight.intro.text": "[PH] Spotlight pages allow to show items (actually, ingredients).",
+ "book.biomancy.guide_book.features.spotlight.spotlight1.title": "[PH] Custom Title",
+ "book.biomancy.guide_book.features.spotlight.spotlight1.text": "[PH] A sample spotlight page with custom title.",
+ "book.biomancy.guide_book.features.spotlight.spotlight2.text": "[PH] A sample spotlight page with automatic title.",
+ "book.biomancy.guide_book.features.spotlight.name": "[PH] Spotlight Entry",
+ "book.biomancy.guide_book.features.spotlight.description": "[PH] An entry showcasing spotlight pages.",
+ "book.biomancy.guide_book.features.mob.living_flesh_spotlight.text": "Living Flesh is the remains of a Flesh Blob after is has been killed.\n\\\nIt's most definitely alive, although it lacks any real intelligence or selfish will.\n\\\n++That isn't necessarily a bad thing though...++",
+ "book.biomancy.guide_book.features.mob.flesh_blob_page.text": "A regular Flesh Blob is formed with just typical raw meat and healing agents.\n\\\nHas no redeeming qualities, but makes for a good house pet.",
+ "book.biomancy.guide_book.features.mob.hungry_flesh_blob_text.text": "A Hungry Flesh Blob is formed by adding a few Sharp Fangs into the cradle with some raw meat and a healing agent.\n\\\nMaybe don't try petting this one...",
+ "book.biomancy.guide_book.features.mob.name": "Flesh Blobs",
+ "book.biomancy.guide_book.features.mob.description": "Bouncy lil guys",
+ "book.biomancy.guide_book.features.decomposer.spotlight.text": "By giving a Living Flesh some more meat, a few Sharp Fangs, and a Bile Gland, you make a creature that will chew up items and give you useful components for the Bio-Forge",
+ "book.biomancy.guide_book.features.decomposer.name": "Decomposer",
+ "book.biomancy.guide_book.features.decomposer.description": "Munch, munch!",
+ "book.biomancy.guide_book.features.name": "Fleshy Constructs"
}
\ No newline at end of file
diff --git a/src/main/java/com/github/elenterius/biomancy/BiomancyConfig.java b/src/main/java/com/github/elenterius/biomancy/BiomancyConfig.java
new file mode 100644
index 000000000..23c716b59
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/BiomancyConfig.java
@@ -0,0 +1,26 @@
+package com.github.elenterius.biomancy;
+
+import com.github.elenterius.biomancy.config.ServerConfig;
+import net.minecraftforge.common.ForgeConfigSpec;
+import net.minecraftforge.fml.ModLoadingContext;
+import net.minecraftforge.fml.config.ModConfig;
+import org.apache.commons.lang3.tuple.Pair;
+
+public final class BiomancyConfig {
+
+ public static final ForgeConfigSpec SERVER_SPECIFICATION;
+ public static final ServerConfig SERVER;
+
+ private BiomancyConfig() {}
+
+ static {
+ Pair specPair = new ForgeConfigSpec.Builder().configure(ServerConfig::new);
+ SERVER = specPair.getLeft();
+ SERVER_SPECIFICATION = specPair.getRight();
+ }
+
+ public static void register(ModLoadingContext modLoadingContext) {
+ modLoadingContext.registerConfig(ModConfig.Type.SERVER, BiomancyConfig.SERVER_SPECIFICATION);
+ }
+
+}
diff --git a/src/main/java/com/github/elenterius/biomancy/BiomancyMod.java b/src/main/java/com/github/elenterius/biomancy/BiomancyMod.java
index 5f50ce94c..e8bbcbe1e 100644
--- a/src/main/java/com/github/elenterius/biomancy/BiomancyMod.java
+++ b/src/main/java/com/github/elenterius/biomancy/BiomancyMod.java
@@ -10,6 +10,7 @@
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentInstance;
import net.minecraftforge.eventbus.api.IEventBus;
+import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.RegistryObject;
@@ -31,12 +32,17 @@ public BiomancyMod() {
GeckoLib.initialize();
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
+ ModLoadingContext modLoadingContext = ModLoadingContext.get();
ModBannerPatterns.BANNERS.register(modEventBus);
ModBlocks.BLOCKS.register(modEventBus);
ModItems.ITEMS.register(modEventBus);
ModBlockEntities.BLOCK_ENTITIES.register(modEventBus);
+
+ ModFluids.FLUID_TYPES.register(modEventBus);
+ ModFluids.FLUIDS.register(modEventBus);
+
ModEntityTypes.ENTITIES.register(modEventBus);
ModAttributes.ATTRIBUTES.register(modEventBus);
@@ -55,6 +61,7 @@ public BiomancyMod() {
ModSoundEvents.SOUND_EVENTS.register(modEventBus);
ModParticleTypes.PARTICLE_TYPES.register(modEventBus);
+ BiomancyConfig.register(modLoadingContext);
ModsCompatHandler.onBiomancyInit(modEventBus);
}
diff --git a/src/main/java/com/github/elenterius/biomancy/advancements/predicate/FoodItemPredicate.java b/src/main/java/com/github/elenterius/biomancy/advancements/predicate/FoodItemPredicate.java
new file mode 100644
index 000000000..e1f0f209f
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/advancements/predicate/FoodItemPredicate.java
@@ -0,0 +1,33 @@
+package com.github.elenterius.biomancy.advancements.predicate;
+
+import com.github.elenterius.biomancy.BiomancyMod;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import net.minecraft.advancements.critereon.ItemPredicate;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.item.ItemStack;
+
+public class FoodItemPredicate extends ItemPredicate {
+
+ public static final ResourceLocation ID = BiomancyMod.createRL("is_food_item");
+
+ public FoodItemPredicate() {}
+
+ @Override
+ public boolean matches(ItemStack stack) {
+ if (!stack.isEdible()) return false;
+ return stack.getFoodProperties(null) != null;
+ }
+
+ @Override
+ public JsonElement serializeToJson() {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("type", ID.toString());
+ return jsonObject;
+ }
+
+ public static FoodItemPredicate deserializeFromJson(JsonObject jsonObject) {
+ return new FoodItemPredicate();
+ }
+
+}
diff --git a/src/main/java/com/github/elenterius/biomancy/block/DirectionalSlabBlock.java b/src/main/java/com/github/elenterius/biomancy/block/DirectionalSlabBlock.java
index 5739b0049..b7eb0259f 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/DirectionalSlabBlock.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/DirectionalSlabBlock.java
@@ -86,6 +86,19 @@ public BlockState getStateForPlacement(BlockPlaceContext context) {
return defaultBlockState().setValue(TYPE, type).setValue(WATERLOGGED, isWaterlogged);
}
+ public BlockState getStateForPlacement(BlockGetter level, BlockPos pos, Direction direction) {
+ BlockState state = level.getBlockState(pos);
+ boolean isWaterlogged = level.getFluidState(pos).getType() == Fluids.WATER;
+
+ if (state.is(this) && state.getValue(TYPE) != DirectionalSlabType.FULL) {
+ return defaultBlockState().setValue(TYPE, DirectionalSlabType.FULL).setValue(WATERLOGGED, false);
+ }
+
+ DirectionalSlabType type = DirectionalSlabType.getHalfFrom(direction);
+
+ return defaultBlockState().setValue(TYPE, type).setValue(WATERLOGGED, isWaterlogged);
+ }
+
@Override
public boolean canBeReplaced(BlockState state, BlockPlaceContext useContext) {
ItemStack stack = useContext.getItemInHand();
diff --git a/src/main/java/com/github/elenterius/biomancy/block/MembraneBlock.java b/src/main/java/com/github/elenterius/biomancy/block/MembraneBlock.java
index 980aae6c6..b3ba09921 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/MembraneBlock.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/MembraneBlock.java
@@ -1,10 +1,12 @@
package com.github.elenterius.biomancy.block;
+import com.github.elenterius.biomancy.init.tags.ModEntityTags;
import net.minecraft.core.BlockPos;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
+import net.minecraft.world.entity.MobType;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
@@ -73,6 +75,8 @@ public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPo
public interface IgnoreEntityCollisionPredicate {
IgnoreEntityCollisionPredicate IS_BABY_MOB = (state, level, pos, entity) -> entity instanceof LivingEntity livingEntity && livingEntity.isBaby();
IgnoreEntityCollisionPredicate IS_ADULT_MOB = (state, level, pos, entity) -> entity instanceof LivingEntity livingEntity && !livingEntity.isBaby();
+ IgnoreEntityCollisionPredicate IS_ALIVE_MOB = (state, level, pos, entity) -> entity instanceof LivingEntity livingEntity && !entity.getType().is(ModEntityTags.FORGE_GOLEMS) && livingEntity.getMobType() != MobType.UNDEAD;
+ IgnoreEntityCollisionPredicate IS_UNDEAD_MOB = (state, level, pos, entity) -> entity instanceof LivingEntity livingEntity && livingEntity.getMobType() == MobType.UNDEAD;
IgnoreEntityCollisionPredicate IS_ITEM = (state, level, pos, entity) -> entity instanceof ItemEntity;
IgnoreEntityCollisionPredicate NEVER = (state, level, pos, entity) -> false;
diff --git a/src/main/java/com/github/elenterius/biomancy/block/SpreadingMembraneBlock.java b/src/main/java/com/github/elenterius/biomancy/block/SpreadingMembraneBlock.java
new file mode 100644
index 000000000..4cc8319a3
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/block/SpreadingMembraneBlock.java
@@ -0,0 +1,49 @@
+package com.github.elenterius.biomancy.block;
+
+import com.github.elenterius.biomancy.block.cradle.PrimalEnergyHandler;
+import com.github.elenterius.biomancy.world.PrimordialEcosystem;
+import com.github.elenterius.biomancy.world.mound.MoundShape;
+import com.github.elenterius.biomancy.world.spatial.SpatialShapeManager;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.util.RandomSource;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.state.BlockState;
+
+public class SpreadingMembraneBlock extends MembraneBlock {
+
+ public SpreadingMembraneBlock(Properties properties, IgnoreEntityCollisionPredicate predicate) {
+ super(properties.randomTicks(), predicate);
+ }
+
+ @Override
+ public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
+ if (level.random.nextFloat() >= 0.5f) return;
+ if (!level.isAreaLoaded(pos, 2)) return;
+
+ BlockPos targetPos = pos.relative(Direction.getRandom(random));
+ BlockState stateAtTargetPos = level.getBlockState(targetPos);
+ if (!stateAtTargetPos.isAir() && !PrimordialEcosystem.isReplaceable(stateAtTargetPos)) return;
+
+ // boolean hasInvalidNeighborAtTargetPos = Direction.stream()
+ // .map(targetPos::relative)
+ // .filter(neighborPos -> !neighborPos.equals(pos))
+ // .anyMatch(neighborPos -> PrimordialEcosystem.isReplaceable(level.getBlockState(neighborPos)));
+ //
+ // if (hasInvalidNeighborAtTargetPos) return;
+
+ if (SpatialShapeManager.getClosestShape(level, pos, MoundShape.class::isInstance) instanceof MoundShape mound) {
+ BlockEntity blockEntity = level.getExistingBlockEntity(mound.getOrigin());
+ if (blockEntity instanceof PrimalEnergyHandler energyHandler && !mound.hasChamberAt(targetPos)) {
+
+ boolean isNeighborNextToAnyChamber = Direction.stream().anyMatch(direction -> mound.hasChamberAt(targetPos.relative(direction)));
+
+ if (isNeighborNextToAnyChamber && energyHandler.drainPrimalEnergy(5) > 0) {
+ level.setBlock(targetPos, defaultBlockState(), UPDATE_CLIENTS);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/elenterius/biomancy/block/bioforge/BioForgeBlock.java b/src/main/java/com/github/elenterius/biomancy/block/bioforge/BioForgeBlock.java
index 9da85a3b7..57020c7f0 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/bioforge/BioForgeBlock.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/bioforge/BioForgeBlock.java
@@ -1,10 +1,10 @@
package com.github.elenterius.biomancy.block.bioforge;
-import com.github.elenterius.biomancy.chat.ComponentUtil;
import com.github.elenterius.biomancy.client.util.ClientTextUtil;
import com.github.elenterius.biomancy.init.ModBlockEntities;
import com.github.elenterius.biomancy.init.ModSoundEvents;
import com.github.elenterius.biomancy.styles.TextStyles;
+import com.github.elenterius.biomancy.util.ComponentUtil;
import com.github.elenterius.biomancy.util.SoundUtil;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
@@ -15,6 +15,8 @@
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
+import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
@@ -111,6 +113,11 @@ public void onRemove(BlockState state, Level level, BlockPos pos, BlockState new
}
}
+ @Override
+ public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
+ entity.causeFallDamage(fallDistance, 0.5f, DamageSource.FALL);
+ }
+
@Override
public RenderShape getRenderShape(BlockState state) {
return RenderShape.ENTITYBLOCK_ANIMATED;
diff --git a/src/main/java/com/github/elenterius/biomancy/block/biolab/BioLabBlock.java b/src/main/java/com/github/elenterius/biomancy/block/biolab/BioLabBlock.java
index 6a521b121..13db22297 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/biolab/BioLabBlock.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/biolab/BioLabBlock.java
@@ -2,11 +2,11 @@
import com.github.elenterius.biomancy.block.HorizontalFacingMachineBlock;
import com.github.elenterius.biomancy.block.entity.MachineBlockEntity;
-import com.github.elenterius.biomancy.chat.ComponentUtil;
import com.github.elenterius.biomancy.client.util.ClientTextUtil;
import com.github.elenterius.biomancy.init.ModBlockEntities;
import com.github.elenterius.biomancy.init.ModSoundEvents;
import com.github.elenterius.biomancy.styles.TextStyles;
+import com.github.elenterius.biomancy.util.ComponentUtil;
import com.github.elenterius.biomancy.util.SoundUtil;
import com.github.elenterius.biomancy.util.VoxelShapeUtil;
import net.minecraft.ChatFormatting;
diff --git a/src/main/java/com/github/elenterius/biomancy/block/biolab/BioLabBlockEntity.java b/src/main/java/com/github/elenterius/biomancy/block/biolab/BioLabBlockEntity.java
index 15dc839cd..c9e55de1d 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/biolab/BioLabBlockEntity.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/biolab/BioLabBlockEntity.java
@@ -3,6 +3,9 @@
import com.github.elenterius.biomancy.block.MachineBlock;
import com.github.elenterius.biomancy.block.entity.MachineBlockEntity;
import com.github.elenterius.biomancy.client.util.ClientLoopingSoundHelper;
+import com.github.elenterius.biomancy.crafting.recipe.BioLabRecipe;
+import com.github.elenterius.biomancy.crafting.recipe.IngredientStack;
+import com.github.elenterius.biomancy.crafting.recipe.SimpleRecipeType;
import com.github.elenterius.biomancy.init.ModBlockEntities;
import com.github.elenterius.biomancy.init.ModCapabilities;
import com.github.elenterius.biomancy.init.ModRecipes;
@@ -11,9 +14,6 @@
import com.github.elenterius.biomancy.inventory.SimpleInventory;
import com.github.elenterius.biomancy.inventory.itemhandler.HandlerBehaviors;
import com.github.elenterius.biomancy.menu.BioLabMenu;
-import com.github.elenterius.biomancy.recipe.BioLabRecipe;
-import com.github.elenterius.biomancy.recipe.IngredientStack;
-import com.github.elenterius.biomancy.recipe.SimpleRecipeType;
import com.github.elenterius.biomancy.styles.TextComponentUtil;
import com.github.elenterius.biomancy.util.ILoopingSoundHelper;
import com.github.elenterius.biomancy.util.SoundUtil;
diff --git a/src/main/java/com/github/elenterius/biomancy/block/biolab/BioLabStateData.java b/src/main/java/com/github/elenterius/biomancy/block/biolab/BioLabStateData.java
index 77bd80490..362757d1c 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/biolab/BioLabStateData.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/biolab/BioLabStateData.java
@@ -1,16 +1,13 @@
package com.github.elenterius.biomancy.block.biolab;
-import com.github.elenterius.biomancy.block.state.RecipeCraftingStateData;
-import com.github.elenterius.biomancy.recipe.BioLabRecipe;
+import com.github.elenterius.biomancy.crafting.recipe.BioLabRecipe;
+import com.github.elenterius.biomancy.crafting.state.FuelConsumingRecipeCraftingStateData;
import com.github.elenterius.biomancy.util.fuel.IFuelHandler;
-public class BioLabStateData extends RecipeCraftingStateData {
-
- public static final int FUEL_INDEX = 2;
- public final IFuelHandler fuelHandler;
+public class BioLabStateData extends FuelConsumingRecipeCraftingStateData {
public BioLabStateData(IFuelHandler fuelHandler) {
- this.fuelHandler = fuelHandler;
+ super(fuelHandler);
}
@Override
@@ -18,31 +15,4 @@ protected Class getRecipeType() {
return BioLabRecipe.class;
}
- @Override
- public int getFuelCost() {
- return fuelHandler.getFuelCost(timeForCompletion);
- }
-
- @Override
- public int get(int index) {
- validateIndex(index);
- if (index == TIME_INDEX) return timeElapsed;
- else if (index == TIME_FOR_COMPLETION_INDEX) return timeForCompletion;
- else if (index == FUEL_INDEX) return fuelHandler.getFuelAmount();
- return 0;
- }
-
- @Override
- public void set(int index, int value) {
- validateIndex(index);
- if (index == TIME_INDEX) timeElapsed = value;
- else if (index == TIME_FOR_COMPLETION_INDEX) timeForCompletion = value;
- else if (index == FUEL_INDEX) fuelHandler.setFuelAmount(value);
- }
-
- @Override
- public int getCount() {
- return 3;
- }
-
}
diff --git a/src/main/java/com/github/elenterius/biomancy/block/cradle/PrimalEnergyHandler.java b/src/main/java/com/github/elenterius/biomancy/block/cradle/PrimalEnergyHandler.java
new file mode 100644
index 000000000..ebc979b80
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/block/cradle/PrimalEnergyHandler.java
@@ -0,0 +1,19 @@
+package com.github.elenterius.biomancy.block.cradle;
+
+public interface PrimalEnergyHandler {
+
+ int getPrimalEnergy();
+
+ /**
+ * @param amount
+ * @return the amount that was successfully filled
+ */
+ int fillPrimalEnergy(int amount);
+
+ /**
+ * @param amount
+ * @return the amount that was successfully drained
+ */
+ int drainPrimalEnergy(int amount);
+
+}
diff --git a/src/main/java/com/github/elenterius/biomancy/block/cradle/PrimordialCradleBlock.java b/src/main/java/com/github/elenterius/biomancy/block/cradle/PrimordialCradleBlock.java
index fda63e315..9c48601f3 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/cradle/PrimordialCradleBlock.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/cradle/PrimordialCradleBlock.java
@@ -1,14 +1,23 @@
package com.github.elenterius.biomancy.block.cradle;
import com.github.elenterius.biomancy.block.fleshkinchest.FleshkinChestBlock;
+import com.github.elenterius.biomancy.block.storagesac.StorageSacBlock;
+import com.github.elenterius.biomancy.client.util.ClientTextUtil;
import com.github.elenterius.biomancy.init.ModBlockEntities;
import com.github.elenterius.biomancy.init.ModItems;
import com.github.elenterius.biomancy.init.ModSoundEvents;
import com.github.elenterius.biomancy.init.ModTriggers;
+import com.github.elenterius.biomancy.init.tags.ModItemTags;
import com.github.elenterius.biomancy.integration.ModsCompatHandler;
+import com.github.elenterius.biomancy.styles.TextStyles;
+import com.github.elenterius.biomancy.util.ComponentUtil;
import com.github.elenterius.biomancy.util.SoundUtil;
+import com.github.elenterius.biomancy.world.spatial.SpatialShapeManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleTypes;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
@@ -33,23 +42,28 @@
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
-import net.minecraftforge.common.Tags;
import net.minecraftforge.items.ItemHandlerHelper;
import org.jetbrains.annotations.Nullable;
+import java.text.DecimalFormat;
+import java.util.List;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class PrimordialCradleBlock extends HorizontalDirectionalBlock implements EntityBlock {
- public static final Predicate EXPENSIVE_ITEMS = stack -> {
- if (stack.is(Tags.Items.TOOLS)) return true;
+ public static final Predicate CANNOT_BE_SACRIFICED = stack -> {
+ if (stack.is(ModItemTags.CANNOT_BE_EATEN_BY_CRADLE)) return true;
Item item = stack.getItem();
- if (item instanceof BlockItem blockItem && (blockItem.getBlock() instanceof ShulkerBoxBlock || blockItem.getBlock() instanceof FleshkinChestBlock))
- return true;
+ if (item instanceof BlockItem blockItem) {
+ Block block = blockItem.getBlock();
+ if (block instanceof ShulkerBoxBlock || block instanceof FleshkinChestBlock || block instanceof StorageSacBlock) {
+ return true;
+ }
+ }
if (ModsCompatHandler.getTetraHelper().isToolOrModularItem(item)) return true;
@@ -78,6 +92,10 @@ protected static BlockEntityTicke
return targetType == blockEntityType ? (BlockEntityTicker) entityTicker : null;
}
+ public static int getPrimalEnergy(CompoundTag tag) {
+ return tag.contains(PrimordialCradleBlockEntity.PRIMAL_ENERGY_KEY) ? tag.getInt(PrimordialCradleBlockEntity.PRIMAL_ENERGY_KEY) : 0;
+ }
+
@Override
protected void createBlockStateDefinition(StateDefinition.Builder builder) {
builder.add(FACING);
@@ -95,6 +113,16 @@ public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return ModBlockEntities.PRIMORDIAL_CRADLE.get().create(pos, state);
}
+ @Override
+ public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!state.is(newState.getBlock())) {
+ if (level instanceof ServerLevel serverLevel) {
+ SpatialShapeManager.remove(serverLevel, pos); //removes mound shape from level
+ }
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ }
+
@Nullable
@Override
public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType blockEntityType) {
@@ -158,7 +186,7 @@ else if (stack.getItem() instanceof PotionItem) {
private boolean increaseFillLevel(@Nullable Player player, Level level, BlockPos pos, ItemStack stack) {
if (!stack.isEmpty() && !level.isClientSide()) {
- if (EXPENSIVE_ITEMS.test(stack)) return false;
+ if (CANNOT_BE_SACRIFICED.test(stack)) return false;
ItemStack copyOfStack = ItemHandlerHelper.copyStackWithSize(stack, 1); //creator#insertItem modifies the stack which may lead to it being empty
if (level.getBlockEntity(pos) instanceof PrimordialCradleBlockEntity creator && !creator.isFull() && creator.insertItem(stack)) {
@@ -200,4 +228,47 @@ public void animateTick(BlockState state, Level level, BlockPos pos, RandomSourc
}
}
+ @Override
+ public void appendHoverText(ItemStack stack, @Nullable BlockGetter level, List tooltip, TooltipFlag flag) {
+ CompoundTag tag = BlockItem.getBlockEntityData(stack);
+ if (tag == null) return;
+
+ tooltip.add(ComponentUtil.emptyLine());
+
+ DecimalFormat df = ClientTextUtil.getDecimalFormatter("#,###,###");
+
+ int primalEnergy = getPrimalEnergy(tag);
+ if (primalEnergy > 0) {
+ tooltip.add(
+ ComponentUtil.literal(df.format(primalEnergy))
+ .withStyle(TextStyles.PRIMORDIAL_RUNES_LIGHT_GRAY)
+ .append(ComponentUtil.space())
+ .append(ComponentUtil.translatable("tooltip.biomancy.primal_energy").withStyle(TextStyles.GRAY))
+ );
+ }
+
+ if (tag.contains(PrimordialCradleBlockEntity.SACRIFICE_KEY)) {
+ CompoundTag sacrificeTag = tag.getCompound(PrimordialCradleBlockEntity.SACRIFICE_KEY);
+ byte biomass = sacrificeTag.getByte("Biomass");
+ int lifeEnergy = sacrificeTag.getInt("LifeEnergy");
+ int success = sacrificeTag.getInt("Success");
+ int disease = sacrificeTag.getInt("Disease");
+ int hostile = sacrificeTag.getInt("Hostile");
+ int anomaly = sacrificeTag.getInt("Anomaly");
+
+ if (biomass > 0) tooltip.add(createValueComponent(df, biomass, "Biomass"));
+ if (lifeEnergy > 0) tooltip.add(createValueComponent(df, lifeEnergy, "Life Energy"));
+ if (success > 0) tooltip.add(createValueComponent(df, success, "Success"));
+ if (disease > 0) tooltip.add(createValueComponent(df, disease, "Disease"));
+ if (hostile > 0) tooltip.add(createValueComponent(df, hostile, "Hostile"));
+ if (anomaly > 0) tooltip.add(createValueComponent(df, anomaly, "Anomaly"));
+ }
+ }
+
+ private static MutableComponent createValueComponent(DecimalFormat df, int value, String name) {
+ return ComponentUtil.literal(df.format(value))
+ .withStyle(TextStyles.PRIMORDIAL_RUNES_LIGHT_GRAY)
+ .append(ComponentUtil.space())
+ .append(ComponentUtil.literal(name).withStyle(TextStyles.GRAY));
+ }
}
diff --git a/src/main/java/com/github/elenterius/biomancy/block/cradle/PrimordialCradleBlockEntity.java b/src/main/java/com/github/elenterius/biomancy/block/cradle/PrimordialCradleBlockEntity.java
index 81c30c1f2..2d0a45b2b 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/cradle/PrimordialCradleBlockEntity.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/cradle/PrimordialCradleBlockEntity.java
@@ -1,12 +1,20 @@
package com.github.elenterius.biomancy.block.cradle;
+import com.github.elenterius.biomancy.BiomancyConfig;
import com.github.elenterius.biomancy.block.entity.SimpleSyncedBlockEntity;
+import com.github.elenterius.biomancy.config.PrimalEnergySettings;
import com.github.elenterius.biomancy.entity.fleshblob.FleshBlob;
import com.github.elenterius.biomancy.init.*;
import com.github.elenterius.biomancy.network.ISyncableAnimation;
import com.github.elenterius.biomancy.network.ModNetworkHandler;
+import com.github.elenterius.biomancy.tribute.Tribute;
import com.github.elenterius.biomancy.util.SoundUtil;
import com.github.elenterius.biomancy.world.PrimordialEcosystem;
+import com.github.elenterius.biomancy.world.mound.MoundGenerator;
+import com.github.elenterius.biomancy.world.mound.MoundShape;
+import com.github.elenterius.biomancy.world.spatial.SpatialShapeManager;
+import com.github.elenterius.biomancy.world.spatial.geometry.Shape;
+import com.google.common.math.IntMath;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
@@ -23,6 +31,7 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
+import org.jetbrains.annotations.Nullable;
import software.bernie.geckolib3.core.AnimationState;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.core.PlayState;
@@ -35,19 +44,23 @@
import java.util.List;
-public class PrimordialCradleBlockEntity extends SimpleSyncedBlockEntity implements IAnimatable, ISyncableAnimation {
+public class PrimordialCradleBlockEntity extends SimpleSyncedBlockEntity implements PrimalEnergyHandler, IAnimatable, ISyncableAnimation {
- public static final int DURATION_TICKS = 20 * 4;
public static final String SACRIFICE_SYNC_KEY = "SyncSacrificeHandler";
public static final String SACRIFICE_KEY = "SacrificeHandler";
- public static final String PRIMAL_SPREAD_CHARGE_KEY = "PrimalSpreadCharge";
+ public static final String PRIMAL_ENERGY_KEY = "PrimalEnergy";
+ public static final String PROC_GEN_VALUES_KEY = "ProcGenValues";
+
+ public static final int DURATION_TICKS = 20 * 4;
+
protected static final AnimationBuilder IDLE_ANIM = new AnimationBuilder().addAnimation("cradle.idle");
protected static final AnimationBuilder SPIKE_ANIM = new AnimationBuilder().addAnimation("cradle.spike");
private final AnimationFactory animationFactory = GeckoLibUtil.createFactory(this);
private final SacrificeHandler sacrificeHandler = new SacrificeHandler();
private boolean playAttackAnimation = false;
private long ticks;
- private int primalSpreadCharge;
+ private int primalEnergy;
+ private @Nullable MoundShape.ProcGenValues procGenValues;
public PrimordialCradleBlockEntity(BlockPos pos, BlockState state) {
super(ModBlockEntities.PRIMORDIAL_CRADLE.get(), pos, state);
@@ -63,6 +76,27 @@ public static void serverTick(Level level, BlockPos pos, BlockState state, Primo
}
}
+ @Override
+ public void onLoad() {
+ super.onLoad();
+ if (level instanceof ServerLevel serverLevel) {
+ Shape shape = SpatialShapeManager.getOrCreateShape(serverLevel, worldPosition, () -> {
+ if (procGenValues != null) {
+ return MoundGenerator.constructShape(worldPosition, procGenValues);
+ }
+ return MoundGenerator.constructShape(level, worldPosition, level.random.nextLong());
+ });
+
+ if (shape instanceof MoundShape moundShape) {
+ MoundShape.ProcGenValues values = moundShape.getProcGenValues();
+ if (!values.equals(procGenValues)) {
+ procGenValues = values;
+ setChangedSilent();
+ }
+ }
+ }
+ }
+
/**
* modifies the stack
*/
@@ -77,7 +111,7 @@ public boolean insertItem(ItemStack stack) {
});
}
- private void spawnTributeParticles(ServerLevel level, ITribute tribute) {
+ private void spawnTributeParticles(ServerLevel level, Tribute tribute) {
BlockPos pos = getBlockPos();
if (tribute.successModifier() < 0) {
@@ -141,11 +175,14 @@ protected void setChangedSilent() {
public void onSacrifice(ServerLevel level) {
BlockPos pos = getBlockPos();
+
+ float energyMultiplier = sacrificeHandler.getLifeEnergyPct();
+
if (level.random.nextFloat() < sacrificeHandler.getSuccessChance()) {
if (level.random.nextFloat() < sacrificeHandler.getAnomalyChance()) {
spawnPrimordialFleshBlob(level, pos, sacrificeHandler);
- primalSpreadCharge += 2048;
+ addPrimalEnergy(Math.round(4096 * energyMultiplier));
SoundUtil.broadcastBlockSound(level, pos, SoundEvents.FOX_SCREECH, 2f, 0.5f);
}
else {
@@ -156,11 +193,11 @@ public void onSacrifice(ServerLevel level) {
spawnFleshBlob(level, pos, sacrificeHandler);
}
- primalSpreadCharge += 512;
+ addPrimalEnergy(Math.round(2048 * energyMultiplier));
SoundUtil.broadcastBlockSound(level, pos, ModSoundEvents.CREATOR_SPAWN_MOB);
}
- if (level.random.nextFloat() >= sacrificeHandler.getTumorFactor() / 2) {
+ if (level.random.nextFloat() >= sacrificeHandler.getTumorFactor() / 3) {
PrimordialEcosystem.tryToReplaceBlock(level, pos.below(), ModBlocks.PRIMAL_FLESH.get().defaultBlockState());
}
@@ -172,22 +209,58 @@ public void onSacrifice(ServerLevel level) {
if (!PrimordialEcosystem.spreadMalignantVeinsFromSource(level, pos, PrimordialEcosystem.MAX_CHARGE_SUPPLIER)) {
PrimordialEcosystem.tryToReplaceBlock(level, pos.below(), ModBlocks.PRIMAL_FLESH.get().defaultBlockState());
}
-
- primalSpreadCharge += 1024;
+ addPrimalEnergy(Math.round(3072 * energyMultiplier));
SoundUtil.broadcastBlockSound(level, pos, ModSoundEvents.FLESH_BLOCK_STEP.get(), 1f, 0.15f + level.random.nextFloat() * 0.5f);
}
resetState();
}
- public boolean consumePrimalSpreadCharge(ServerLevel level, int amount) {
- if (amount <= 0) return false;
- if (primalSpreadCharge < amount) return false;
+ @Override
+ public int getPrimalEnergy() {
+ PrimalEnergySettings.SupplyAmount supplyAmount = BiomancyConfig.SERVER.primalEnergySupplyOfCradle.get();
+ if (supplyAmount == PrimalEnergySettings.SupplyAmount.UNLIMITED) return Integer.MAX_VALUE;
+ if (supplyAmount == PrimalEnergySettings.SupplyAmount.NONE) return 0;
+
+ return primalEnergy;
+ }
- primalSpreadCharge -= amount;
+ private void addPrimalEnergy(int amount) {
+ primalEnergy = IntMath.saturatedAdd(primalEnergy, amount);
+ }
+
+ @Override
+ public int fillPrimalEnergy(int amount) {
+ if (amount <= 0) return 0;
+
+ int prevPrimalEnergy = primalEnergy;
+ primalEnergy = IntMath.saturatedAdd(primalEnergy, amount);
+ int filled = primalEnergy - prevPrimalEnergy;
+
+ setChanged();
+
+ return filled;
+ }
+
+ @Override
+ public int drainPrimalEnergy(int amount) {
+ if (amount <= 0) return 0;
+
+ PrimalEnergySettings.SupplyAmount supplyAmount = BiomancyConfig.SERVER.primalEnergySupplyOfCradle.get();
+ if (supplyAmount == PrimalEnergySettings.SupplyAmount.UNLIMITED) return amount;
+ if (supplyAmount == PrimalEnergySettings.SupplyAmount.NONE) return 0;
+
+ if (primalEnergy < amount) {
+ int prevPrimalEnergy = primalEnergy;
+ primalEnergy = 0;
+ setChanged();
+ return prevPrimalEnergy;
+ }
+
+ primalEnergy -= amount;
setChanged();
- return true;
+ return amount;
}
public void spawnPrimordialFleshBlob(ServerLevel level, BlockPos pos, SacrificeHandler sacrificeHandler) {
@@ -256,7 +329,13 @@ protected void attackAOE(ServerLevel level, BlockPos pos) {
protected void saveAdditional(CompoundTag tag) {
super.saveAdditional(tag);
tag.put(SACRIFICE_KEY, sacrificeHandler.serializeNBT());
- tag.putInt(PRIMAL_SPREAD_CHARGE_KEY, primalSpreadCharge);
+ tag.putInt(PRIMAL_ENERGY_KEY, primalEnergy);
+
+ if (procGenValues != null) {
+ CompoundTag tagProcGen = new CompoundTag();
+ procGenValues.writeTo(tagProcGen);
+ tag.put(PROC_GEN_VALUES_KEY, tagProcGen);
+ }
}
@Override
@@ -274,7 +353,11 @@ else if (tag.contains(SACRIFICE_SYNC_KEY)) {
sacrificeHandler.deserializeNBT(tag.getCompound(SACRIFICE_SYNC_KEY));
}
- primalSpreadCharge = tag.getInt(PRIMAL_SPREAD_CHARGE_KEY);
+ primalEnergy = tag.getInt(PRIMAL_ENERGY_KEY);
+
+ if (tag.contains(PROC_GEN_VALUES_KEY)) {
+ procGenValues = MoundShape.ProcGenValues.readFrom(tag.getCompound(PROC_GEN_VALUES_KEY));
+ }
}
@Override
diff --git a/src/main/java/com/github/elenterius/biomancy/block/cradle/SacrificeHandler.java b/src/main/java/com/github/elenterius/biomancy/block/cradle/SacrificeHandler.java
index bbf194dc5..389875945 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/cradle/SacrificeHandler.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/cradle/SacrificeHandler.java
@@ -1,5 +1,8 @@
package com.github.elenterius.biomancy.block.cradle;
+import com.github.elenterius.biomancy.tribute.Tribute;
+import com.github.elenterius.biomancy.tribute.Tributes;
+import com.google.common.math.IntMath;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack;
@@ -9,10 +12,10 @@
public class SacrificeHandler implements INBTSerializable {
- private static final int MAX_VALUE = 100;
+ private static final int MAX_BIOMASS_VALUE = 100;
private byte biomass;
- private byte lifeEnergy;
+ private int lifeEnergy;
private int successValue;
private int diseaseValue;
private int hostileValue;
@@ -37,11 +40,11 @@ public void reset() {
}
public boolean isFull() {
- return lifeEnergy >= MAX_VALUE && biomass >= MAX_VALUE;
+ return lifeEnergy >= MAX_BIOMASS_VALUE && biomass >= MAX_BIOMASS_VALUE;
}
public void setBiomass(int amount) {
- biomass = (byte) Mth.clamp(amount, 0, MAX_VALUE);
+ biomass = (byte) Mth.clamp(amount, 0, MAX_BIOMASS_VALUE);
}
public boolean addBiomass(int amount) {
@@ -52,7 +55,7 @@ public boolean addBiomass(int amount) {
return true;
}
- if (amount > 0 && biomass < MAX_VALUE) {
+ if (amount > 0 && biomass < MAX_BIOMASS_VALUE) {
setBiomass(biomass + amount);
return true;
}
@@ -65,11 +68,11 @@ public int getBiomassAmount() {
}
public float getBiomassPct() {
- return biomass / (float) MAX_VALUE;
+ return biomass / 100f;
}
public void setLifeEnergy(int amount) {
- lifeEnergy = (byte) Mth.clamp(amount, 0, MAX_VALUE);
+ lifeEnergy = Mth.clamp(amount, 0, Integer.MAX_VALUE);
}
public boolean addLifeEnergy(int amount) {
@@ -80,8 +83,8 @@ public boolean addLifeEnergy(int amount) {
return true;
}
- if (amount > 0 && lifeEnergy < MAX_VALUE) {
- setLifeEnergy(lifeEnergy + amount);
+ if (amount > 0) {
+ setLifeEnergy(IntMath.saturatedAdd(lifeEnergy, amount));
return true;
}
@@ -93,7 +96,7 @@ public int getLifeEnergyAmount() {
}
public float getLifeEnergyPct() {
- return lifeEnergy / (float) MAX_VALUE;
+ return lifeEnergy / 100f;
}
public float getSuccessChance() {
@@ -116,11 +119,11 @@ public boolean hasModifiers() {
return hasModifiers;
}
- public boolean addItem(ItemStack stack, Consumer onSuccess) {
+ public boolean addItem(ItemStack stack, Consumer onSuccess) {
if (isFull()) return false;
if (stack.isEmpty()) return false;
- ITribute tribute = Tributes.from(stack);
+ Tribute tribute = Tributes.from(stack);
int count = addTribute(tribute, stack.getCount());
if (count > 0) {
stack.shrink(count);
@@ -144,13 +147,13 @@ public boolean addItem(ItemStack stack) {
return false;
}
- private int addTribute(ITribute tribute, int maxCount) {
+ private int addTribute(Tribute tribute, int maxCount) {
int n = maxCount;
while (n > 0 && addTribute(tribute)) n--;
return maxCount - n;
}
- public boolean addTribute(ITribute tribute) {
+ public boolean addTribute(Tribute tribute) {
if (isFull()) return false;
if (tribute.isEmpty()) return false;
@@ -182,7 +185,7 @@ public boolean addTribute(ITribute tribute) {
public CompoundTag serializeNBT() {
CompoundTag tag = new CompoundTag();
tag.putByte("Biomass", biomass);
- tag.putByte("LifeEnergy", lifeEnergy);
+ tag.putInt("LifeEnergy", lifeEnergy);
tag.putInt("Success", successValue);
@@ -197,7 +200,7 @@ public CompoundTag serializeNBT() {
@Override
public void deserializeNBT(CompoundTag tag) {
biomass = tag.getByte("Biomass");
- lifeEnergy = tag.getByte("LifeEnergy");
+ lifeEnergy = tag.getInt("LifeEnergy");
successValue = tag.getInt("Success");
diff --git a/src/main/java/com/github/elenterius/biomancy/block/cradle/Tributes.java b/src/main/java/com/github/elenterius/biomancy/block/cradle/Tributes.java
deleted file mode 100644
index 24108c08c..000000000
--- a/src/main/java/com/github/elenterius/biomancy/block/cradle/Tributes.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.github.elenterius.biomancy.block.cradle;
-
-import com.github.elenterius.biomancy.init.ModItems;
-import com.github.elenterius.biomancy.init.tags.ModItemTags;
-import com.google.common.collect.ImmutableMap;
-import net.minecraft.world.item.Item;
-import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.Items;
-import net.minecraftforge.common.Tags;
-
-import java.util.List;
-import java.util.Map;
-import java.util.function.Predicate;
-
-final class Tributes {
-
- static final Map
- ITEM_MAP = new ImmutableMap.Builder
- ()
- .put(ModItems.CREATOR_MIX.get(), Tribute.builder().biomass(20).lifeEnergy(20).successModifier(19).diseaseModifier(6).hostileModifier(-12).create())
- .put(ModItems.PRIMORDIAL_CORE.get(), Tribute.builder().biomass(80).successModifier(64).anomalyModifier(100).diseaseModifier(50).create())
- .put(ModItems.LIVING_FLESH.get(), Tribute.builder().biomass(10).lifeEnergy(10).successModifier(40).anomalyModifier(55).create())
- .put(Items.GOLDEN_APPLE, Tribute.builder().successModifier(10).hostileModifier(-100).create())
- .put(Items.ENCHANTED_GOLDEN_APPLE, Tribute.builder().lifeEnergy(15).successModifier(40).hostileModifier(-200).create())
- .put(Items.CAKE, Tribute.builder().hostileModifier(-80).diseaseModifier(10).create())
-
- .put(ModItems.HEALING_ADDITIVE.get(), Tribute.builder().lifeEnergy(50).successModifier(1).diseaseModifier(-5).hostileModifier(-10).create())
- .put(ModItems.REGENERATIVE_FLUID.get(), Tribute.builder().lifeEnergy(5).hostileModifier(-1).create())
-
- .put(Items.ROTTEN_FLESH, Tribute.builder().biomass(10).successModifier(-10).diseaseModifier(20).create())
- .put(ModItems.MOB_SINEW.get(), Tribute.builder().biomass(5).successModifier(2).hostileModifier(-2).create())
- .put(ModItems.FLESH_BITS.get(), Tribute.builder().biomass(5).successModifier(2).hostileModifier(-2).create())
-
- .put(Items.RABBIT_FOOT, Tribute.builder().successModifier(1000).hostileModifier(-50).anomalyModifier(50).create())
- .put(Items.SPIDER_EYE, Tribute.builder().successModifier(10).diseaseModifier(10).hostileModifier(-5).create())
- .put(Items.FERMENTED_SPIDER_EYE, Tribute.builder().successModifier(-10).hostileModifier(-10).create())
- .put(ModItems.TOXIN_GLAND.get(), Tribute.builder().successModifier(-5).diseaseModifier(50).create())
- .put(ModItems.VOLATILE_GLAND.get(), Tribute.builder().successModifier(-5).diseaseModifier(20).create())
- .put(ModItems.GENERIC_MOB_GLAND.get(), Tribute.builder().diseaseModifier(-5).hostileModifier(-20).create())
- .put(Items.BONE, Tribute.builder().successModifier(3).diseaseModifier(-10).create())
- .put(Items.BONE_MEAL, Tribute.builder().successModifier(1).diseaseModifier(-1).create())
- .put(ModItems.MOB_MARROW.get(), Tribute.builder().successModifier(5).diseaseModifier(-20).hostileModifier(-10).create())
- .put(ModItems.WITHERED_MOB_MARROW.get(), Tribute.builder().successModifier(-30).diseaseModifier(-40).create())
- .put(ModItems.MOB_FANG.get(), Tribute.builder().successModifier(5).hostileModifier(5).create())
- .put(ModItems.MOB_CLAW.get(), Tribute.builder().successModifier(5).hostileModifier(5).create())
- .put(Items.ENDER_PEARL, Tribute.builder().hostileModifier(50).anomalyModifier(50).create())
-
- .put(ModItems.ELASTIC_FIBERS.get(), Tribute.builder().diseaseModifier(1).anomalyModifier(1).create())
- .put(ModItems.TOUGH_FIBERS.get(), Tribute.builder().diseaseModifier(1).anomalyModifier(1).create())
- .build();
-
- static final List FUZZY_TRIBUTES = List.of(
- new FuzzyTribute(stack -> stack.is(ModItemTags.RAW_MEATS), Tribute.builder().biomass(20).successModifier(16).diseaseModifier(5).hostileModifier(-5).create()),
- new FuzzyTribute(stack -> stack.is(ModItemTags.COOKED_MEATS), Tribute.builder().successModifier(-999).create()),
- new FuzzyTribute(stack -> stack.is(Tags.Items.BONES), Tribute.builder().successModifier(5).diseaseModifier(-5).create())
- );
- static final ITribute INVALID_ITEM = Tribute.builder().successModifier(-99).diseaseModifier(5).hostileModifier(20).create();
-
- private Tributes() {}
-
- static ITribute from(ItemStack stack) {
-
- MobEffectTribute mobEffectTribute = MobEffectTribute.from(stack);
- ITribute tribute = findExistingTribute(stack);
-
- if (mobEffectTribute.isEmpty() && tribute.isEmpty()) {
- return INVALID_ITEM;
- }
-
- return new Tribute(tribute, mobEffectTribute);
- }
-
- static ITribute findExistingTribute(ItemStack stack) {
- if (stack.isEmpty()) return ITribute.EMPTY;
-
- ITribute foundTribute = ITEM_MAP.get(stack.getItem());
- if (foundTribute != null) return foundTribute;
-
- for (FuzzyTribute fuzzyTribute : FUZZY_TRIBUTES) {
- if (fuzzyTribute.predicate.test(stack)) return fuzzyTribute.tribute;
- }
-
- return ITribute.EMPTY;
- }
-
- record FuzzyTribute(Predicate predicate, ITribute tribute) {}
-
-}
diff --git a/src/main/java/com/github/elenterius/biomancy/block/decomposer/DecomposerBlock.java b/src/main/java/com/github/elenterius/biomancy/block/decomposer/DecomposerBlock.java
index e50b14ed2..067aa7c47 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/decomposer/DecomposerBlock.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/decomposer/DecomposerBlock.java
@@ -2,11 +2,11 @@
import com.github.elenterius.biomancy.block.HorizontalFacingMachineBlock;
import com.github.elenterius.biomancy.block.entity.MachineBlockEntity;
-import com.github.elenterius.biomancy.chat.ComponentUtil;
import com.github.elenterius.biomancy.client.util.ClientTextUtil;
import com.github.elenterius.biomancy.init.ModBlockEntities;
import com.github.elenterius.biomancy.init.ModSoundEvents;
import com.github.elenterius.biomancy.styles.TextStyles;
+import com.github.elenterius.biomancy.util.ComponentUtil;
import com.github.elenterius.biomancy.util.SoundUtil;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
diff --git a/src/main/java/com/github/elenterius/biomancy/block/decomposer/DecomposerBlockEntity.java b/src/main/java/com/github/elenterius/biomancy/block/decomposer/DecomposerBlockEntity.java
index 6ac7c426e..a2ee09fd6 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/decomposer/DecomposerBlockEntity.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/decomposer/DecomposerBlockEntity.java
@@ -3,6 +3,9 @@
import com.github.elenterius.biomancy.block.MachineBlock;
import com.github.elenterius.biomancy.block.entity.MachineBlockEntity;
import com.github.elenterius.biomancy.client.util.ClientLoopingSoundHelper;
+import com.github.elenterius.biomancy.crafting.recipe.DecomposerRecipe;
+import com.github.elenterius.biomancy.crafting.recipe.SimpleRecipeType;
+import com.github.elenterius.biomancy.crafting.recipe.VariableProductionOutput;
import com.github.elenterius.biomancy.init.ModBlockEntities;
import com.github.elenterius.biomancy.init.ModCapabilities;
import com.github.elenterius.biomancy.init.ModRecipes;
@@ -10,9 +13,6 @@
import com.github.elenterius.biomancy.inventory.BehavioralInventory;
import com.github.elenterius.biomancy.inventory.itemhandler.HandlerBehaviors;
import com.github.elenterius.biomancy.menu.DecomposerMenu;
-import com.github.elenterius.biomancy.recipe.DecomposerRecipe;
-import com.github.elenterius.biomancy.recipe.SimpleRecipeType;
-import com.github.elenterius.biomancy.recipe.VariableProductionOutput;
import com.github.elenterius.biomancy.styles.TextComponentUtil;
import com.github.elenterius.biomancy.util.ILoopingSoundHelper;
import com.github.elenterius.biomancy.util.SoundUtil;
diff --git a/src/main/java/com/github/elenterius/biomancy/block/decomposer/DecomposerStateData.java b/src/main/java/com/github/elenterius/biomancy/block/decomposer/DecomposerStateData.java
index cc77b33b5..47f37e7a5 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/decomposer/DecomposerStateData.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/decomposer/DecomposerStateData.java
@@ -1,17 +1,13 @@
package com.github.elenterius.biomancy.block.decomposer;
-import com.github.elenterius.biomancy.block.state.RecipeCraftingStateData;
-import com.github.elenterius.biomancy.recipe.DecomposerRecipe;
+import com.github.elenterius.biomancy.crafting.recipe.DecomposerRecipe;
+import com.github.elenterius.biomancy.crafting.state.FuelConsumingRecipeCraftingStateData;
import com.github.elenterius.biomancy.util.fuel.IFuelHandler;
-public class DecomposerStateData extends RecipeCraftingStateData {
-
- public static final int FUEL_INDEX = 2;
-
- public final IFuelHandler fuelHandler;
+public class DecomposerStateData extends FuelConsumingRecipeCraftingStateData {
public DecomposerStateData(IFuelHandler fuelHandler) {
- this.fuelHandler = fuelHandler;
+ super(fuelHandler);
}
@Override
@@ -19,36 +15,4 @@ protected Class getRecipeType() {
return DecomposerRecipe.class;
}
- @Override
- public int getFuelCost() {
- return fuelHandler.getFuelCost(timeForCompletion);
- }
-
- @Override
- public int get(int index) {
- validateIndex(index);
- return switch (index) {
- case TIME_INDEX -> timeElapsed;
- case TIME_FOR_COMPLETION_INDEX -> timeForCompletion;
- case FUEL_INDEX -> fuelHandler.getFuelAmount();
- default -> 0;
- };
- }
-
- @Override
- public void set(int index, int value) {
- validateIndex(index);
- switch (index) {
- case TIME_INDEX -> timeElapsed = value;
- case TIME_FOR_COMPLETION_INDEX -> timeForCompletion = value;
- case FUEL_INDEX -> fuelHandler.setFuelAmount(value);
- default -> throw new IllegalStateException("Unexpected value: " + index);
- }
- }
-
- @Override
- public int getCount() {
- return 3;
- }
-
}
diff --git a/src/main/java/com/github/elenterius/biomancy/block/digester/DigesterBlock.java b/src/main/java/com/github/elenterius/biomancy/block/digester/DigesterBlock.java
index 47abad31b..c5fddbc3b 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/digester/DigesterBlock.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/digester/DigesterBlock.java
@@ -2,11 +2,11 @@
import com.github.elenterius.biomancy.block.HorizontalFacingMachineBlock;
import com.github.elenterius.biomancy.block.entity.MachineBlockEntity;
-import com.github.elenterius.biomancy.chat.ComponentUtil;
import com.github.elenterius.biomancy.client.util.ClientTextUtil;
import com.github.elenterius.biomancy.init.ModBlockEntities;
import com.github.elenterius.biomancy.init.ModSoundEvents;
import com.github.elenterius.biomancy.styles.TextStyles;
+import com.github.elenterius.biomancy.util.ComponentUtil;
import com.github.elenterius.biomancy.util.SoundUtil;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
diff --git a/src/main/java/com/github/elenterius/biomancy/block/digester/DigesterBlockEntity.java b/src/main/java/com/github/elenterius/biomancy/block/digester/DigesterBlockEntity.java
index 1eb47b477..fc8f626ee 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/digester/DigesterBlockEntity.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/digester/DigesterBlockEntity.java
@@ -3,6 +3,8 @@
import com.github.elenterius.biomancy.block.MachineBlock;
import com.github.elenterius.biomancy.block.entity.MachineBlockEntity;
import com.github.elenterius.biomancy.client.util.ClientLoopingSoundHelper;
+import com.github.elenterius.biomancy.crafting.recipe.DigesterRecipe;
+import com.github.elenterius.biomancy.crafting.recipe.SimpleRecipeType;
import com.github.elenterius.biomancy.init.ModBlockEntities;
import com.github.elenterius.biomancy.init.ModCapabilities;
import com.github.elenterius.biomancy.init.ModRecipes;
@@ -10,8 +12,6 @@
import com.github.elenterius.biomancy.inventory.BehavioralInventory;
import com.github.elenterius.biomancy.inventory.itemhandler.HandlerBehaviors;
import com.github.elenterius.biomancy.menu.DigesterMenu;
-import com.github.elenterius.biomancy.recipe.DigesterRecipe;
-import com.github.elenterius.biomancy.recipe.SimpleRecipeType;
import com.github.elenterius.biomancy.styles.TextComponentUtil;
import com.github.elenterius.biomancy.util.ILoopingSoundHelper;
import com.github.elenterius.biomancy.util.SoundUtil;
diff --git a/src/main/java/com/github/elenterius/biomancy/block/digester/DigesterStateData.java b/src/main/java/com/github/elenterius/biomancy/block/digester/DigesterStateData.java
index 1d9bbdf8d..fbaa7c938 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/digester/DigesterStateData.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/digester/DigesterStateData.java
@@ -1,17 +1,13 @@
package com.github.elenterius.biomancy.block.digester;
-import com.github.elenterius.biomancy.block.state.RecipeCraftingStateData;
-import com.github.elenterius.biomancy.recipe.DigesterRecipe;
+import com.github.elenterius.biomancy.crafting.recipe.DigesterRecipe;
+import com.github.elenterius.biomancy.crafting.state.FuelConsumingRecipeCraftingStateData;
import com.github.elenterius.biomancy.util.fuel.IFuelHandler;
-public class DigesterStateData extends RecipeCraftingStateData {
-
- public static final int FUEL_AMOUNT_INDEX = 2;
-
- public final IFuelHandler fuelHandler;
+public class DigesterStateData extends FuelConsumingRecipeCraftingStateData {
public DigesterStateData(IFuelHandler fuelHandler) {
- this.fuelHandler = fuelHandler;
+ super(fuelHandler);
}
@Override
@@ -19,36 +15,4 @@ protected Class getRecipeType() {
return DigesterRecipe.class;
}
- @Override
- public int getFuelCost() {
- return fuelHandler.getFuelCost(timeForCompletion);
- }
-
- @Override
- public int get(int index) {
- validateIndex(index);
- return switch (index) {
- case TIME_INDEX -> timeElapsed;
- case TIME_FOR_COMPLETION_INDEX -> timeForCompletion;
- case FUEL_AMOUNT_INDEX -> fuelHandler.getFuelAmount();
- default -> 0;
- };
- }
-
- @Override
- public void set(int index, int value) {
- validateIndex(index);
- switch (index) {
- case TIME_INDEX -> timeElapsed = value;
- case TIME_FOR_COMPLETION_INDEX -> timeForCompletion = value;
- case FUEL_AMOUNT_INDEX -> fuelHandler.setFuelAmount(value);
- default -> throw new IllegalStateException("Unexpected value: " + index);
- }
- }
-
- @Override
- public int getCount() {
- return 3;
- }
-
}
diff --git a/src/main/java/com/github/elenterius/biomancy/block/entity/MachineBlockEntity.java b/src/main/java/com/github/elenterius/biomancy/block/entity/MachineBlockEntity.java
index 08dfc27d6..cbdd4469b 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/entity/MachineBlockEntity.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/entity/MachineBlockEntity.java
@@ -2,10 +2,10 @@
import com.github.elenterius.biomancy.BiomancyMod;
import com.github.elenterius.biomancy.block.MachineBlock;
-import com.github.elenterius.biomancy.block.state.CraftingState;
-import com.github.elenterius.biomancy.block.state.RecipeCraftingStateData;
+import com.github.elenterius.biomancy.crafting.recipe.ProcessingRecipe;
+import com.github.elenterius.biomancy.crafting.state.CraftingState;
+import com.github.elenterius.biomancy.crafting.state.RecipeCraftingStateData;
import com.github.elenterius.biomancy.init.ModBlockProperties;
-import com.github.elenterius.biomancy.recipe.ProcessingRecipe;
import com.github.elenterius.biomancy.util.fuel.IFuelHandler;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
diff --git a/src/main/java/com/github/elenterius/biomancy/block/fleshkinchest/FleshkinChestBlock.java b/src/main/java/com/github/elenterius/biomancy/block/fleshkinchest/FleshkinChestBlock.java
index ecc34bb71..9ae2223ee 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/fleshkinchest/FleshkinChestBlock.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/fleshkinchest/FleshkinChestBlock.java
@@ -1,6 +1,5 @@
package com.github.elenterius.biomancy.block.fleshkinchest;
-import com.github.elenterius.biomancy.chat.ComponentUtil;
import com.github.elenterius.biomancy.init.ModBlockEntities;
import com.github.elenterius.biomancy.init.ModSoundEvents;
import com.github.elenterius.biomancy.ownable.IOwnableEntityBlock;
@@ -8,6 +7,7 @@
import com.github.elenterius.biomancy.permission.IRestrictedInteraction;
import com.github.elenterius.biomancy.permission.UserType;
import com.github.elenterius.biomancy.styles.TextStyles;
+import com.github.elenterius.biomancy.util.ComponentUtil;
import net.minecraft.ChatFormatting;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
diff --git a/src/main/java/com/github/elenterius/biomancy/block/fleshspike/FleshSpikeBlock.java b/src/main/java/com/github/elenterius/biomancy/block/fleshspike/FleshSpikeBlock.java
index 2a8a0df48..a0f110927 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/fleshspike/FleshSpikeBlock.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/fleshspike/FleshSpikeBlock.java
@@ -3,6 +3,7 @@
import com.github.elenterius.biomancy.block.base.WaterloggedFacingBlock;
import com.github.elenterius.biomancy.init.ModBlockProperties;
import com.github.elenterius.biomancy.init.ModDamageSources;
+import com.github.elenterius.biomancy.util.EnhancedIntegerProperty;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
@@ -15,7 +16,6 @@
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
-import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.CollisionContext;
@@ -25,24 +25,22 @@
public class FleshSpikeBlock extends WaterloggedFacingBlock {
- public static final int MIN_SPIKES = 1;
- public static final int MAX_SPIKES = 3;
- public static final IntegerProperty SPIKES = ModBlockProperties.SPIKES;
+ public static final EnhancedIntegerProperty SPIKES = ModBlockProperties.SPIKES;
public FleshSpikeBlock(Properties properties) {
super(properties);
- registerDefaultState(defaultBlockState().setValue(SPIKES, MIN_SPIKES));
+ registerDefaultState(defaultBlockState().setValue(SPIKES.get(), SPIKES.getMin()));
FleshSpikeShapes.computePossibleShapes(stateDefinition.getPossibleStates());
}
public static int getSpikes(BlockState blockState) {
- return blockState.getValue(SPIKES);
+ return SPIKES.getValue(blockState);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder builder) {
super.createBlockStateDefinition(builder);
- builder.add(SPIKES);
+ builder.add(SPIKES.get());
}
@Nullable
@@ -50,7 +48,7 @@ protected void createBlockStateDefinition(StateDefinition.Builder builder) {
+ super.createBlockStateDefinition(builder);
+ builder.add(AGE.get());
+ }
+
+ public BlockState getStateForPlacement(BlockGetter level, BlockPos pos, Direction direction) {
+ boolean isWaterlogged = level.getFluidState(pos).getType() == Fluids.WATER;
+ return defaultBlockState().setValue(FACING, direction).setValue(WATERLOGGED, isWaterlogged);
+ }
+
+ public boolean hasUnobstructedAim(BlockGetter level, BlockPos pos, Direction direction) {
+ return hasUnobstructedAim(level, pos, pos.relative(direction, AIM_DISTANCE));
+ }
+
+ public boolean hasUnobstructedAim(BlockGetter level, BlockPos origin, BlockPos target) {
+ return level.clip(new ClipContext(Vec3.atCenterOf(origin), Vec3.atCenterOf(target), ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, null)).getType() == HitResult.Type.MISS;
+ }
+
+ @Override
+ public boolean isRandomlyTicking(BlockState state) {
+ return true;
+ }
+
+ @Override
+ public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
+ if (!level.isAreaLoaded(pos, 1)) return;
+
+ Direction direction = getFacing(state);
+ BlockPos relativePos = pos.relative(direction);
+ BlockState relativeState = level.getBlockState(relativePos);
+ if (relativeState.getMaterial().isSolid() || !relativeState.getCollisionShape(level, relativePos).isEmpty()) return;
+
+ int age = AGE.getValue(state);
+ if (age < AGE.getMax()) {
+ int growthSpeed = age < AGE.getMax() - 1 ? getGrowthSpeed(level, pos) : 1;
+
+ if (ForgeHooks.onCropsGrowPre(level, pos, state, random.nextInt(growthSpeed) == 0)) {
+ level.setBlock(pos, AGE.addValue(state, 1), Block.UPDATE_CLIENTS);
+ ForgeHooks.onCropsGrowPost(level, pos, state);
+ }
+ }
+ else {
+ level.sendParticles(ParticleTypes.EXPLOSION, pos.getX() + 0.5d, pos.getY() + 0.5d, pos.getZ() + 0.5d, 1, 0, 0, 0, 0);
+ level.setBlock(pos, AGE.setValue(state, AGE.getMin()), Block.UPDATE_CLIENTS);
+
+ int range = 6;
+ Vec3i plane = VectorUtil.axisAlignedPlane3i(direction);
+ int offsetX = plane.getX() * random.nextIntBetweenInclusive(-range, range);
+ int offsetY = plane.getY() * random.nextIntBetweenInclusive(-range, range);
+ int offsetZ = plane.getZ() * random.nextIntBetweenInclusive(-range, range);
+ BlockPos target = pos.relative(direction, AIM_DISTANCE).offset(offsetX, offsetY, offsetZ);
+
+ ModProjectiles.SAPBERRY.shoot(level, Vec3.atCenterOf(pos), Vec3.atCenterOf(target));
+ }
+ }
+
+ @Override
+ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
+ int age = AGE.getValue(state);
+ if (age > 5 && player.getItemInHand(hand).isEmpty()) {
+ if (!level.isClientSide) {
+ int count = 1 + (age > 6 ? level.random.nextInt(2) : 0);
+ popResource(level, pos, new ItemStack(ModItems.BLOOMBERRY.get(), count));
+
+ player.hurt(DamageSource.SWEET_BERRY_BUSH, 1f);
+
+ level.playSound(null, pos, SoundEvents.CAVE_VINES_PICK_BERRIES, SoundSource.BLOCKS, 1f, 0.5f + level.random.nextFloat() * 0.4f);
+ BlockState blockState = AGE.setValue(state, AGE.getMin());
+ level.setBlock(pos, blockState, Block.UPDATE_CLIENTS);
+ level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(player, blockState));
+ }
+
+ return InteractionResult.sidedSuccess(level.isClientSide);
+ }
+
+ return super.use(state, level, pos, player, hand, hit);
+ }
+
+ @Override
+ public BlockState getPlant(BlockGetter level, BlockPos pos) {
+ BlockState state = level.getBlockState(pos);
+ if (state.getBlock() != this) return defaultBlockState();
+ return state;
+ }
+
+ @Override
+ public PlantType getPlantType(BlockGetter level, BlockPos pos) {
+ return ModPlantTypes.FLESH_PLANT_TYPE;
+ }
+
+ @Override
+ public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos currentPos, BlockPos neighborPos) {
+ return !state.canSurvive(level, currentPos) ? Blocks.AIR.defaultBlockState() : super.updateShape(state, direction, neighborState, level, currentPos, neighborPos);
+ }
+
+ public boolean mayPlaceOn(BlockGetter level, BlockPos pos, BlockState state) {
+ return state.is(ModBlocks.PRIMAL_FLESH.get()) || state.is(ModBlocks.MALIGNANT_FLESH.get());
+ }
+
+ @Override
+ public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
+ Direction direction = state.getValue(FACING);
+ BlockPos blockPos = pos.relative(direction.getOpposite());
+
+ if (state.getBlock() == this) {
+ //world gen and placement
+ return level.getBlockState(blockPos).canSustainPlant(level, blockPos, direction, this);
+ }
+
+ return mayPlaceOn(level, blockPos, level.getBlockState(blockPos));
+ }
+
+ @Override
+ public boolean propagatesSkylightDown(BlockState state, BlockGetter level, BlockPos pos) {
+ return state.getFluidState().isEmpty();
+ }
+
+ @Override
+ public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
+ return MalignantBloomShapes.getBoundingShape(state);
+ }
+
+ @Override
+ public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
+ return hasCollision ? MalignantBloomShapes.getCollisionShape(state) : Shapes.empty();
+ }
+
+ @Override
+ public boolean isCollisionShapeFullBlock(BlockState state, BlockGetter level, BlockPos pos) {
+ return false;
+ }
+
+}
diff --git a/src/main/java/com/github/elenterius/biomancy/block/malignantbloom/MalignantBloomShapes.java b/src/main/java/com/github/elenterius/biomancy/block/malignantbloom/MalignantBloomShapes.java
new file mode 100644
index 000000000..bba50d125
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/block/malignantbloom/MalignantBloomShapes.java
@@ -0,0 +1,65 @@
+package com.github.elenterius.biomancy.block.malignantbloom;
+
+import com.github.elenterius.biomancy.util.IntermediaryKeyCache;
+import com.github.elenterius.biomancy.util.VoxelShapeUtil;
+import net.minecraft.core.Direction;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.phys.shapes.BooleanOp;
+import net.minecraft.world.phys.shapes.Shapes;
+import net.minecraft.world.phys.shapes.VoxelShape;
+
+import java.util.List;
+import java.util.Objects;
+
+public final class MalignantBloomShapes {
+
+ static final IntermediaryKeyCache CACHE = new IntermediaryKeyCache<>(MalignantBloomShapes::computeKey);
+
+ private MalignantBloomShapes() {}
+
+ static void computePossibleShapes(List possibleStates) {
+ possibleStates.forEach(possibleState -> CACHE.computeIfAbsent(possibleState, MalignantBloomShapes::computeShapes));
+ }
+
+ static VoxelShape getBoundingShape(BlockState blockState) {
+ return CACHE.get(blockState).boundingShape();
+ }
+
+ static VoxelShape getCollisionShape(BlockState blockState) {
+ return CACHE.get(blockState).collisionShape();
+ }
+
+ private static Integer computeKey(BlockState blockState) {
+ Direction direction = MalignantBloomBlock.getFacing(blockState);
+ int stage = MalignantBloomBlock.getStage(blockState);
+
+ return Objects.hash(direction, stage);
+ }
+
+ private static ComputedShapes computeShapes(BlockState blockState) {
+ Direction direction = MalignantBloomBlock.getFacing(blockState);
+
+ int stage = MalignantBloomBlock.getStage(blockState);
+
+ if (stage == 0) {
+ VoxelShape boundingShape = VoxelShapeUtil.createXZRotatedTowards(direction, 5, 0, 5, 11, 6, 11);
+ VoxelShape collisionShape = VoxelShapeUtil.createXZRotatedTowards(direction, 5, 0, 5, 11, 2, 11);
+ return new ComputedShapes(boundingShape, collisionShape);
+ }
+
+ VoxelShape shape = switch (stage) {
+ case 1 -> Shapes.join(
+ VoxelShapeUtil.createXZRotatedTowards(direction, 5, 0, 5, 11, 2, 11),
+ VoxelShapeUtil.createXZRotatedTowards(direction, 4, 2, 4, 12, 10, 12), BooleanOp.OR);
+ case 2 -> Shapes.join(
+ VoxelShapeUtil.createXZRotatedTowards(direction, 5, 0, 5, 11, 2, 11),
+ VoxelShapeUtil.createXZRotatedTowards(direction, 2, 2, 2, 14, 15, 14), BooleanOp.OR);
+ case 3, 4 -> Shapes.block();
+ default -> Shapes.empty();
+ };
+
+ return new ComputedShapes(shape, shape);
+ }
+
+ protected record ComputedShapes(VoxelShape boundingShape, VoxelShape collisionShape) {}
+}
diff --git a/src/main/java/com/github/elenterius/biomancy/block/malignantbloom/package-info.java b/src/main/java/com/github/elenterius/biomancy/block/malignantbloom/package-info.java
new file mode 100644
index 000000000..874104113
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/block/malignantbloom/package-info.java
@@ -0,0 +1,7 @@
+@ParametersAreNonnullByDefault
+@MethodsReturnNonnullByDefault
+package com.github.elenterius.biomancy.block.malignantbloom;
+
+import net.minecraft.MethodsReturnNonnullByDefault;
+
+import javax.annotation.ParametersAreNonnullByDefault;
\ No newline at end of file
diff --git a/src/main/java/com/github/elenterius/biomancy/block/neural/NeuralInterceptorBlock.java b/src/main/java/com/github/elenterius/biomancy/block/neural/NeuralInterceptorBlock.java
new file mode 100644
index 000000000..a14480436
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/block/neural/NeuralInterceptorBlock.java
@@ -0,0 +1,93 @@
+package com.github.elenterius.biomancy.block.neural;
+
+import com.github.elenterius.biomancy.util.SoundUtil;
+import com.github.elenterius.biomancy.world.MobSpawnFilterShape;
+import com.github.elenterius.biomancy.world.spatial.SpatialShapeManager;
+import com.github.elenterius.biomancy.world.spatial.geometry.SphereShape;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.particles.ParticleTypes;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.sounds.SoundEvents;
+import net.minecraft.util.RandomSource;
+import net.minecraft.world.item.context.BlockPlaceContext;
+import net.minecraft.world.level.BlockGetter;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.HorizontalDirectionalBlock;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.block.state.StateDefinition;
+import net.minecraft.world.phys.shapes.BooleanOp;
+import net.minecraft.world.phys.shapes.CollisionContext;
+import net.minecraft.world.phys.shapes.Shapes;
+import net.minecraft.world.phys.shapes.VoxelShape;
+import org.jetbrains.annotations.Nullable;
+
+public class NeuralInterceptorBlock extends HorizontalDirectionalBlock {
+
+ protected static final VoxelShape SHAPE = createShape();
+
+ private static VoxelShape createShape() {
+ VoxelShape a = Block.box(2, 0, 2, 14, 8, 14);
+ VoxelShape b = Block.box(3, 8, 3, 13, 17, 13);
+ return Shapes.join(a, b, BooleanOp.OR);
+ }
+
+ public NeuralInterceptorBlock(Properties properties) {
+ super(properties);
+ }
+
+ @Override
+ protected void createBlockStateDefinition(StateDefinition.Builder builder) {
+ builder.add(FACING);
+ }
+
+ @Nullable
+ @Override
+ public BlockState getStateForPlacement(BlockPlaceContext context) {
+ return defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
+ }
+
+ @Override
+ public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) {
+ if (level instanceof ServerLevel serverLevel) {
+ SpatialShapeManager.getOrCreateShape(serverLevel, pos, () -> {
+ SphereShape shape = new SphereShape(pos.getX() + 0.5d, pos.getY() + 0.5d, pos.getZ() + 0.5d, 48);
+ return new MobSpawnFilterShape(shape);
+ });
+ }
+ }
+
+ @Override
+ public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
+ if (!state.is(newState.getBlock())) {
+ if (level instanceof ServerLevel serverLevel) {
+ SpatialShapeManager.remove(serverLevel, pos);
+ }
+ super.onRemove(state, level, pos, newState, isMoving);
+ }
+ }
+
+ @Override
+ public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
+ return SHAPE;
+ }
+
+ @Override
+ public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
+ if (random.nextInt(4) == 0) {
+ int particleAmount = random.nextInt(2, 8);
+ int color = 0x9f4576; //magenta haze
+ double r = (color >> 16 & 255) / 255d;
+ double g = (color >> 8 & 255) / 255d;
+ double b = (color & 255) / 255d;
+ for (int i = 0; i < particleAmount; i++) {
+ level.addParticle(ParticleTypes.ENTITY_EFFECT, pos.getX() + (random.nextFloat() * 0.8f + 0.1f), pos.getY() + 0.75f, pos.getZ() + (random.nextFloat() * 0.8f + 0.1f), r, g, b);
+ }
+
+ if (random.nextInt(3) == 0) {
+ SoundUtil.clientPlayBlockSound(level, pos, SoundEvents.VILLAGER_AMBIENT, 0.6f, 0.6f);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/elenterius/biomancy/block/neural/package-info.java b/src/main/java/com/github/elenterius/biomancy/block/neural/package-info.java
new file mode 100644
index 000000000..f44255cba
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/block/neural/package-info.java
@@ -0,0 +1,7 @@
+@ParametersAreNonnullByDefault
+@MethodsReturnNonnullByDefault
+package com.github.elenterius.biomancy.block.neural;
+
+import net.minecraft.MethodsReturnNonnullByDefault;
+
+import javax.annotation.ParametersAreNonnullByDefault;
\ No newline at end of file
diff --git a/src/main/java/com/github/elenterius/biomancy/block/orifice/OrificeBlock.java b/src/main/java/com/github/elenterius/biomancy/block/orifice/OrificeBlock.java
new file mode 100644
index 000000000..d335c0ded
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/block/orifice/OrificeBlock.java
@@ -0,0 +1,109 @@
+package com.github.elenterius.biomancy.block.orifice;
+
+import com.github.elenterius.biomancy.init.ModFluids;
+import com.github.elenterius.biomancy.init.ModParticleTypes;
+import com.github.elenterius.biomancy.init.ModPlantTypes;
+import com.github.elenterius.biomancy.init.ModProjectiles;
+import com.github.elenterius.biomancy.util.EnhancedIntegerProperty;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.sounds.SoundEvent;
+import net.minecraft.util.RandomSource;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.BlockGetter;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.LevelAccessor;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.BucketPickup;
+import net.minecraft.world.level.block.FallingBlock;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.block.state.StateDefinition;
+import net.minecraft.world.level.block.state.properties.BlockStateProperties;
+import net.minecraft.world.phys.Vec3;
+import net.minecraftforge.common.IPlantable;
+import net.minecraftforge.common.PlantType;
+
+import java.util.Optional;
+
+public class OrificeBlock extends Block implements BucketPickup {
+
+ public static final EnhancedIntegerProperty AGE = EnhancedIntegerProperty.wrap(BlockStateProperties.AGE_2);
+
+ public OrificeBlock(Properties properties) {
+ super(properties);
+ registerDefaultState(defaultBlockState().setValue(AGE.get(), AGE.getMin()));
+ }
+
+ @Override
+ protected void createBlockStateDefinition(StateDefinition.Builder builder) {
+ super.createBlockStateDefinition(builder);
+ builder.add(AGE.get());
+ }
+
+ @Override
+ public boolean canSustainPlant(BlockState state, BlockGetter world, BlockPos pos, Direction facing, IPlantable plantable) {
+ PlantType type = plantable.getPlantType(world, pos.relative(facing));
+ return type == ModPlantTypes.FLESH_PLANT_TYPE;
+ }
+
+ @Override
+ public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
+ if (!level.isAreaLoaded(pos, 1)) return;
+
+ if (random.nextFloat() < 0.33f) {
+ int age = AGE.getValue(state);
+ if (age < AGE.getMax()) {
+ level.setBlock(pos, AGE.addValue(state, 1), Block.UPDATE_CLIENTS);
+ }
+ else {
+ if (random.nextFloat() < 0.5f) {
+ BlockPos posBelow = pos.below();
+ if (FallingBlock.isFree(level.getBlockState(posBelow)) && pos.getY() >= level.getMinBuildHeight()) {
+ level.setBlock(pos, AGE.setValue(state, AGE.getMin()), Block.UPDATE_CLIENTS);
+ float x = random.nextIntBetweenInclusive(-6, 6) / 16f;
+ float z = random.nextIntBetweenInclusive(-6, 6) / 16f;
+ ModProjectiles.FALLING_ACID_BLOB.shoot(level, Vec3.atBottomCenterOf(pos).add(x, 0, z), Vec3.atBottomCenterOf(posBelow).add(x, 0, z));
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public ItemStack pickupBlock(LevelAccessor level, BlockPos pos, BlockState state) {
+ if (AGE.getValue(state) == AGE.getMax()) {
+ level.setBlock(pos, AGE.setValue(state, AGE.getMin()), Block.UPDATE_CLIENTS);
+ return new ItemStack(ModFluids.ACID.get().getBucket());
+ }
+
+ return ItemStack.EMPTY;
+ }
+
+ @Override
+ public Optional getPickupSound() {
+ return ModFluids.ACID.get().getPickupSound();
+ }
+
+ @Override
+ public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
+ if (random.nextInt(5) == 0 && AGE.getValue(state) == AGE.getMax()) {
+ Direction direction = Direction.getRandom(random);
+
+ if (direction == Direction.UP) {
+ return;
+ }
+
+ BlockPos neighborPos = pos.relative(direction);
+ BlockState neighborState = level.getBlockState(neighborPos);
+
+ if (!state.canOcclude() || !neighborState.isFaceSturdy(level, neighborPos, direction.getOpposite())) {
+ double x = direction.getStepX() == 0 ? random.nextDouble() : 0.5d + direction.getStepX() * 0.6d;
+ double y = direction.getStepY() == 0 ? random.nextDouble() : 0.5d + direction.getStepY() * 0.6d;
+ double z = direction.getStepZ() == 0 ? random.nextDouble() : 0.5d + direction.getStepZ() * 0.6d;
+ level.addParticle(ModParticleTypes.DRIPPING_ACID.get(), pos.getX() + x, pos.getY() + y, pos.getZ() + z, 0, 0, 0);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/elenterius/biomancy/block/orifice/package-info.java b/src/main/java/com/github/elenterius/biomancy/block/orifice/package-info.java
new file mode 100644
index 000000000..c1c91a051
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/block/orifice/package-info.java
@@ -0,0 +1,7 @@
+@ParametersAreNonnullByDefault
+@MethodsReturnNonnullByDefault
+package com.github.elenterius.biomancy.block.orifice;
+
+import net.minecraft.MethodsReturnNonnullByDefault;
+
+import javax.annotation.ParametersAreNonnullByDefault;
\ No newline at end of file
diff --git a/src/main/java/com/github/elenterius/biomancy/block/property/BlockPropertyUtil.java b/src/main/java/com/github/elenterius/biomancy/block/property/BlockPropertyUtil.java
index 4bfe6f05a..4fbfc125e 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/property/BlockPropertyUtil.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/property/BlockPropertyUtil.java
@@ -1,9 +1,8 @@
package com.github.elenterius.biomancy.block.property;
-import com.google.common.collect.ImmutableMap;
+import com.github.elenterius.biomancy.mixin.IntegerPropertyAccessor;
import net.minecraft.world.level.block.CropBlock;
import net.minecraft.world.level.block.state.BlockState;
-import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.level.block.state.properties.Property;
@@ -13,35 +12,16 @@
public final class BlockPropertyUtil {
- public static final ImmutableMap maxAgeMappings;
public static final String AGE_PROPERTY = "age";
- static {
- //we can't know if someone might have manipulated the properties, so we search for the max value
- maxAgeMappings = ImmutableMap.builder()
- .put(BlockStateProperties.AGE_1, findLast(BlockStateProperties.AGE_1.getPossibleValues()))
- .put(BlockStateProperties.AGE_3, findLast(BlockStateProperties.AGE_3.getPossibleValues()))
- .put(BlockStateProperties.AGE_5, findLast(BlockStateProperties.AGE_5.getPossibleValues()))
- .put(BlockStateProperties.AGE_7, findLast(BlockStateProperties.AGE_7.getPossibleValues()))
- .put(BlockStateProperties.AGE_15, findLast(BlockStateProperties.AGE_15.getPossibleValues()))
- .put(BlockStateProperties.AGE_25, findLast(BlockStateProperties.AGE_25.getPossibleValues()))
- .build();
- }
-
private BlockPropertyUtil() {}
public static int getMaxAge(IntegerProperty property) {
- if (maxAgeMappings.containsKey(property)) {
- Integer integer = maxAgeMappings.get(property);
- return integer != null ? integer : 0;
- }
- else {
- return findLast(property.getPossibleValues());
- }
+ return ((IntegerPropertyAccessor) property).biomancy$getMax();
}
public static int getMinAge(IntegerProperty property) {
- return property.getPossibleValues().iterator().next();
+ return ((IntegerPropertyAccessor) property).biomancy$getMin();
}
public static Optional getAgeProperty(BlockState state) {
@@ -60,25 +40,11 @@ public static int getAge(BlockState state) {
return getAgeProperty(state).map(state::getValue).orElse(0);
}
- public static Optional getCurrentAgeAndMaxAge(BlockState state) {
- if (state.getBlock() instanceof CropBlock crop) {
- return Optional.of(new int[]{state.getValue(crop.getAgeProperty()), crop.getMaxAge()});
- }
-
- for (Property> property : state.getProperties()) {
- if (property.getName().equals(AGE_PROPERTY) && property instanceof IntegerProperty ageProperty) {
- return Optional.of(new int[]{state.getValue(ageProperty), getMaxAge(ageProperty)});
- }
- }
-
- return Optional.empty();
- }
-
public static > T getPrevious(Property property, T value) {
return findPrevious(property.getPossibleValues(), value);
}
- public static T findPrevious(Collection collection, T value) {
+ private static T findPrevious(Collection collection, T value) {
Iterator iterator = collection.iterator();
T previous = null;
@@ -93,7 +59,11 @@ public static T findPrevious(Collection collection, T value) {
return previous != null ? previous : value; //returns the last value of the collection if possible
}
- public static T findLast(Collection collection) {
+ public static > T getLast(Property property) {
+ return findLast(property.getPossibleValues());
+ }
+
+ private static T findLast(Collection collection) {
T value = collection.iterator().next();
for (T t : collection) value = t;
return value;
diff --git a/src/main/java/com/github/elenterius/biomancy/block/veins/FleshVeinsBlock.java b/src/main/java/com/github/elenterius/biomancy/block/veins/FleshVeinsBlock.java
index 69f51404c..e3ffb8940 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/veins/FleshVeinsBlock.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/veins/FleshVeinsBlock.java
@@ -1,18 +1,25 @@
package com.github.elenterius.biomancy.block.veins;
-import com.github.elenterius.biomancy.block.DirectionalSlabBlock;
-import com.github.elenterius.biomancy.block.cradle.PrimordialCradleBlockEntity;
-import com.github.elenterius.biomancy.block.property.DirectionalSlabType;
+import com.github.elenterius.biomancy.block.cradle.PrimalEnergyHandler;
+import com.github.elenterius.biomancy.block.malignantbloom.MalignantBloomBlock;
import com.github.elenterius.biomancy.init.ModBlockProperties;
import com.github.elenterius.biomancy.init.ModBlocks;
-import com.github.elenterius.biomancy.init.ModItems;
+import com.github.elenterius.biomancy.init.ModFluids;
import com.github.elenterius.biomancy.init.ModSoundEvents;
+import com.github.elenterius.biomancy.init.tags.ModBlockTags;
import com.github.elenterius.biomancy.util.ArrayUtil;
import com.github.elenterius.biomancy.util.Bit32Set;
import com.github.elenterius.biomancy.util.EnhancedIntegerProperty;
import com.github.elenterius.biomancy.util.LevelUtil;
-import com.github.elenterius.biomancy.util.random.Noise;
+import com.github.elenterius.biomancy.util.random.CellularNoise;
import com.github.elenterius.biomancy.world.PrimordialEcosystem;
+import com.github.elenterius.biomancy.world.mound.MoundChamber;
+import com.github.elenterius.biomancy.world.mound.MoundShape;
+import com.github.elenterius.biomancy.world.mound.decorator.ChamberDecorator;
+import com.github.elenterius.biomancy.world.mound.decorator.ChamberSpecialDecorator;
+import com.github.elenterius.biomancy.world.spatial.SpatialShapeManager;
+import com.github.elenterius.biomancy.world.spatial.geometry.HasRadius;
+import com.github.elenterius.biomancy.world.spatial.geometry.Shape;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ItemParticleOption;
@@ -29,22 +36,28 @@
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
+import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.*;
+import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.Half;
import net.minecraft.world.level.block.state.properties.StairsShape;
+import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
+import java.util.Arrays;
import java.util.Optional;
+import java.util.function.Predicate;
public class FleshVeinsBlock extends MultifaceBlock implements SimpleWaterloggedBlock {
+ public static final Predicate BLOCKS_TO_AVOID_PREDICATE = blockState -> blockState.is(ModBlocks.MALIGNANT_BLOOM.get());
protected static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
protected static final EnhancedIntegerProperty CHARGE = ModBlockProperties.CHARGE;
private final MultifaceSpreader spreader = new MultifaceSpreader(new MalignantFleshSpreaderConfig(this));
@@ -54,97 +67,185 @@ public FleshVeinsBlock(Properties properties) {
registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false).setValue(CHARGE.get(), CHARGE.getMin()));
}
- public static boolean convertSelf(BlockState state, ServerLevel level, BlockPos pos, int directNeighbors, boolean isCradleNearby, float nearCradlePct) {
-
- Bit32Set bitSet = new Bit32Set();
- bitSet.set(5, hasFace(state, Direction.DOWN));
- bitSet.set(4, hasFace(state, Direction.UP));
- bitSet.set(3, hasFace(state, Direction.NORTH));
- bitSet.set(2, hasFace(state, Direction.SOUTH));
- bitSet.set(1, hasFace(state, Direction.WEST));
- bitSet.set(0, hasFace(state, Direction.EAST));
-
- int faces = bitSet.cardinality();
-
- if (faces == 1) {
- if (isCradleNearby) {
- int bitIndex = bitSet.nextSetBit(0);
- if (bitIndex < 6) {
- Direction direction = Direction.from3DDataValue(5 - bitIndex);
- BlockPos posBelow = pos.relative(direction);
- BlockState stateBelow = level.getBlockState(posBelow);
-
- Block replacementBlock = ModBlocks.PRIMAL_FLESH.get();
-
- if (stateBelow.getBlock() == ModBlocks.PRIMAL_FLESH.get() || stateBelow.getBlock() == ModBlocks.MALIGNANT_FLESH.get()) {
- BlockPos posBelow2 = pos.relative(direction, 2);
- BlockState stateBelow2 = level.getBlockState(posBelow2);
-
- if (direction == Direction.UP && (stateBelow2.getBlock() == ModBlocks.PRIMAL_FLESH.get() || stateBelow2.getBlock() == ModBlocks.MALIGNANT_FLESH.get())) {
- if (level.getLightEngine().getRawBrightness(pos, 0) < 5) {
- level.setBlock(posBelow, Blocks.SHROOMLIGHT.defaultBlockState(), Block.UPDATE_CLIENTS);
- return true;
- }
- }
+ public static boolean convert(BlockState state, ServerLevel level, BlockPos pos, int directNeighbors, @Nullable MoundShape mound, float nearBoundingCenterPct, @Nullable PrimalEnergyHandler energyHandler) {
- posBelow = posBelow2;
- stateBelow = stateBelow2;
- }
- else {
- replacementBlock = level.random.nextFloat() < nearCradlePct ? ModBlocks.PRIMAL_FLESH.get() : ModBlocks.MALIGNANT_FLESH.get();
- }
+ Bit32Set facesSet = new Bit32Set();
+ facesSet.set(5, hasFace(state, Direction.DOWN));
+ facesSet.set(4, hasFace(state, Direction.UP));
+ facesSet.set(3, hasFace(state, Direction.NORTH));
+ facesSet.set(2, hasFace(state, Direction.SOUTH));
+ facesSet.set(1, hasFace(state, Direction.WEST));
+ facesSet.set(0, hasFace(state, Direction.EAST));
- return PrimordialEcosystem.tryToReplaceBlock(level, posBelow, stateBelow, replacementBlock.defaultBlockState());
- }
+ if (mound != null) {
+ MoundChamber chamber = mound.getChamberAt(pos);
+ if (chamber != null && chamber.contains(pos)) {
+ return convertInsideChamber(level, pos, directNeighbors, mound, chamber, nearBoundingCenterPct, facesSet, energyHandler);
+ }
+ }
+
+ return convertNormal(level, pos, mound, nearBoundingCenterPct, directNeighbors, facesSet);
+ }
+
+ protected static boolean convertNormal(ServerLevel level, BlockPos pos, @Nullable MoundShape mound, float nearBoundingCenterPct, int directNeighbors, Bit32Set facesSet) {
+ int numFaces = facesSet.cardinality();
+
+ boolean hasAnyBlockToAvoidNearby = LevelUtil.isBlockNearby(level, pos, 2, BLOCKS_TO_AVOID_PREDICATE);
+
+ if (numFaces == 1) {
+ CellularNoise cellularNoise = PrimordialEcosystem.getCellularNoise(level);
+ float noiseValue = cellularNoise.getValueAtCenter(pos);
+
+ //vein face points inwards and the direction is in reference to itself and not in reference to the block it's attached to
+ Direction axisDirection = Direction.from3DDataValue(5 - facesSet.nextSetBit(0));
+
+ boolean hasConvertedAnyOtherBlocks = convertDirectNeighborBlock(level, pos, axisDirection, directNeighbors, cellularNoise, noiseValue);
- return false;
+ if (!hasConvertedAnyOtherBlocks && !hasAnyBlockToAvoidNearby && directNeighbors > 2) {
+ if (noiseValue >= cellularNoise.borderThreshold()) {
+ return convertSelfIntoSlabBlock(level, pos, axisDirection.getOpposite());
+ }
+ else if (noiseValue < cellularNoise.coreThreshold() && (PrimordialEcosystem.getRandomWithSeed(pos).nextFloat() <= 0.3f - nearBoundingCenterPct) && (LevelUtil.getMaxBrightness(level, pos) > 5)) {
+ return convertSelfIntoBloom(level, pos, axisDirection);
+ }
}
- if (directNeighbors < 3) return false;
+ return hasConvertedAnyOtherBlocks;
+ }
+
+ if (hasAnyBlockToAvoidNearby) return false;
+
+ if (numFaces > 3) {
+ return convertSelfIntoFullBlock(level, pos);
+ }
+
+ return convertSelfIntoStairs(level, pos, facesSet);
+ }
+
+ protected static boolean convertInsideChamber(ServerLevel level, BlockPos pos, int directNeighbors, MoundShape mound, MoundChamber chamber, float nearBoundingCenterPct, Bit32Set facesSet, @Nullable PrimalEnergyHandler energyHandler) {
+ Direction[] axisDirections = Arrays.stream(facesSet.getIndices()).mapToObj(i -> Direction.from3DDataValue(5 - i)).toArray(Direction[]::new);
+ ArrayUtil.shuffle(axisDirections, level.random);
- int bitIndex = bitSet.nextSetBit(0);
- if (bitIndex < 6) {
- //vein faces point inwards and the direction is in reference to itself and not in reference to the block it's attached to
+ for (Direction axisDirection : axisDirections) {
+ BlockPos closeOffsetPos = pos.relative(axisDirection);
+ BlockState closeOffsetState = level.getBlockState(closeOffsetPos);
- Direction direction = Direction.from3DDataValue(5 - bitIndex);
- BlockPos posBelow = pos.relative(direction);
- BlockState stateBelow = level.getBlockState(posBelow);
+ if (PrimordialEcosystem.isReplaceable(closeOffsetState)) {
+ return destroyBlockAndConvertIntoEnergy(level, closeOffsetPos, energyHandler, 15);
+ }
+
+ if (PrimordialEcosystem.FULL_FLESH_BLOCKS.contains(closeOffsetState.getBlock())) {
+ ChamberDecorator chamberDecorator = chamber.getDecorator();
- Block replacementBlock;
+ boolean chamberContainsCloseOffsetPos = chamber.contains(closeOffsetPos);
- if (stateBelow.getBlock() == ModBlocks.PRIMAL_FLESH.get() || stateBelow.getBlock() == ModBlocks.MALIGNANT_FLESH.get()) {
- posBelow = pos.relative(direction, 2);
- stateBelow = level.getBlockState(posBelow);
- replacementBlock = ModBlocks.PRIMAL_FLESH.get();
+ if (chamberContainsCloseOffsetPos && !closeOffsetState.is(ModBlocks.BLOOMLIGHT.get())) {
+ ChamberDecorator.PartOfDecorationResult result = chamberDecorator.isBlockPartOfDecoration(chamber, level, closeOffsetPos, closeOffsetState);
+ if (result.positionIsValid && !result.materialIsValid) {
+ return destroyBlockAndConvertIntoEnergy(level, closeOffsetPos, energyHandler, 30);
+ }
}
- else {
- replacementBlock = ModBlocks.MALIGNANT_FLESH.get();
+
+ if (chamberDecorator.canPlace(chamber, level, pos, axisDirection)) {
+ return chamberDecorator.place(chamber, level, pos, axisDirection);
}
- if (!PrimordialEcosystem.tryToReplaceBlock(level, posBelow, stateBelow, replacementBlock.defaultBlockState())) {
- Noise noise = PrimordialEcosystem.getCellularNoise(level);
- float borderThreshold = 0.15f;
- float n = noise.getValue(pos.getX(), pos.getY(), pos.getZ());
- if (n >= borderThreshold) {
- BlockState slabState = ModBlocks.MALIGNANT_FLESH_SLAB.get()
- .defaultBlockState()
- .setValue(DirectionalSlabBlock.TYPE, DirectionalSlabType.getHalfFrom(pos, Vec3.atCenterOf(pos), direction.getOpposite()));
- level.setBlock(pos, slabState, Block.UPDATE_CLIENTS);
+ BlockPos farOffsetPos = pos.relative(axisDirection, 2);
+ BlockState farOffsetState = level.getBlockState(farOffsetPos);
+
+ if (!chamberContainsCloseOffsetPos) {
+ // create "Door" between two adjacent chambers that are separated by a one block thick wall
+ if (!mound.hasChamberAt(closeOffsetPos)) {
+ MoundChamber farChamber = mound.getChamberAt(farOffsetPos);
+ if (farChamber != null && farChamber != chamber) {
+ return level.setBlock(closeOffsetPos, ModBlocks.PRIMAL_PERMEABLE_MEMBRANE.get().defaultBlockState(), Block.UPDATE_CLIENTS);
+ }
}
}
+
+ // create light source in dark areas
+ if (ChamberSpecialDecorator.BLOOMLIGHT.canDecorate(chamber, level, pos, axisDirection, closeOffsetPos, closeOffsetState, farOffsetPos, farOffsetState)) {
+ return ChamberSpecialDecorator.BLOOMLIGHT.decorate(chamber, level, pos, axisDirection, closeOffsetPos, closeOffsetState, farOffsetPos, farOffsetState);
+ }
+
+ if (PrimordialEcosystem.isReplaceable(farOffsetState) && farOffsetState.isCollisionShapeFullBlock(level, farOffsetPos)) {
+ BlockState replacementState = level.random.nextFloat() < nearBoundingCenterPct ? ModBlocks.PRIMAL_FLESH.get().defaultBlockState() : ModBlocks.MALIGNANT_FLESH.get().defaultBlockState();
+ return level.setBlock(farOffsetPos, replacementState, Block.UPDATE_CLIENTS);
+ }
}
+ }
+
+ return false;
+ }
+ protected static boolean destroyBlockAndConvertIntoEnergy(ServerLevel level, BlockPos pos, @Nullable PrimalEnergyHandler energyHandler, int amount) {
+ if (level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS)) {
+ if (energyHandler != null) energyHandler.fillPrimalEnergy(amount);
return true;
}
+ return false;
+ }
- if (isCradleNearby) return false;
+ protected static boolean convertDirectNeighborBlock(ServerLevel level, BlockPos pos, Direction axisDirection, int directNeighbors, CellularNoise cellularNoise, float noiseValue) {
+ BlockPos posRelative = pos.relative(axisDirection);
+ BlockState stateRelative = level.getBlockState(posRelative);
+ BlockState replacementState = null;
- if (faces > 3) {
- level.setBlock(pos, ModBlocks.MALIGNANT_FLESH.get().defaultBlockState(), Block.UPDATE_CLIENTS);
- return true;
+ if (directNeighbors > 2) {
+ if (stateRelative.getBlock() == ModBlocks.PRIMAL_FLESH.get() || stateRelative.getBlock() == ModBlocks.MALIGNANT_FLESH.get()) {
+ posRelative = pos.relative(axisDirection, 2);
+ stateRelative = level.getBlockState(posRelative);
+ return PrimordialEcosystem.tryToReplaceBlock(level, posRelative, stateRelative, ModBlocks.PRIMAL_FLESH.get().defaultBlockState());
+ }
+ else {
+ replacementState = ModBlocks.MALIGNANT_FLESH.get().defaultBlockState();
+ }
+ }
+
+ if (PrimordialEcosystem.isReplaceableLog(stateRelative)) {
+ if (noiseValue < cellularNoise.coreThreshold()) {
+ if (stateRelative.hasProperty(RotatedPillarBlock.AXIS)) {
+ Direction.Axis axis = stateRelative.getValue(RotatedPillarBlock.AXIS);
+ replacementState = Blocks.BONE_BLOCK.defaultBlockState().setValue(RotatedPillarBlock.AXIS, axis);
+ }
+ else replacementState = ModBlocks.PRIMAL_FLESH_WALL.get().defaultBlockState();
+ }
+ else replacementState = ModBlocks.PRIMAL_FLESH.get().defaultBlockState();
+ }
+
+ if (replacementState != null) {
+ return PrimordialEcosystem.tryToReplaceBlock(level, posRelative, stateRelative, replacementState);
}
- int mask = bitSet.getBits();
+ return false;
+ }
+
+ protected static boolean convertSelfIntoBloom(ServerLevel level, BlockPos pos, Direction direction) {
+ MalignantBloomBlock bloomBlock = ModBlocks.MALIGNANT_BLOOM.get();
+
+ BlockPos posBelow = pos.relative(direction);
+ BlockState stateBelow = level.getBlockState(posBelow);
+ boolean mayPlace = bloomBlock.mayPlaceOn(level, posBelow, stateBelow);
+
+ if (mayPlace && !LevelUtil.isBlockNearby(level, pos, 4, blockState -> blockState.is(bloomBlock)) && bloomBlock.hasUnobstructedAim(level, pos, direction.getOpposite())) {
+ BlockState stateForPlacement = bloomBlock.getStateForPlacement(level, pos, direction.getOpposite());
+ return level.setBlock(pos, stateForPlacement, Block.UPDATE_CLIENTS);
+ }
+
+ return false;
+ }
+
+ protected static boolean convertSelfIntoSlabBlock(ServerLevel level, BlockPos pos, Direction direction) {
+ BlockState stateForPlacement = ModBlocks.MALIGNANT_FLESH_SLAB.get().getStateForPlacement(level, pos, direction);
+ return level.setBlock(pos, stateForPlacement, Block.UPDATE_CLIENTS);
+ }
+
+ protected static boolean convertSelfIntoFullBlock(ServerLevel level, BlockPos pos) {
+ return level.setBlock(pos, ModBlocks.MALIGNANT_FLESH.get().defaultBlockState(), Block.UPDATE_CLIENTS);
+ }
+
+ protected static boolean convertSelfIntoStairs(ServerLevel level, BlockPos pos, Bit32Set facesSet) {
+ int mask = facesSet.getBits();
if (mask == 0b10_10_00) { //down & north
BlockState blockState = ModBlocks.MALIGNANT_FLESH_STAIRS.get().defaultBlockState()
@@ -277,6 +378,17 @@ public static boolean convertSelf(BlockState state, ServerLevel level, BlockPos
return false;
}
+ protected static BlockState removeFace(BlockState state, BooleanProperty face) {
+ BlockState blockstate = state.setValue(face, Boolean.FALSE);
+ return hasAnyFace(blockstate) ? blockstate : Blocks.AIR.defaultBlockState();
+ }
+
+ public static boolean canVeinsAttachTo(BlockGetter level, Direction direction, BlockPos pos, BlockState state) {
+ if (state.is(ModBlockTags.DISALLOW_VEINS_TO_ATTACH)) return false;
+ if (state.is(ModBlockTags.ALLOW_VEINS_TO_ATTACH)) return true;
+ return Block.isFaceFull(state.getBlockSupportShape(level, pos), direction.getOpposite()) || Block.isFaceFull(state.getCollisionShape(level, pos), direction.getOpposite());
+ }
+
@Override
protected void createBlockStateDefinition(StateDefinition.Builder builder) {
super.createBlockStateDefinition(builder);
@@ -306,12 +418,52 @@ public BlockState updateShape(BlockState state, Direction direction, BlockState
if (Boolean.TRUE.equals(state.getValue(WATERLOGGED))) {
level.scheduleTick(currentPos, Fluids.WATER, Fluids.WATER.getTickDelay(level));
}
- return super.updateShape(state, direction, neighborState, level, currentPos, neighborPos);
+
+ if (!hasAnyFace(state)) {
+ return Blocks.AIR.defaultBlockState();
+ }
+
+ if (hasFace(state, direction) && !canVeinsAttachTo(level, direction, neighborPos, neighborState)) {
+ return removeFace(state, getFaceProperty(direction));
+ }
+
+ return state;
+ }
+
+ @Override
+ public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
+ boolean flag = false;
+
+ for (Direction direction : DIRECTIONS) {
+ if (hasFace(state, direction)) {
+ BlockPos blockpos = pos.relative(direction);
+ if (!canVeinsAttachTo(level, direction, blockpos, level.getBlockState(blockpos))) {
+ return false;
+ }
+ flag = true;
+ }
+ }
+
+ return flag;
+ }
+
+ @Override
+ public boolean isValidStateForPlacement(BlockGetter level, BlockState state, BlockPos pos, Direction direction) {
+ if (isFaceSupported(direction) && (!state.is(this) || !hasFace(state, direction))) {
+ BlockPos blockPos = pos.relative(direction);
+ return canVeinsAttachTo(level, direction, blockPos, level.getBlockState(blockPos));
+ }
+ return false;
}
@Override
public boolean canBeReplaced(BlockState state, BlockPlaceContext useContext) {
- return useContext.getItemInHand().is(asItem()) && super.canBeReplaced(state, useContext);
+ return !useContext.getItemInHand().is(asItem()) || super.canBeReplaced(state, useContext);
+ }
+
+ @Override
+ public boolean canBeReplaced(BlockState state, Fluid fluid) {
+ return fluid.getFluidType() == ModFluids.ACID_TYPE.get() || material.isReplaceable() || !material.isSolid();
}
@Override
@@ -334,17 +486,7 @@ public void entityInside(BlockState state, Level level, BlockPos pos, Entity ent
ItemStack stack = itemEntity.getItem();
- if (stack.is(ModItems.LIVING_FLESH.get())) {
- charge = CHARGE.getMax();
-
- Vec3 motion = new Vec3((level.random.nextFloat() - 0.5d) * 0.1d, level.random.nextFloat() * 0.1d + 0.15d, (level.random.nextFloat() - 0.5d) * 0.1d);
- ((ServerLevel) level).sendParticles(new ItemParticleOption(ParticleTypes.ITEM, stack), itemEntity.getX(), itemEntity.getY(), itemEntity.getZ(), 8, motion.x, motion.y, motion.z, 0.05f);
-
- stack.shrink(1);
- setCharge(level, pos, state, charge);
- level.playSound(null, pos, ModSoundEvents.DECOMPOSER_EAT.get(), SoundSource.BLOCKS, 1f, 0.15f + level.random.nextFloat() * 0.5f);
- }
- else if (stack.isEdible()) {
+ if (stack.isEdible()) {
int nutrition = Optional.ofNullable(stack.getFoodProperties(null))
.filter(FoodProperties::isMeat)
.map(FoodProperties::getNutrition).orElse(0);
@@ -358,7 +500,7 @@ else if (stack.isEdible()) {
stack.shrink(amount);
charge += amount * nutrition;
setCharge(level, pos, state, charge);
- level.playSound(null, pos, ModSoundEvents.DECOMPOSER_EAT.get(), SoundSource.BLOCKS, 1f, 0.15f + level.random.nextFloat() * 0.5f);
+ level.playSound(null, pos, ModSoundEvents.DECOMPOSER_EAT.get(), SoundSource.BLOCKS, 0.6f, 0.15f + level.random.nextFloat() * 0.5f);
}
}
}
@@ -368,21 +510,36 @@ public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource
if (level.random.nextFloat() >= 0.5f) return;
if (!level.isAreaLoaded(pos, 2)) return;
- int cradleCoreRadius = 8;
- int maxCradleDist = cradleCoreRadius * 4;
- PrimordialCradleBlockEntity cradle = LevelUtil.findNearestBlockEntity(level, pos, maxCradleDist, PrimordialCradleBlockEntity.class);
+ PrimalEnergyHandler energyHandler = null;
+ MoundShape mound = null;
+ float nearBoundingCenterPct = 0;
+
+ if (SpatialShapeManager.getClosestShape(level, pos, MoundShape.class::isInstance) instanceof MoundShape moundShape) {
+ mound = moundShape;
+
+ BlockPos origin = mound.getOrigin();
+ BlockEntity existingBlockEntity = level.getExistingBlockEntity(origin);
+ if (existingBlockEntity instanceof PrimalEnergyHandler peh) {
+ energyHandler = peh;
+ }
+
+ Shape boundingShape = mound.getBoundingShapeAt(pos);
+ if (boundingShape != null) {
+ double radius = boundingShape instanceof HasRadius sphere ? sphere.getRadius() : boundingShape.getAABB().getSize() / 2;
+ double radiusSqr = radius * radius;
+ double distSqr = boundingShape.distanceToSqr(pos.getX() + 0.5d, pos.getY() + 0.5d, pos.getZ() + 0.5d);
+ nearBoundingCenterPct = Mth.clamp((float) (1 - distSqr / radiusSqr), 0f, 1f);
+ }
+ }
int charge = getCharge(state);
if (charge < 2) {
- if (cradle != null && cradle.consumePrimalSpreadCharge(level, 1)) {
+ if (energyHandler != null && energyHandler.drainPrimalEnergy(1) > 0) {
setCharge(level, pos, state, charge + 1);
}
return;
}
- double cradleDistance = cradle != null ? Math.sqrt(cradle.getBlockPos().distSqr(pos)) : maxCradleDist + 1;
- float nearCradlePct = Mth.clamp((float) (1d - cradleDistance / maxCradleDist), 0f, 1f);
-
int directNeighbors = 0;
for (Direction direction : Direction.values()) {
BlockState neighborState = level.getBlockState(pos.relative(direction));
@@ -392,9 +549,9 @@ public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource
float populationPct = directNeighbors / (float) Direction.values().length;
float conversionChance = charge / (CHARGE.getMax() + 5f) + populationPct * 0.5f;
- if (random.nextFloat() < conversionChance && convertSelf(state, level, pos, directNeighbors, cradleDistance <= cradleCoreRadius, nearCradlePct)) {
- level.playSound(null, pos, ModSoundEvents.FLESH_BLOCK_STEP.get(), SoundSource.BLOCKS, 1.2f, 0.15f + random.nextFloat() * 0.5f);
- return;
+ if (random.nextFloat() < conversionChance && convert(state, level, pos, directNeighbors, mound, nearBoundingCenterPct, energyHandler)) {
+ level.playSound(null, pos, ModSoundEvents.FLESH_BLOCK_STEP.get(), SoundSource.BLOCKS, 0.8f, 0.15f + random.nextFloat() * 0.5f);
+ //return; //TODO: exiting early hampers growth to a very extreme degree. reevaluate which conversions should return true or be ignored
}
if (charge > 4) {
@@ -402,21 +559,21 @@ public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource
if (growthAmount > 0) {
charge -= growthAmount * 2;
state = level.getBlockState(pos);
- level.playSound(null, pos, ModSoundEvents.FLESH_BLOCK_STEP.get(), SoundSource.BLOCKS, 1f, 0.15f + random.nextFloat() * 0.5f);
+ level.playSound(null, pos, ModSoundEvents.FLESH_BLOCK_STEP.get(), SoundSource.BLOCKS, 0.6f, 0.15f + random.nextFloat() * 0.5f);
}
}
else {
if (getSpreader().spreadFromRandomFaceTowardRandomDirection(state, level, pos, random).isPresent()) {
charge -= 2;
state = level.getBlockState(pos);
- level.playSound(null, pos, ModSoundEvents.FLESH_BLOCK_STEP.get(), SoundSource.BLOCKS, 1f, 0.15f + random.nextFloat() * 0.5f);
+ level.playSound(null, pos, ModSoundEvents.FLESH_BLOCK_STEP.get(), SoundSource.BLOCKS, 0.6f, 0.15f + random.nextFloat() * 0.5f);
}
}
- if (cradleDistance <= maxCradleDist) {
- if (cradleDistance <= cradleCoreRadius || (cradle != null && cradle.consumePrimalSpreadCharge(level, charge))) {
- charge = Math.max(charge, Math.round(CHARGE.getMax() * nearCradlePct));
- increaseChargeAroundPos(level, pos, random, charge * 2);
+ if (energyHandler != null) {
+ int primalEnergy = Math.max(charge, Math.round(CHARGE.getMax() * nearBoundingCenterPct) / 2);
+ if (energyHandler.getPrimalEnergy() > primalEnergy && energyHandler.drainPrimalEnergy(primalEnergy) >= primalEnergy) {
+ increaseChargeAroundPos(level, pos, random, primalEnergy * 2);
}
else if (charge > 1) {
int usedCharge = increaseChargeAroundPos(level, pos, random, charge);
diff --git a/src/main/java/com/github/elenterius/biomancy/block/veins/MalignantFleshSpreaderConfig.java b/src/main/java/com/github/elenterius/biomancy/block/veins/MalignantFleshSpreaderConfig.java
index 405468810..33d01147e 100644
--- a/src/main/java/com/github/elenterius/biomancy/block/veins/MalignantFleshSpreaderConfig.java
+++ b/src/main/java/com/github/elenterius/biomancy/block/veins/MalignantFleshSpreaderConfig.java
@@ -2,7 +2,8 @@
import com.github.elenterius.biomancy.block.cradle.PrimordialCradleBlock;
import com.github.elenterius.biomancy.init.ModBlocks;
-import com.github.elenterius.biomancy.util.random.Noise;
+import com.github.elenterius.biomancy.util.LevelUtil;
+import com.github.elenterius.biomancy.util.random.CellularNoise;
import com.github.elenterius.biomancy.world.PrimordialEcosystem;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@@ -23,7 +24,6 @@
class MalignantFleshSpreaderConfig extends MultifaceSpreader.DefaultSpreaderConfig {
protected static final Set VALID_SOURCES = Set.of(ModBlocks.MALIGNANT_FLESH_SLAB.get(), ModBlocks.MALIGNANT_FLESH_STAIRS.get(), ModBlocks.MALIGNANT_FLESH.get());
- protected static final Set VALID_UPGRADE_TARGETS = Set.of(ModBlocks.MALIGNANT_FLESH_SLAB.get(), ModBlocks.MALIGNANT_FLESH_STAIRS.get());
public MalignantFleshSpreaderConfig(MultifaceBlock block) {
super(block);
@@ -54,12 +54,12 @@ protected boolean stateCanBeReplaced(BlockGetter level, BlockPos posA, BlockPos
@Override
public boolean canSpreadInto(BlockGetter level, BlockPos pos, MultifaceSpreader.SpreadPos spreadPos) {
BlockState state = level.getBlockState(spreadPos.pos());
- if (VALID_UPGRADE_TARGETS.contains(state.getBlock())) {
+ if (PrimordialEcosystem.VALID_UPGRADE_TARGETS.contains(state.getBlock())) {
if (level instanceof ServerLevel serverLevel) {
- Noise noise = PrimordialEcosystem.getCellularNoise(serverLevel);
- float borderThreshold = 0.145f;
- float n = noise.getValue(pos.getX(), pos.getY(), pos.getZ());
- return n >= borderThreshold;
+ CellularNoise cellularNoise = PrimordialEcosystem.getCellularNoise(serverLevel);
+ float borderThreshold = cellularNoise.borderThreshold() - 0.005f;
+ float n = cellularNoise.getValueAtCenter(pos);
+ return n >= borderThreshold && !LevelUtil.isBlockNearby(serverLevel, spreadPos.pos(), 4, blockState -> blockState.is(ModBlocks.MALIGNANT_BLOOM.get()));
}
return true;
}
@@ -68,7 +68,7 @@ public boolean canSpreadInto(BlockGetter level, BlockPos pos, MultifaceSpreader.
@Override
public boolean placeBlock(LevelAccessor level, MultifaceSpreader.SpreadPos spreadPos, BlockState state, boolean markForPostprocessing) {
- if (VALID_UPGRADE_TARGETS.contains(state.getBlock())) {
+ if (PrimordialEcosystem.VALID_UPGRADE_TARGETS.contains(state.getBlock())) {
if (level.getRandom().nextFloat() < 0.25f) {
return level.setBlock(spreadPos.pos(), ModBlocks.MALIGNANT_FLESH.get().defaultBlockState(), Block.UPDATE_CLIENTS);
}
diff --git a/src/main/java/com/github/elenterius/biomancy/client/gui/BioForgeScreen.java b/src/main/java/com/github/elenterius/biomancy/client/gui/BioForgeScreen.java
index b67d7422f..0abe1ba63 100644
--- a/src/main/java/com/github/elenterius/biomancy/client/gui/BioForgeScreen.java
+++ b/src/main/java/com/github/elenterius/biomancy/client/gui/BioForgeScreen.java
@@ -1,16 +1,16 @@
package com.github.elenterius.biomancy.client.gui;
import com.github.elenterius.biomancy.BiomancyMod;
-import com.github.elenterius.biomancy.chat.ComponentUtil;
import com.github.elenterius.biomancy.client.gui.component.CustomEditBox;
import com.github.elenterius.biomancy.client.util.ClientSoundUtil;
import com.github.elenterius.biomancy.client.util.GuiRenderUtil;
import com.github.elenterius.biomancy.client.util.GuiUtil;
+import com.github.elenterius.biomancy.crafting.recipe.BioForgeRecipe;
+import com.github.elenterius.biomancy.crafting.recipe.IngredientStack;
import com.github.elenterius.biomancy.init.ModSoundEvents;
import com.github.elenterius.biomancy.menu.BioForgeMenu;
-import com.github.elenterius.biomancy.recipe.BioForgeRecipe;
-import com.github.elenterius.biomancy.recipe.IngredientStack;
import com.github.elenterius.biomancy.styles.ColorStyles;
+import com.github.elenterius.biomancy.util.ComponentUtil;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
diff --git a/src/main/java/com/github/elenterius/biomancy/client/gui/BioForgeScreenController.java b/src/main/java/com/github/elenterius/biomancy/client/gui/BioForgeScreenController.java
index f131e81ac..7c43b8cb3 100644
--- a/src/main/java/com/github/elenterius/biomancy/client/gui/BioForgeScreenController.java
+++ b/src/main/java/com/github/elenterius/biomancy/client/gui/BioForgeScreenController.java
@@ -1,13 +1,15 @@
package com.github.elenterius.biomancy.client.gui;
+import com.github.elenterius.biomancy.BiomancyConfig;
+import com.github.elenterius.biomancy.crafting.recipe.BioForgeRecipe;
import com.github.elenterius.biomancy.init.ModBioForgeTabs;
import com.github.elenterius.biomancy.init.ModRecipeBookTypes;
import com.github.elenterius.biomancy.init.client.ModRecipeBookCategories;
+import com.github.elenterius.biomancy.integration.BioForgeCompat;
import com.github.elenterius.biomancy.menu.BioForgeMenu;
import com.github.elenterius.biomancy.menu.BioForgeTab;
import com.github.elenterius.biomancy.mixin.client.RecipeCollectionAccessor;
import com.github.elenterius.biomancy.network.ModNetworkHandler;
-import com.github.elenterius.biomancy.recipe.BioForgeRecipe;
import com.google.common.collect.Lists;
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
@@ -267,7 +269,7 @@ private static void canCraftRecipe(RecipeCollection recipeCollection, StackedCon
private void updateAndSearchRecipes() {
LocalPlayer player = getPlayer();
- boolean isCreativePlayer = player.isCreative();
+ boolean isCreativePlayer = player.isCreative() || !BiomancyConfig.SERVER.doBioForgeRecipeProgression.get() || BioForgeCompat.isRecipeCollectionOverwriteEnabled();
ClientRecipeBook recipeBook = player.getRecipeBook();
List recipesForCategory = recipeBook.getCollection(ModRecipeBookCategories.getRecipeBookCategories(tabs.get(activeTab)));
diff --git a/src/main/java/com/github/elenterius/biomancy/client/gui/DevCannonScreen.java b/src/main/java/com/github/elenterius/biomancy/client/gui/DevCannonScreen.java
index d1c9ad809..1790593c2 100644
--- a/src/main/java/com/github/elenterius/biomancy/client/gui/DevCannonScreen.java
+++ b/src/main/java/com/github/elenterius/biomancy/client/gui/DevCannonScreen.java
@@ -1,12 +1,12 @@
package com.github.elenterius.biomancy.client.gui;
-import com.github.elenterius.biomancy.chat.ComponentUtil;
import com.github.elenterius.biomancy.client.util.GuiRenderUtil;
import com.github.elenterius.biomancy.entity.projectile.BaseProjectile;
import com.github.elenterius.biomancy.init.ModProjectiles;
import com.github.elenterius.biomancy.item.weapon.DevArmCannonItem;
import com.github.elenterius.biomancy.network.ModNetworkHandler;
import com.github.elenterius.biomancy.styles.ColorStyles;
+import com.github.elenterius.biomancy.util.ComponentUtil;
import com.mojang.blaze3d.platform.InputConstants;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
diff --git a/src/main/java/com/github/elenterius/biomancy/client/gui/DigesterScreen.java b/src/main/java/com/github/elenterius/biomancy/client/gui/DigesterScreen.java
index 5f4c19d98..9e81009d6 100644
--- a/src/main/java/com/github/elenterius/biomancy/client/gui/DigesterScreen.java
+++ b/src/main/java/com/github/elenterius/biomancy/client/gui/DigesterScreen.java
@@ -72,7 +72,7 @@ protected void renderTooltip(PoseStack poseStack, int mouseX, int mouseY) {
}
private void drawFuelTooltip(PoseStack poseStack, int mouseX, int mouseY) {
- int maxFuel = menu.getMAxFuelAmount();
+ int maxFuel = menu.getMaxFuelAmount();
int fuelAmount = menu.getFuelAmount();
int totalFuelCost = menu.getFuelCost();
GuiRenderUtil.drawFuelTooltip(this, poseStack, mouseX, mouseY, maxFuel, fuelAmount, totalFuelCost);
diff --git a/src/main/java/com/github/elenterius/biomancy/client/gui/InjectorScreen.java b/src/main/java/com/github/elenterius/biomancy/client/gui/InjectorScreen.java
index 64f1192d4..cd4d55cd5 100644
--- a/src/main/java/com/github/elenterius/biomancy/client/gui/InjectorScreen.java
+++ b/src/main/java/com/github/elenterius/biomancy/client/gui/InjectorScreen.java
@@ -2,12 +2,12 @@
import com.github.elenterius.biomancy.api.serum.Serum;
import com.github.elenterius.biomancy.api.serum.SerumContainer;
-import com.github.elenterius.biomancy.chat.ComponentUtil;
import com.github.elenterius.biomancy.client.util.GuiRenderUtil;
import com.github.elenterius.biomancy.item.injector.InjectorItem;
import com.github.elenterius.biomancy.network.ModNetworkHandler;
import com.github.elenterius.biomancy.styles.ColorStyles;
import com.github.elenterius.biomancy.styles.TextStyles;
+import com.github.elenterius.biomancy.util.ComponentUtil;
import com.mojang.blaze3d.platform.InputConstants;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
diff --git a/src/main/java/com/github/elenterius/biomancy/client/particle/ParticleProviders.java b/src/main/java/com/github/elenterius/biomancy/client/particle/ParticleProviders.java
new file mode 100644
index 000000000..8cf12ee5e
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/client/particle/ParticleProviders.java
@@ -0,0 +1,65 @@
+package com.github.elenterius.biomancy.client.particle;
+
+import com.github.elenterius.biomancy.init.ModFluids;
+import com.github.elenterius.biomancy.init.ModMobEffects;
+import com.github.elenterius.biomancy.init.ModParticleTypes;
+import net.minecraft.client.multiplayer.ClientLevel;
+import net.minecraft.client.particle.Particle;
+import net.minecraft.client.particle.ParticleProvider;
+import net.minecraft.client.particle.SpriteSet;
+import net.minecraft.core.particles.SimpleParticleType;
+import net.minecraftforge.api.distmarker.Dist;
+import net.minecraftforge.api.distmarker.OnlyIn;
+
+public final class ParticleProviders {
+ private ParticleProviders() {}
+
+ @OnlyIn(Dist.CLIENT)
+ public static class AcidLandProvider implements ParticleProvider {
+ protected final SpriteSet sprite;
+
+ public AcidLandProvider(SpriteSet pSprites) {
+ this.sprite = pSprites;
+ }
+
+ public Particle createParticle(SimpleParticleType type, ClientLevel level, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) {
+ VanillaDripParticle particle = new VanillaDripParticle.DripLandParticle(level, x, y, z, ModFluids.ACID.get());
+ particle.setColorRGB(ModMobEffects.CORROSIVE.get().getColor());
+ particle.pickSprite(sprite);
+ return particle;
+ }
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ public static class AcidHangProvider implements ParticleProvider {
+ protected final SpriteSet sprite;
+
+ public AcidHangProvider(SpriteSet pSprites) {
+ this.sprite = pSprites;
+ }
+
+ public Particle createParticle(SimpleParticleType type, ClientLevel level, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) {
+ VanillaDripParticle particle = new VanillaDripParticle.DripHangParticle(level, x, y, z, ModFluids.ACID.get(), ModParticleTypes.FALLING_ACID.get());
+ particle.setColorRGB(ModMobEffects.CORROSIVE.get().getColor());
+ particle.pickSprite(sprite);
+ return particle;
+ }
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ public static class AcidFallProvider implements ParticleProvider {
+ protected final SpriteSet sprite;
+
+ public AcidFallProvider(SpriteSet pSprites) {
+ this.sprite = pSprites;
+ }
+
+ public Particle createParticle(SimpleParticleType type, ClientLevel level, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) {
+ VanillaDripParticle particle = new VanillaDripParticle.AcidFallAndLandParticle(level, x, y, z, ModFluids.ACID.get(), ModParticleTypes.LANDING_ACID.get());
+ particle.setColorRGB(ModMobEffects.CORROSIVE.get().getColor());
+ particle.pickSprite(sprite);
+ return particle;
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/elenterius/biomancy/client/particle/VanillaDripParticle.java b/src/main/java/com/github/elenterius/biomancy/client/particle/VanillaDripParticle.java
new file mode 100644
index 000000000..42ac6f3ec
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/client/particle/VanillaDripParticle.java
@@ -0,0 +1,191 @@
+package com.github.elenterius.biomancy.client.particle;
+
+import net.minecraft.client.multiplayer.ClientLevel;
+import net.minecraft.client.particle.ParticleRenderType;
+import net.minecraft.client.particle.TextureSheetParticle;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.particles.ParticleOptions;
+import net.minecraft.core.particles.ParticleTypes;
+import net.minecraft.sounds.SoundEvents;
+import net.minecraft.sounds.SoundSource;
+import net.minecraft.util.FastColor;
+import net.minecraft.util.Mth;
+import net.minecraft.world.level.material.Fluid;
+import net.minecraft.world.level.material.FluidState;
+import net.minecraftforge.api.distmarker.Dist;
+import net.minecraftforge.api.distmarker.OnlyIn;
+
+/**
+ * Almost exact copy of vanilla code because DripParticle class can't be extended
+ */
+@OnlyIn(Dist.CLIENT)
+public class VanillaDripParticle extends TextureSheetParticle {
+
+ protected final Fluid type;
+ private boolean isGlowing;
+
+ protected VanillaDripParticle(ClientLevel level, double x, double y, double z, Fluid fluid) {
+ super(level, x, y, z);
+ this.setSize(0.01F, 0.01F);
+ this.gravity = 0.06F;
+ this.type = fluid;
+ }
+
+ public ParticleRenderType getRenderType() {
+ return ParticleRenderType.PARTICLE_SHEET_OPAQUE;
+ }
+
+ protected void setGlowing(boolean glowing) {
+ isGlowing = glowing;
+ }
+
+ @Override
+ public int getLightColor(float partialTick) {
+ return isGlowing ? 0xf0 : super.getLightColor(partialTick);
+ }
+
+ @Override
+ public void tick() {
+ xo = x;
+ yo = y;
+ zo = z;
+
+ preMoveUpdate();
+
+ if (!removed) {
+ yd -= gravity;
+ move(xd, yd, zd);
+
+ postMoveUpdate();
+
+ if (!removed) {
+ xd *= 0.9800000190734863;
+ yd *= 0.9800000190734863;
+ zd *= 0.9800000190734863;
+ BlockPos blockPos = new BlockPos(x, y, z);
+ FluidState fluidState = level.getFluidState(blockPos);
+ if (fluidState.getType() == type && y < (blockPos.getY() + fluidState.getHeight(level, blockPos))) {
+ remove();
+ }
+ }
+ }
+ }
+
+ protected void preMoveUpdate() {
+ if (lifetime-- <= 0) {
+ remove();
+ }
+ }
+
+ protected void postMoveUpdate() { /* placeholder */ }
+
+ protected void setColorRGB(int color) {
+ rCol = FastColor.ARGB32.red(color) / 255f;
+ gCol = FastColor.ARGB32.green(color) / 255f;
+ bCol = FastColor.ARGB32.blue(color) / 255f;
+ }
+
+ protected void setColorARGB(int color) {
+ rCol = FastColor.ARGB32.red(color) / 255f;
+ gCol = FastColor.ARGB32.green(color) / 255f;
+ bCol = FastColor.ARGB32.blue(color) / 255f;
+ alpha = FastColor.ARGB32.alpha(color) / 255f;
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ protected static class DripLandParticle extends VanillaDripParticle {
+ protected DripLandParticle(ClientLevel level, double x, double y, double z, Fluid fluid) {
+ super(level, x, y, z, fluid);
+ this.lifetime = (int) (16.0f / (Math.random() * 0.8f + 0.2f));
+ }
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ protected static class DripHangParticle extends VanillaDripParticle {
+ protected final ParticleOptions fallingParticle;
+
+ protected DripHangParticle(ClientLevel level, double x, double y, double z, Fluid fluid, ParticleOptions fallingParticle) {
+ super(level, x, y, z, fluid);
+ this.fallingParticle = fallingParticle;
+ this.gravity *= 0.02F;
+ this.lifetime = 40;
+ }
+
+ @Override
+ protected void preMoveUpdate() {
+ if (lifetime-- <= 0) {
+ remove();
+ level.addParticle(fallingParticle, x, y, z, xd, yd, zd);
+ }
+ }
+
+ @Override
+ protected void postMoveUpdate() {
+ xd *= 0.02;
+ yd *= 0.02;
+ zd *= 0.02;
+ }
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ protected static class FallingParticle extends VanillaDripParticle {
+ protected FallingParticle(ClientLevel level, double x, double y, double z, Fluid fluid) {
+ this(level, x, y, z, fluid, (int) (64.0f / (Math.random() * 0.8f + 0.2f)));
+ }
+
+ protected FallingParticle(ClientLevel level, double x, double y, double z, Fluid fluid, int lifetime) {
+ super(level, x, y, z, fluid);
+ this.lifetime = lifetime;
+ }
+
+ @Override
+ protected void postMoveUpdate() {
+ if (onGround) {
+ remove();
+ }
+ }
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ protected static class FallAndLandParticle extends FallingParticle {
+ protected final ParticleOptions landParticle;
+
+ protected FallAndLandParticle(ClientLevel level, double x, double y, double z, Fluid fluid, ParticleOptions landParticle) {
+ super(level, x, y, z, fluid);
+ this.landParticle = landParticle;
+ }
+
+ @Override
+ protected void postMoveUpdate() {
+ if (onGround) {
+ remove();
+ level.addParticle(landParticle, x, y, z, 0, 0, 0);
+ }
+ }
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ protected static class AcidFallAndLandParticle extends FallAndLandParticle {
+ protected AcidFallAndLandParticle(ClientLevel level, double x, double y, double z, Fluid fluid, ParticleOptions landParticle) {
+ super(level, x, y, z, fluid, landParticle);
+ }
+
+ @Override
+ protected void postMoveUpdate() {
+ if (onGround) {
+ remove();
+ level.addParticle(landParticle, x, y, z, 0, 0, 0);
+
+ if (random.nextInt(4) == 0) {
+ float volume = Mth.randomBetween(random, 0.4f, 0.6f);
+ float pitch = Mth.randomBetween(random, 1.8f, 3.4f);
+ level.playLocalSound(x, y, z, SoundEvents.LAVA_EXTINGUISH, SoundSource.BLOCKS, volume, pitch, false);
+ for (int i = 0; i < 4; i++) {
+ level.addParticle(ParticleTypes.LARGE_SMOKE, x + random.nextDouble(), y + 0.2f, z + random.nextDouble(), 0, 0, 0);
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/elenterius/biomancy/client/render/entity/CustomGeoProjectileRenderer.java b/src/main/java/com/github/elenterius/biomancy/client/render/entity/CustomGeoProjectileRenderer.java
new file mode 100644
index 000000000..b1233b34d
--- /dev/null
+++ b/src/main/java/com/github/elenterius/biomancy/client/render/entity/CustomGeoProjectileRenderer.java
@@ -0,0 +1,165 @@
+package com.github.elenterius.biomancy.client.render.entity;
+
+import com.github.elenterius.biomancy.entity.projectile.BaseProjectile;
+import com.mojang.blaze3d.systems.RenderSystem;
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import com.mojang.math.Matrix4f;
+import com.mojang.math.Vector3f;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.renderer.entity.EntityRenderer;
+import net.minecraft.client.renderer.entity.EntityRendererProvider;
+import net.minecraft.client.renderer.texture.OverlayTexture;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.util.Mth;
+import net.minecraft.world.entity.Entity;
+import org.jetbrains.annotations.Nullable;
+import software.bernie.geckolib3.core.IAnimatable;
+import software.bernie.geckolib3.core.IAnimatableModel;
+import software.bernie.geckolib3.core.controller.AnimationController;
+import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
+import software.bernie.geckolib3.core.util.Color;
+import software.bernie.geckolib3.geo.render.built.GeoBone;
+import software.bernie.geckolib3.geo.render.built.GeoModel;
+import software.bernie.geckolib3.model.AnimatedGeoModel;
+import software.bernie.geckolib3.model.provider.GeoModelProvider;
+import software.bernie.geckolib3.model.provider.data.EntityModelData;
+import software.bernie.geckolib3.renderers.geo.IGeoRenderer;
+import software.bernie.geckolib3.util.AnimationUtils;
+import software.bernie.geckolib3.util.EModelRenderCycle;
+import software.bernie.geckolib3.util.IRenderCycle;
+import software.bernie.geckolib3.util.RenderUtils;
+
+import javax.annotation.Nonnull;
+import java.util.Collections;
+
+public class CustomGeoProjectileRenderer extends EntityRenderer implements IGeoRenderer {
+
+ static {
+ AnimationController.addModelFetcher(animatable -> animatable instanceof Entity entity ? (IAnimatableModel