Rework barrels to use JSON recipes for fluid transformation recipes

This commit is contained in:
thedarkcolour 2024-03-11 16:46:15 -07:00
parent 992cb80aec
commit 39a5895c12
78 changed files with 1070 additions and 359 deletions

View File

@ -1,3 +1,9 @@
## Ex Deorum 1.26
- Fluid transformation recipes are now data driven
- Increased drop rate of Iron Ore Chunk
- Updated documentation to explain how to add Ex Deorum recipes through JSON data packs. If you are using KubeJS/CraftTweaker, this will probably be useful to you as well. Check it out [here](https://exdeorum.readthedocs.io/en/latest/datapack/).
- Fixed Witch Water spawning mushrooms when not converting (now, they only spawn while converting from water to witch water)
## Ex Deorum 1.25
- Fixed crash with fluid containers
- Added `exdeorum:summation` result count type for sieve recipes, mostly for converting Ex Nihilo Sequentia recipes over (also usable for loot tables)

View File

@ -1,4 +1,4 @@
// 1.20.1 2024-02-13T15:52:36.681433 Recipes
// 1.20.1 2024-03-11T16:13:53.5720006 Recipes
e37b64428f17e304e91539ac0513456d7ce40cd1 data/exdeorum/advancements/recipes/building_blocks/sponge.json
5ad481a0c376c1a1785a5d3b992064d0ec0bf3b0 data/exdeorum/advancements/recipes/food/end_cake.json
25dd027e844a72b03c95dbe5e3c3dd8c738ceb00 data/exdeorum/advancements/recipes/misc/acacia_barrel.json
@ -174,6 +174,7 @@ b9a34df74ce0ee9c4247a9a64784c851eb1de58c data/exdeorum/recipes/barrel_compost/wo
6d2469e79cbc88817a4582fa467857d65d9b70ed data/exdeorum/recipes/barrel_fluid_mixing/obsidian.json
4657af4003335ca25d2f92c43fd82dc3b3ad7fb2 data/exdeorum/recipes/barrel_fluid_mixing/slime_block.json
5e2a7bd06a83260c18c007bcf793c336faef264d data/exdeorum/recipes/barrel_fluid_mixing/stone.json
89c033548e54ca28030b79f07249787b51d7db7d data/exdeorum/recipes/barrel_fluid_transformation/witch_water.json
bdcdeae9d06028ce943d06c367b58677efe03fa8 data/exdeorum/recipes/barrel_mixing/clay.json
72f969f4db1f82a627df573c866a1b291e540a0a data/exdeorum/recipes/barrel_mixing/end_stone.json
37f73e219fda3c6f56bf55f8ec7f97586ecdbae1 data/exdeorum/recipes/barrel_mixing/ice.json
@ -298,10 +299,10 @@ f1368be282014a882ece8c28d43ea1d3f8c19ad2 data/exdeorum/recipes/jacaranda_sieve.j
332d5396af038b56047e88fcad713478e45cbd97 data/exdeorum/recipes/jungle_barrel.json
7239040d0cee42fe9077c89eaa3d768a07db0557 data/exdeorum/recipes/jungle_crucible.json
bffa756563ac5aa791f299ae6d7d042813c2614a data/exdeorum/recipes/jungle_sieve.json
d24ed2178e5875da5e0a6f82b5ac9c2ece4b64ff data/exdeorum/recipes/lava_crucible/cobblestone.json
0963c17c9f78907017fa0192c684f016c39f31eb data/exdeorum/recipes/lava_crucible/gravel.json
e9affa16c926fe63ca2270a81aba4e33cd0b198b data/exdeorum/recipes/lava_crucible/netherrack.json
20744c980e4a68f67acea24af617f1ddb865f9a3 data/exdeorum/recipes/lava_crucible/stone.json
83f2a9b35dbee148a7f74e2bd3d85daa8f276c74 data/exdeorum/recipes/lava_crucible/cobblestone.json
9058a167bc4eab87e02be115ae6391aafd82177d data/exdeorum/recipes/lava_crucible/gravel.json
f6c2801f5410a26fba7ff632b5c7ce80d2df3042 data/exdeorum/recipes/lava_crucible/netherrack.json
6dd34eedb61a5063e283739ee1e033f52cfb6607 data/exdeorum/recipes/lava_crucible/stone.json
de4aec27404547b2cc9a709e54eba1459c210149 data/exdeorum/recipes/lunar_barrel.json
848e724409a1ade08e1d40a28b6d570e0362cb45 data/exdeorum/recipes/lunar_crucible.json
6760d41983e3553c785f251c1ab4813db7312b32 data/exdeorum/recipes/lunar_sieve.json
@ -399,7 +400,7 @@ c546193f9cab7af9c92ea4a05c080c2ea24f33a2 data/exdeorum/recipes/sieve/crushed_dee
db7026d3f31ec9a4e2ac085101a49cbcbc67b712 data/exdeorum/recipes/sieve/crushed_deepslate/diamond/emerald.json
69e4b707f2e433bda0742dfbba9223f0d4dbf872 data/exdeorum/recipes/sieve/crushed_deepslate/diamond/gold_ore_chunk.json
b60486888c693bef336989c8e36b62f8bc60ce28 data/exdeorum/recipes/sieve/crushed_deepslate/diamond/iridium_ore_chunk.json
91dabfb0a3256393d74779c2bc291a0b13f93eb4 data/exdeorum/recipes/sieve/crushed_deepslate/diamond/iron_ore_chunk.json
daf4aea771f0bd538b42af2788dfb6bf64ea4398 data/exdeorum/recipes/sieve/crushed_deepslate/diamond/iron_ore_chunk.json
fa548967f2323aa67b8b0adb3802cb513047dff7 data/exdeorum/recipes/sieve/crushed_deepslate/diamond/lapis_lazuli.json
1918afd9a0af6536a5a4c0fd90d11143f90f937e data/exdeorum/recipes/sieve/crushed_deepslate/diamond/lead_ore_chunk.json
fce785ad95a0f7c2f5077c7fe2f98ce64e3d4f92 data/exdeorum/recipes/sieve/crushed_deepslate/diamond/lithium_ore_chunk.json
@ -421,7 +422,7 @@ d789f6cde58525c3fe965eb40ececa89e4ee8241 data/exdeorum/recipes/sieve/crushed_dee
f90e1a71760aea8e3bede5b4ad8607c172e42b0e data/exdeorum/recipes/sieve/crushed_deepslate/flint/emerald.json
925ebffabfed246a52990df6db690d64b3242875 data/exdeorum/recipes/sieve/crushed_deepslate/flint/gold_ore_chunk.json
05d695f74dea3e675f4b85bb42174c97a57cf96c data/exdeorum/recipes/sieve/crushed_deepslate/flint/iridium_ore_chunk.json
c8053bbcfc5f7b8933e09517b6457578401603db data/exdeorum/recipes/sieve/crushed_deepslate/flint/iron_ore_chunk.json
93ceac1deecc354104bcfc881fab201754fcb18c data/exdeorum/recipes/sieve/crushed_deepslate/flint/iron_ore_chunk.json
28d91d9c411f7a1d9daec605b3c1a204e75f063a data/exdeorum/recipes/sieve/crushed_deepslate/flint/lapis_lazuli.json
7b3cc3cf4af738377cef6d50dae392fc64e8848d data/exdeorum/recipes/sieve/crushed_deepslate/flint/lead_ore_chunk.json
eb1dc810e1f4ba76ce23b0799acfbc5f43e34eb7 data/exdeorum/recipes/sieve/crushed_deepslate/flint/lithium_ore_chunk.json
@ -443,7 +444,7 @@ a4b81bbfbeb70efa064fe6ea1eea68b6f2da96c8 data/exdeorum/recipes/sieve/crushed_dee
355bbd4ef545137d3d1a0754f272297dbec3e1b7 data/exdeorum/recipes/sieve/crushed_deepslate/golden/gold_nugget.json
7d701e272f47a5029786c2a59ceed24a8a6fe339 data/exdeorum/recipes/sieve/crushed_deepslate/golden/gold_ore_chunk.json
21ca6821d3f1e259eb4efa2046bd53315f588b21 data/exdeorum/recipes/sieve/crushed_deepslate/golden/iridium_ore_chunk.json
93ace70556c0b59bfd2de7b14562506b032dbb46 data/exdeorum/recipes/sieve/crushed_deepslate/golden/iron_ore_chunk.json
22093b07c1075eb377848e39675704cb1f89e833 data/exdeorum/recipes/sieve/crushed_deepslate/golden/iron_ore_chunk.json
f82704720c2b43f9f482aac5109d00d0419186ff data/exdeorum/recipes/sieve/crushed_deepslate/golden/lapis_lazuli.json
c2a7d4076e92291d7b183c9c30f85848a748883b data/exdeorum/recipes/sieve/crushed_deepslate/golden/lead_ore_chunk.json
bb0991f3c3362fa59f6221a13637c4a60335c5de data/exdeorum/recipes/sieve/crushed_deepslate/golden/lithium_ore_chunk.json
@ -464,7 +465,7 @@ a573a2731f646884bd3f4ae61136280dde8c2c96 data/exdeorum/recipes/sieve/crushed_dee
f1a444b52e9e1696a846592b833a2ceb63c994bc data/exdeorum/recipes/sieve/crushed_deepslate/iron/emerald.json
f387102be827d0ad7ef6590bdd97435adc0adb19 data/exdeorum/recipes/sieve/crushed_deepslate/iron/gold_ore_chunk.json
05129a20fdb122ca64e61252ae7011b0189c4c4f data/exdeorum/recipes/sieve/crushed_deepslate/iron/iridium_ore_chunk.json
4a9e056ddaeafce083fa91f4adca89f28e409b42 data/exdeorum/recipes/sieve/crushed_deepslate/iron/iron_ore_chunk.json
7424678a70bbfe69af04e248aa2dbf92ea71b00d data/exdeorum/recipes/sieve/crushed_deepslate/iron/iron_ore_chunk.json
e2356f1aa76f9f39f3d9eb71e34b206d567456be data/exdeorum/recipes/sieve/crushed_deepslate/iron/lapis_lazuli.json
9601262f949921d5bdd6c3fe2b8bd1aa75101007 data/exdeorum/recipes/sieve/crushed_deepslate/iron/lead_ore_chunk.json
6988d47f7ac27c7b0c2f43b22080df420a00cae2 data/exdeorum/recipes/sieve/crushed_deepslate/iron/lithium_ore_chunk.json
@ -484,7 +485,7 @@ cdc25d35d8ec98f7cca1a74dd417f3590a839583 data/exdeorum/recipes/sieve/crushed_dee
69c3f29af10cbd0b6a929ea29612e54678687dec data/exdeorum/recipes/sieve/crushed_deepslate/netherite/emerald.json
a743371407c1200e19049de0c1cfb7db54e9e224 data/exdeorum/recipes/sieve/crushed_deepslate/netherite/gold_ore_chunk.json
55e3999812bcae17b63f1815782979969733cbd1 data/exdeorum/recipes/sieve/crushed_deepslate/netherite/iridium_ore_chunk.json
641be85ac7300b45c139844316086cb5c30b8599 data/exdeorum/recipes/sieve/crushed_deepslate/netherite/iron_ore_chunk.json
fc19cf491131e9fc0aa47ae2eab42f6cc378a666 data/exdeorum/recipes/sieve/crushed_deepslate/netherite/iron_ore_chunk.json
0d84fa101dd247f42867022a1aa15cb45e719ef3 data/exdeorum/recipes/sieve/crushed_deepslate/netherite/lapis_lazuli.json
2b8244da348847d271355e1cadaa2d08e285bc8f data/exdeorum/recipes/sieve/crushed_deepslate/netherite/lead_ore_chunk.json
95537aa47bd9ad122c4330e70f593ebdee3c7676 data/exdeorum/recipes/sieve/crushed_deepslate/netherite/lithium_ore_chunk.json
@ -504,7 +505,7 @@ e5e179dec565277380d0d0b4e35990c8baeeda65 data/exdeorum/recipes/sieve/crushed_dee
7d3b675754200bcd0d44a1b595a7cd1443ce3f28 data/exdeorum/recipes/sieve/crushed_deepslate/string/emerald.json
744b9140fc69e1cf0a59d72524baf1770d45ae8c data/exdeorum/recipes/sieve/crushed_deepslate/string/gold_ore_chunk.json
b37bd819bfe576ac0f75b9eab2a59436832ad1a4 data/exdeorum/recipes/sieve/crushed_deepslate/string/iridium_ore_chunk.json
a2e895b8b68e6cddf045a4dc97f323679e37be60 data/exdeorum/recipes/sieve/crushed_deepslate/string/iron_ore_chunk.json
88bff049d23e5ea9ff4946c3b8deb322ff4abd23 data/exdeorum/recipes/sieve/crushed_deepslate/string/iron_ore_chunk.json
c2165469fc079114e44a96c89753e01e276d4f05 data/exdeorum/recipes/sieve/crushed_deepslate/string/lapis_lazuli.json
cd1cb531c5e7cdc9c96450e4bf0f411a279d3fd3 data/exdeorum/recipes/sieve/crushed_deepslate/string/lead_ore_chunk.json
defb4a676f1e5f08d81ba04acecb452bd497f8ec data/exdeorum/recipes/sieve/crushed_deepslate/string/lithium_ore_chunk.json
@ -744,7 +745,7 @@ ac9139345f1b1d4bd8fb48350d3a6df9a33c2a93 data/exdeorum/recipes/sieve/gravel/diam
66d27aa930f24ab223056cd8e306a62b0d7c91c9 data/exdeorum/recipes/sieve/gravel/diamond/flint.json
3544e4e64e54f9ab80015c8d708e397777cb3212 data/exdeorum/recipes/sieve/gravel/diamond/gold_ore_chunk.json
b25b9a23f50fa60719f74ffc26b53017f8d74cd0 data/exdeorum/recipes/sieve/gravel/diamond/iridium_ore_chunk.json
6cf8e4f262fa4e4153bcaa6c684854712f720021 data/exdeorum/recipes/sieve/gravel/diamond/iron_ore_chunk.json
552825678b5e7967289200ad01c1ef6beeefbe06 data/exdeorum/recipes/sieve/gravel/diamond/iron_ore_chunk.json
71084e96ae9c98c76ecb03b38de241b72ad0cf8c data/exdeorum/recipes/sieve/gravel/diamond/lapis_lazuli.json
981752f69c4094f1cb4a8d0272399117eb28f19b data/exdeorum/recipes/sieve/gravel/diamond/lead_ore_chunk.json
be9d385c0cb20baf3a5a084d4110e81fae2c2988 data/exdeorum/recipes/sieve/gravel/diamond/magnesium_ore_chunk.json
@ -767,7 +768,7 @@ adfae10501cc5a1f7d13ce93da1fe2b9f2d26624 data/exdeorum/recipes/sieve/gravel/flin
d988d062013ae4d6afcb8e5e13065518a012d126 data/exdeorum/recipes/sieve/gravel/flint/gold_ore_chunk.json
a3f7e6269846b25acbd994b0e564020f7a22cd0f data/exdeorum/recipes/sieve/gravel/flint/granite_pebble.json
cb1601e4e798f148a352d0910a028f594a944d4c data/exdeorum/recipes/sieve/gravel/flint/iridium_ore_chunk.json
1526d58887ae5ca553fb5d6de0edbb4ce85dc916 data/exdeorum/recipes/sieve/gravel/flint/iron_ore_chunk.json
5f08daac6cb75b6fda8441dfc43be424fd2e32ec data/exdeorum/recipes/sieve/gravel/flint/iron_ore_chunk.json
702f85e882f2b10a6613f41074ccfc9b759c42b9 data/exdeorum/recipes/sieve/gravel/flint/lapis_lazuli.json
91d01d076b8a72827d270de34fe03022a44c9291 data/exdeorum/recipes/sieve/gravel/flint/lead_ore_chunk.json
0e26f51a7c57c969447ca398021c10225c38d839 data/exdeorum/recipes/sieve/gravel/flint/magnesium_ore_chunk.json
@ -791,7 +792,7 @@ b910213c60616555b2701eab2e6ed6c10ab2996d data/exdeorum/recipes/sieve/gravel/gold
4f0edad66d6d5899a81fb32c11da8b4f4943e483 data/exdeorum/recipes/sieve/gravel/golden/gold_nugget.json
4be0b7be825c07b1406f45f6b9182d6c0a643cb3 data/exdeorum/recipes/sieve/gravel/golden/gold_ore_chunk.json
5e940efaf67afe5273df3bdea9054e57f2685d52 data/exdeorum/recipes/sieve/gravel/golden/iridium_ore_chunk.json
5a33eb0cec0ddfef976f26708dcc2f55ac7f167e data/exdeorum/recipes/sieve/gravel/golden/iron_ore_chunk.json
bf2e0f336645be47182a8cec4c81ab97d09ead65 data/exdeorum/recipes/sieve/gravel/golden/iron_ore_chunk.json
ae0acc3deb886e04d8226b1cbe36e67a8dd360bf data/exdeorum/recipes/sieve/gravel/golden/lapis_lazuli.json
35f01fd1939936fa63ea4c13afda51a444e139e8 data/exdeorum/recipes/sieve/gravel/golden/lead_ore_chunk.json
ff3cb01dbb798637b1cbc6bfc3038944595ae519 data/exdeorum/recipes/sieve/gravel/golden/magnesium_ore_chunk.json
@ -814,7 +815,7 @@ e28dd0cc2ae440c324a78b97757266ef0243b94e data/exdeorum/recipes/sieve/gravel/iron
6610b8fb3cb40f1d5e149fe3831d82063add8b5d data/exdeorum/recipes/sieve/gravel/iron/flint.json
5bbb6415d53f5efac6799f654bc3486a277aed31 data/exdeorum/recipes/sieve/gravel/iron/gold_ore_chunk.json
23e6a404d85a3351772fb713b5db7c5582345e4c data/exdeorum/recipes/sieve/gravel/iron/iridium_ore_chunk.json
be90f3b4db2a9e24f218ca9ba2b96bcbb607e693 data/exdeorum/recipes/sieve/gravel/iron/iron_ore_chunk.json
3d355020c82eeed520d8a33a4b35bc5703eaa991 data/exdeorum/recipes/sieve/gravel/iron/iron_ore_chunk.json
b8b54b1de7034163b0f679f7e0368530dc15e159 data/exdeorum/recipes/sieve/gravel/iron/lapis_lazuli.json
c02f2b1d17c3cdb68ed9b6afd41bd30adbc4fda6 data/exdeorum/recipes/sieve/gravel/iron/lead_ore_chunk.json
68757b584fee704ad0c459b16eab12f729362a5e data/exdeorum/recipes/sieve/gravel/iron/magnesium_ore_chunk.json
@ -836,7 +837,7 @@ cb71ef4f529eafcdc9b37ac05c69d5f382ff85ea data/exdeorum/recipes/sieve/gravel/iron
41aaa9c5a1b61ea79b231528a6e76c9c1d273331 data/exdeorum/recipes/sieve/gravel/netherite/gold_nugget.json
22a8a86bd12d7db9a4929121692dccfe3616a942 data/exdeorum/recipes/sieve/gravel/netherite/gold_ore_chunk.json
f2c95dc2b7bee18aa27ad336ad470957050148d3 data/exdeorum/recipes/sieve/gravel/netherite/iridium_ore_chunk.json
e28a30509e84956d6d193911cfe8ba252a2825cf data/exdeorum/recipes/sieve/gravel/netherite/iron_ore_chunk.json
ad8d3754eb5262296af4131a484c812628dd7d08 data/exdeorum/recipes/sieve/gravel/netherite/iron_ore_chunk.json
8f49a2cdf84583537955e4c27c854bf34dc47903 data/exdeorum/recipes/sieve/gravel/netherite/lapis_lazuli.json
f12a4bd98ef79dd7e9073d1626e8294f11f900ae data/exdeorum/recipes/sieve/gravel/netherite/lead_ore_chunk.json
61dda81ce471e511fc24d01c84866549a0c2888a data/exdeorum/recipes/sieve/gravel/netherite/magnesium_ore_chunk.json
@ -857,7 +858,7 @@ bd1ce763ae605e9a0d82e4afa58c4811516bc6bf data/exdeorum/recipes/sieve/gravel/stri
b298e2f51255b88beea1394e2f609768fbb36921 data/exdeorum/recipes/sieve/gravel/string/flint.json
0c0e184928b7371b1cabaca16b51d137a52fc77b data/exdeorum/recipes/sieve/gravel/string/gold_ore_chunk.json
1a3a7eba846fb34fa5391dc7fb29509011a7f88c data/exdeorum/recipes/sieve/gravel/string/iridium_ore_chunk.json
8006ea24e8d9c89a1886e806659ab1bb733da534 data/exdeorum/recipes/sieve/gravel/string/iron_ore_chunk.json
cbe0eed19afb1c57760aafa210546a38e265f287 data/exdeorum/recipes/sieve/gravel/string/iron_ore_chunk.json
19ddad521fcb43ea69e4aeda92f8ea841630c530 data/exdeorum/recipes/sieve/gravel/string/lapis_lazuli.json
f245cf69e06874c43bc2bdaabb7806c59d274c93 data/exdeorum/recipes/sieve/gravel/string/lead_ore_chunk.json
78081972da9f17787319a28bc5d29b50ca8fab12 data/exdeorum/recipes/sieve/gravel/string/magnesium_ore_chunk.json
@ -1228,32 +1229,32 @@ e6ff95b6fbc43c73a537174e01c9eb519e8fdef1 data/exdeorum/recipes/unfired_porcelain
346b70c2d2516f6e735fd1f156e22a649175813d data/exdeorum/recipes/warped_barrel.json
1ae1b311f2e370c924041da80fea01ac8da870c5 data/exdeorum/recipes/warped_crucible.json
7d589e398d803bc7a30614f6ee4aa0d48ca3540e data/exdeorum/recipes/warped_sieve.json
4fbb682aa185e8d9d945619554dc98015221a4eb data/exdeorum/recipes/water_crucible/apple.json
fa23650a3d75ed6278d9c3860aa6ea086371210b data/exdeorum/recipes/water_crucible/beetroot.json
8fed4fdb981ca82436919a074fc1166a2fc6385d data/exdeorum/recipes/water_crucible/cactus.json
8d9de0f7eb46ffb7990a9ac311ec697dffa40443 data/exdeorum/recipes/water_crucible/carrot.json
b191c567f221393c91baaaf456212caebee30048 data/exdeorum/recipes/water_crucible/grass.json
a71db1fcbabb44ed0a0a709175ca2a419b98caa8 data/exdeorum/recipes/water_crucible/grass_block.json
1a31f9a9826fc882acc135c40845b1f227476c7c data/exdeorum/recipes/water_crucible/leaves.json
0e8f136f5fa986bc1c73e063cad5377597fc1a6d data/exdeorum/recipes/water_crucible/lily_pad.json
27134a6501957007812b98886e16d22cd8517ee0 data/exdeorum/recipes/water_crucible/melon.json
d9c0f111e2ae9715cd76a9d5f0ceadce72e34c87 data/exdeorum/recipes/water_crucible/melon_slice.json
3252ccfd40508d9b50e881cee8b5e50e1be7ccee data/exdeorum/recipes/water_crucible/moss.json
8e2e91cb5d81688355ef9ad4f1eb859af24973bb data/exdeorum/recipes/water_crucible/moss_carpet.json
4a5b07cf133e13fc6c2c5d3ea56a60b21d836c27 data/exdeorum/recipes/water_crucible/mushrooms.json
b4674be18b463bed47425ea85f4dd992480c2409 data/exdeorum/recipes/water_crucible/potato.json
0505bf31de1c13f3a22ee2cbdd1595bbb4857692 data/exdeorum/recipes/water_crucible/pumpkin.json
8b04ebb043ce62c0f17adf40cb45431f8e54701f data/exdeorum/recipes/water_crucible/saplings.json
c3ac3ad583b38351ae54d5fe291506dd87d402ab data/exdeorum/recipes/water_crucible/seagrass.json
a48d1f3abe9bf8607096ee8be1ec70d670dfd8d3 data/exdeorum/recipes/water_crucible/sea_pickle.json
43440237534dba69b9f4d97b84148b0e6f131c61 data/exdeorum/recipes/water_crucible/seeds.json
7668124adff54b4cc345e1338ec90ed8b84662c9 data/exdeorum/recipes/water_crucible/seeds_and_spores.json
dabaaa0c9db5dd4668b528df176606609f45c0ce data/exdeorum/recipes/water_crucible/small_flowers.json
0b210ee847c361d8568e0b581ea1e0dfca16fc6c data/exdeorum/recipes/water_crucible/spore_blossom.json
8198da30f7d529f2350f8e276a7660a15bba0a4f data/exdeorum/recipes/water_crucible/sugar_cane.json
3927d17ed5a24132956fa60b51bdb22e67ef4626 data/exdeorum/recipes/water_crucible/sweet_berries.json
9d4abedfd8af2e988c4f11d62ed66743f3e8ac07 data/exdeorum/recipes/water_crucible/tall_flowers.json
a5333ee537aa0e10b740e20a137a24b7699ff52b data/exdeorum/recipes/water_crucible/vine.json
869c22919d2e8004a4d673b02006254bb5d5be03 data/exdeorum/recipes/water_crucible/apple.json
a518997f4f4e48414d2880ddf8bb01e3acdfb4c3 data/exdeorum/recipes/water_crucible/beetroot.json
139a25fefb90ab0f0ce0210062fdb17f2853d691 data/exdeorum/recipes/water_crucible/cactus.json
8fea9c88f60f3f8a85e0fe0f4d7a3efacb2b277e data/exdeorum/recipes/water_crucible/carrot.json
159ec896ca6a807042a8fba793f331fd183bb421 data/exdeorum/recipes/water_crucible/grass.json
cc9b853c700e14c019334bfae36bf8e9f44dfe30 data/exdeorum/recipes/water_crucible/grass_block.json
d2bab4ad2c3ff1bd0d27752e25515c7de4b35ff3 data/exdeorum/recipes/water_crucible/leaves.json
52619bdbe7644f93641449b4d9c2c38ee7fca1ae data/exdeorum/recipes/water_crucible/lily_pad.json
bbbc1d66da41e6a736c7b390c13d7e54ef792ab9 data/exdeorum/recipes/water_crucible/melon.json
d070954f86ceda52d006e8492c3018a10145e0f0 data/exdeorum/recipes/water_crucible/melon_slice.json
7662288906c5cf44dba97891d5cb4dfd31cf8383 data/exdeorum/recipes/water_crucible/moss.json
590c737ca8f89a2aaffb02c007b8f9390ff3571f data/exdeorum/recipes/water_crucible/moss_carpet.json
0d5fc77b292960772c7a84d2c5425980642b86df data/exdeorum/recipes/water_crucible/mushrooms.json
cc35722008f3bef166b65539e4feb180509e79bf data/exdeorum/recipes/water_crucible/potato.json
750ab48f805db09fcb3351ee8db83e9257f7fc53 data/exdeorum/recipes/water_crucible/pumpkin.json
dadcf0474738c5545058e28ed38232b6117f6c28 data/exdeorum/recipes/water_crucible/saplings.json
1dc644ba382fcfc5dbd6bdfac4bc88a5684cfaea data/exdeorum/recipes/water_crucible/seagrass.json
9454184f23b7e567479f743fdf4dfbdc200f55b1 data/exdeorum/recipes/water_crucible/sea_pickle.json
bb86024d353c8347ce35f8c464296045a1589c67 data/exdeorum/recipes/water_crucible/seeds.json
6ac4af54d7c2a89ae06209479c0344a9140906a7 data/exdeorum/recipes/water_crucible/seeds_and_spores.json
312054df63af0de599582452308272719353b890 data/exdeorum/recipes/water_crucible/small_flowers.json
afc3166b1040068a465cd7ec3a532413a87b58d2 data/exdeorum/recipes/water_crucible/spore_blossom.json
ab3ae2221e47670534c49837620fcc61e088aa90 data/exdeorum/recipes/water_crucible/sugar_cane.json
9133a58cb4b5f2f69f0de7a22d1eca2023a29396 data/exdeorum/recipes/water_crucible/sweet_berries.json
3ba422c14ce1396e1686ac41045be16f2ef9c7e8 data/exdeorum/recipes/water_crucible/tall_flowers.json
ae732ce5e5c70e4b5b44396b1db432c22c2dd561 data/exdeorum/recipes/water_crucible/vine.json
05c12b51cdd74a0619df2b35d4d6fafffb84ee0c data/exdeorum/recipes/willow_barrel.json
c1dd98278720c97caccca82449d769c6a8a0f5e0 data/exdeorum/recipes/willow_crucible.json
24e72702e3ae9d0832deac8917603c4565f7aed2 data/exdeorum/recipes/willow_sieve.json

View File

@ -0,0 +1,20 @@
{
"type": "exdeorum:barrel_fluid_transformation",
"base_fluid": "minecraft:lava",
"byproducts": [
{
"value": "minecraft:red_mushroom",
"weight": 50
},
{
"value": "minecraft:brown_mushroom",
"weight": 50
}
],
"catalyst": {
"block": "minecraft:mycelium"
},
"duration": 1700,
"result_color": 2822231,
"result_fluid": "exdeorum:witch_water"
}

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:lava_crucible",
"fluid": {
"Amount": 250,
"FluidName": "minecraft:lava"
"amount": 250,
"fluid": "minecraft:lava"
},
"ingredient": {
"tag": "forge:cobblestone"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:lava_crucible",
"fluid": {
"Amount": 250,
"FluidName": "minecraft:lava"
"amount": 250,
"fluid": "minecraft:lava"
},
"ingredient": {
"tag": "forge:gravel"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:lava_crucible",
"fluid": {
"Amount": 500,
"FluidName": "minecraft:lava"
"amount": 500,
"fluid": "minecraft:lava"
},
"ingredient": {
"tag": "forge:netherrack"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:lava_crucible",
"fluid": {
"Amount": 250,
"FluidName": "minecraft:lava"
"amount": 250,
"fluid": "minecraft:lava"
},
"ingredient": {
"tag": "forge:stone"

View File

@ -8,6 +8,6 @@
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.16
"p": 0.18
}
}

View File

@ -8,6 +8,6 @@
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.11
"p": 0.13
}
}

View File

@ -8,6 +8,6 @@
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.13
"p": 0.15
}
}

View File

@ -8,6 +8,6 @@
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.12
"p": 0.15
}
}

View File

@ -8,6 +8,6 @@
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.17
"p": 0.2
}
}

View File

@ -8,6 +8,6 @@
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.1
"p": 0.12
}
}

View File

@ -8,6 +8,6 @@
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.13
"p": 0.15
}
}

View File

@ -8,6 +8,6 @@
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.08
"p": 0.12
}
}

View File

@ -8,6 +8,6 @@
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.07
"p": 0.14
}
}

View File

@ -8,6 +8,6 @@
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.11
"p": 0.14
}
}

View File

@ -8,6 +8,6 @@
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.13
"p": 0.17
}
}

View File

@ -8,6 +8,6 @@
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.07
"p": 0.1
}
}

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 100,
"FluidName": "minecraft:water"
"amount": 100,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:apple"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 100,
"FluidName": "minecraft:water"
"amount": 100,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:beetroot"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 250,
"FluidName": "minecraft:water"
"amount": 250,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:cactus"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 100,
"FluidName": "minecraft:water"
"amount": 100,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:carrot"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 100,
"FluidName": "minecraft:water"
"amount": 100,
"fluid": "minecraft:water"
},
"ingredient": [
{

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 150,
"FluidName": "minecraft:water"
"amount": 150,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:grass_block"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 250,
"FluidName": "minecraft:water"
"amount": 250,
"fluid": "minecraft:water"
},
"ingredient": {
"tag": "minecraft:leaves"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 150,
"FluidName": "minecraft:water"
"amount": 150,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:lily_pad"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 250,
"FluidName": "minecraft:water"
"amount": 250,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:melon"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 50,
"FluidName": "minecraft:water"
"amount": 50,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:melon_slice"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 150,
"FluidName": "minecraft:water"
"amount": 150,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:moss_block"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 100,
"FluidName": "minecraft:water"
"amount": 100,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:moss_carpet"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 100,
"FluidName": "minecraft:water"
"amount": 100,
"fluid": "minecraft:water"
},
"ingredient": {
"tag": "forge:mushrooms"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 100,
"FluidName": "minecraft:water"
"amount": 100,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:potato"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 250,
"FluidName": "minecraft:water"
"amount": 250,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:pumpkin"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 100,
"FluidName": "minecraft:water"
"amount": 100,
"fluid": "minecraft:water"
},
"ingredient": {
"tag": "minecraft:saplings"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 200,
"FluidName": "minecraft:water"
"amount": 200,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:sea_pickle"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 100,
"FluidName": "minecraft:water"
"amount": 100,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:seagrass"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 50,
"FluidName": "minecraft:water"
"amount": 50,
"fluid": "minecraft:water"
},
"ingredient": {
"tag": "forge:seeds"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 50,
"FluidName": "minecraft:water"
"amount": 50,
"fluid": "minecraft:water"
},
"ingredient": [
{

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 100,
"FluidName": "minecraft:water"
"amount": 100,
"fluid": "minecraft:water"
},
"ingredient": {
"tag": "minecraft:small_flowers"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 150,
"FluidName": "minecraft:water"
"amount": 150,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:spore_blossom"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 100,
"FluidName": "minecraft:water"
"amount": 100,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:sugar_cane"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 50,
"FluidName": "minecraft:water"
"amount": 50,
"fluid": "minecraft:water"
},
"ingredient": [
{

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 200,
"FluidName": "minecraft:water"
"amount": 200,
"fluid": "minecraft:water"
},
"ingredient": {
"tag": "minecraft:tall_flowers"

View File

@ -1,8 +1,8 @@
{
"type": "exdeorum:water_crucible",
"fluid": {
"Amount": 100,
"FluidName": "minecraft:water"
"amount": 100,
"fluid": "minecraft:water"
},
"ingredient": {
"item": "minecraft:vine"

View File

@ -76,11 +76,15 @@ public class BarrelBlock extends EBlock {
@Override
public void neighborChanged(BlockState pState, Level level, BlockPos pos, Block pBlock, BlockPos fromPos, boolean pIsMoving) {
// Only check when the above block is updated
// Only check when the above block is updated, or when the below block is updated
if (fromPos.getY() - pos.getY() == 1) {
if (level.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) {
barrel.tryInWorldFluidMixing();
}
} else if (fromPos.getY() - pos.getY() == -1) {
if (level.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) {
barrel.updateFluidTransform();
}
}
}
}

View File

@ -360,14 +360,7 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
}
}
if (crucible instanceof WaterCrucibleBlockEntity && level.isRainingAt(pos.above())) {
if (crucible.tank.isEmpty()) {
crucible.tank.setFluid(new FluidStack(Fluids.WATER, 1));
crucible.markUpdated();
} else if (crucible.tank.getFluid().getFluid() == Fluids.WATER &&
crucible.tank.getFluidAmount() < crucible.tank.getCapacity()) {
crucible.tank.getFluid().grow(1);
crucible.markUpdated();
}
BarrelBlockEntity.fillRainWater(crucible, crucible.tank);
}
}
}

View File

@ -26,6 +26,7 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.item.ItemEntity;
@ -54,7 +55,7 @@ import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.ItemStackHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.block.BarrelBlock;
import thedarkcolour.exdeorum.blockentity.helper.FluidHelper;
import thedarkcolour.exdeorum.client.CompostColors;
@ -62,6 +63,7 @@ import thedarkcolour.exdeorum.config.EConfig;
import thedarkcolour.exdeorum.material.BarrelMaterial;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe;
import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe;
import thedarkcolour.exdeorum.registry.EBlockEntities;
import thedarkcolour.exdeorum.registry.EFluids;
@ -73,10 +75,14 @@ public class BarrelBlockEntity extends EBlockEntity {
public float progress;
public short compost;
// compost colors (has to be shorts because Java bytes are signed and only go to 127, when need 255)
// also used for fluid transformation (destination color)
public short r, g, b;
// Used to avoid triggering obsidian dupes in onContentsChanged, because Forge's FluidUtil actually modifies the tank for some reason
private boolean isBeingFilledByPlayer;
public final boolean transparent;
// Current transformation recipe
@Nullable
public FluidTransformationRecipe currentTransformRecipe = null;
private final LazyOptional<IItemHandler> itemHandler = LazyOptional.of(() -> this.item);
private final LazyOptional<IFluidHandler> fluidHandler = LazyOptional.of(() -> this.tank);
@ -158,7 +164,7 @@ public class BarrelBlockEntity extends EBlockEntity {
}
public boolean isBurning() {
return isHotFluid(this.tank.getFluid().getFluid().getFluidType()) && this.progress != 0.0f;
return this.getBlockState().ignitedByLava() && isHotFluid(this.tank.getFluid().getFluid().getFluidType()) && this.progress != 0.0f;
}
// Composting is in progress if at 1000. When finished, compost is set back to 0
@ -453,6 +459,26 @@ public class BarrelBlockEntity extends EBlockEntity {
}
}
public void updateFluidTransform() {
if (!this.level.isClientSide) {
var belowState = this.level.getBlockState(this.worldPosition.below());
if (this.tank.getFluidAmount() != 1000) {
this.currentTransformRecipe = null;
} else {
this.currentTransformRecipe = RecipeUtil.getFluidTransformationRecipe(this.tank.getFluid().getFluid(), belowState);
if (this.currentTransformRecipe != null) {
var color = this.currentTransformRecipe.resultColor;
this.r = (short) ((color >> 16) & 0xff);
this.g = (short) ((color >> 8) & 0xff);
this.b = (short) ((color) & 0xff);
markUpdated();
}
}
this.progress = 0.0f;
}
}
public static class Ticker implements BlockEntityTicker<BarrelBlockEntity> {
@Override
public void tick(Level level, BlockPos pos, BlockState state, BarrelBlockEntity barrel) {
@ -460,31 +486,61 @@ public class BarrelBlockEntity extends EBlockEntity {
// Turn compost to dirt
if (barrel.isComposting()) {
barrel.doCompost();
} else if (barrel.hasFullWater()) {
var rand = level.random;
var mycelium = 0f;
} else if (isHotFluid(barrel.tank.getFluid().getFluid().getFluidType()) && state.ignitedByLava()) {
if ((barrel.progress += getProgressStep()) >= 1.0f) {
if (barrel.tank.getFluidAmount() == 1000) {
var fluid = barrel.tank.getFluid().getFluid();
level.setBlockAndUpdate(pos, fluid.getFluidType().getBlockForFluidState(level, pos, fluid.defaultFluidState()));
} else {
level.setBlockAndUpdate(pos, Blocks.FIRE.defaultBlockState());
}
}
barrel.markUpdated();
} else if (level.isRainingAt(pos.above()) && barrel.item.getStackInSlot(0).isEmpty() && barrel.compost == 0) {
fillRainWater(barrel, barrel.tank);
} else if (barrel.currentTransformRecipe != null) {
var recipe = barrel.currentTransformRecipe;
var catalysts = 0;
for (BlockPos cursor : BlockPos.betweenClosed(pos.getX() - 1, pos.getY() - 1, pos.getZ() - 1, pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1)) {
if (level.getBlockState(cursor).getBlock() == Blocks.MYCELIUM) {
mycelium += 0.15f;
for (var cursor : BlockPos.betweenClosed(pos.getX() - 1, pos.getY() - 1, pos.getZ() - 1, pos.getX() + 1, pos.getY() - 1, pos.getZ() + 1)) {
if (recipe.catalyst.test(level.getBlockState(cursor))) {
catalysts++;
if (rand.nextInt(1500) == 0) {
BlockPos above = cursor.above();
if (!recipe.byproducts.isEmpty()) {
var rand = level.random;
if (level.getBlockState(above).isAir()) {
if (rand.nextBoolean()) {
level.setBlockAndUpdate(above, Blocks.RED_MUSHROOM.defaultBlockState());
} else {
level.setBlockAndUpdate(above, Blocks.BROWN_MUSHROOM.defaultBlockState());
if (rand.nextInt(1500) == 0) {
var above = cursor.above();
if (level.getBlockState(above).isAir()) {
var byproduct = recipe.byproducts.getRandom(rand);
if (byproduct.canSurvive(level, above)) {
level.setBlockAndUpdate(above, byproduct);
}
}
}
}
}
}
// Try to perform a fluid transformation recipe
if (catalysts == 0) {
barrel.currentTransformRecipe = null;
} else {
barrel.progress += catalysts * (1.0f / barrel.currentTransformRecipe.duration);
if (barrel.progress >= 1.0f - Mth.EPSILON) {
// Reset progress
barrel.progress = 0.0f;
level.playSound(null, pos, SoundEvents.BREWING_STAND_BREW, SoundSource.BLOCKS, 1.0f, 0.6f);
barrel.tank.setFluid(FluidStack.EMPTY);
barrel.tank.fill(new FluidStack(EFluids.WITCH_WATER.get(), 1000), IFluidHandler.FluidAction.EXECUTE);
}
barrel.markUpdated();
}
} else if (barrel.hasFullWater()) {
if (barrel.tank.getFluid().getFluid().getFluidType() == ForgeMod.WATER_TYPE.get()) {
if (mycelium == 0 && state.ignitedByLava() && rand.nextInt(500) == 0) {
var rand = level.random;
// Leak water to create moss (only wooden barrels do this)
if (state.ignitedByLava() && rand.nextInt(500) == 0) {
var randomPos = pos.offset(rand.nextIntBetweenInclusive(-MOSS_SPREAD_RANGE, MOSS_SPREAD_RANGE), -1, rand.nextIntBetweenInclusive(-MOSS_SPREAD_RANGE, MOSS_SPREAD_RANGE));
var randomBlock = level.getBlockState(randomPos).getBlock();
@ -494,37 +550,6 @@ public class BarrelBlockEntity extends EBlockEntity {
level.setBlock(randomPos, Blocks.MOSSY_STONE_BRICKS.defaultBlockState(), 3);
}
}
if (barrel.progress != (barrel.progress += mycelium * getProgressStep())) {
barrel.markUpdated();
}
if (barrel.progress >= 1.0f) {
// Reset progress
barrel.progress = 0.0f;
level.playSound(null, pos, SoundEvents.BREWING_STAND_BREW, SoundSource.BLOCKS, 1.0f, 0.6f);
barrel.tank.setFluid(new FluidStack(EFluids.WITCH_WATER.get(), barrel.tank.getFluidAmount()));
}
}
} else if (isHotFluid(barrel.tank.getFluid().getFluid().getFluidType())) {
if (state.ignitedByLava()) {
if ((barrel.progress += getProgressStep()) >= 1.0f) {
if (barrel.tank.getFluidAmount() == 1000) {
var fluid = barrel.tank.getFluid().getFluid();
level.setBlockAndUpdate(pos, fluid.getFluidType().getBlockForFluidState(level, pos, fluid.defaultFluidState()));
} else {
level.setBlockAndUpdate(pos, Blocks.FIRE.defaultBlockState());
}
}
barrel.markUpdated();
}
} else if (level.isRainingAt(pos.above()) && barrel.item.getStackInSlot(0).isEmpty() && barrel.compost == 0) {
if (barrel.tank.isEmpty()) {
barrel.tank.setFluid(new FluidStack(Fluids.WATER, 1));
barrel.markUpdated();
} else if (barrel.tank.getFluid().getFluid() == Fluids.WATER) {
barrel.tank.getFluid().grow(1);
barrel.markUpdated();
}
}
} else {
@ -533,6 +558,16 @@ public class BarrelBlockEntity extends EBlockEntity {
}
}
public static void fillRainWater(EBlockEntity block, FluidHelper tank) {
if (tank.isEmpty()) {
tank.setFluid(new FluidStack(Fluids.WATER, 1));
block.markUpdated();
} else if (tank.getFluid().getFluid() == Fluids.WATER && tank.getFluidAmount() < tank.getCapacity()) {
tank.getFluid().grow(1);
block.markUpdated();
}
}
private static float getProgressStep() {
return EConfig.SERVER.barrelProgressStep.get().floatValue();
}
@ -556,6 +591,7 @@ public class BarrelBlockEntity extends EBlockEntity {
@Override
public void onLoad() {
tryInWorldFluidMixing();
updateFluidTransform();
}
// Inner class
@ -571,7 +607,7 @@ public class BarrelBlockEntity extends EBlockEntity {
}
@Override
public @NotNull ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate) {
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
if (stack.isEmpty())
return ItemStack.EMPTY;
validateSlotIndex(slot);
@ -595,7 +631,7 @@ public class BarrelBlockEntity extends EBlockEntity {
}
@Override
public @NotNull ItemStack extractItem(int slot, int amount, boolean simulate) {
public ItemStack extractItem(int slot, int amount, boolean simulate) {
return super.extractItem(slot, amount, simulate);
}
@ -624,45 +660,7 @@ public class BarrelBlockEntity extends EBlockEntity {
BarrelBlockEntity.this.tryInWorldFluidMixing();
BarrelBlockEntity.this.markUpdated();
}
}
@Override
public int fill(FluidStack resource, FluidAction action) {
if (resource.isEmpty() || !isFluidValid(resource)) {
return 0;
}
if (action.simulate()) {
if (this.fluid.isEmpty()) {
return Math.min(this.capacity, resource.getAmount());
}
if (!this.fluid.isFluidEqual(resource)) {
return 0;
}
return Math.min(this.capacity - this.fluid.getAmount(), resource.getAmount());
}
if (this.fluid.isEmpty()) {
// fix forge's implementation to avoid dupes
int amount = Math.min(this.capacity, resource.getAmount());
this.fluid = new FluidStack(resource, Math.min(this.capacity, amount));
onContentsChanged();
return amount;
}
if (!this.fluid.isFluidEqual(resource))
{
return 0;
}
int filled = this.capacity - this.fluid.getAmount();
if (resource.getAmount() < filled) {
this.fluid.grow(resource.getAmount());
filled = resource.getAmount();
} else {
this.fluid.setAmount(this.capacity);
}
if (filled > 0) {
onContentsChanged();
}
return filled;
BarrelBlockEntity.this.updateFluidTransform();
}
}
}

View File

@ -19,14 +19,57 @@
package thedarkcolour.exdeorum.blockentity.helper;
import net.minecraft.nbt.CompoundTag;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.templates.FluidTank;
// Only changed behavior from FluidTank is that fluid stacks read from NBT are clamped and removed validator predicate.
// Changed behavior from FluidTank:
// - fluid stacks read from NBT are clamped.
// - removed validator predicate
// - fixed incorrect fill implementation that caused dupes with the barrel
public class FluidHelper extends FluidTank {
public FluidHelper(int capacity) {
super(capacity);
}
@Override
public int fill(FluidStack resource, FluidAction action) {
if (resource.isEmpty() || !isFluidValid(resource)) {
return 0;
}
if (action.simulate()) {
if (this.fluid.isEmpty()) {
return Math.min(this.capacity, resource.getAmount());
}
if (!this.fluid.isFluidEqual(resource)) {
return 0;
}
return Math.min(this.capacity - this.fluid.getAmount(), resource.getAmount());
}
if (this.fluid.isEmpty()) {
// fix forge's implementation to avoid dupes
int amount = Math.min(this.capacity, resource.getAmount());
this.fluid = new FluidStack(resource, Math.min(this.capacity, amount));
onContentsChanged();
return amount;
}
if (!this.fluid.isFluidEqual(resource))
{
return 0;
}
int filled = this.capacity - this.fluid.getAmount();
if (resource.getAmount() < filled) {
this.fluid.grow(resource.getAmount());
filled = resource.getAmount();
} else {
this.fluid.setAmount(this.capacity);
}
if (filled > 0) {
onContentsChanged();
}
return filled;
}
@Override
public FluidTank readFromNBT(CompoundTag nbt) {
super.readFromNBT(nbt);

View File

@ -33,6 +33,7 @@ import net.minecraft.util.Mth;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.level.material.Fluid;
import net.minecraftforge.client.model.data.ModelData;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import thedarkcolour.exdeorum.ExDeorum;
@ -82,19 +83,19 @@ public class BarrelRenderer implements BlockEntityRenderer<BarrelBlockEntity> {
var pos = barrel.getBlockPos();
var percentage = fluidStack.getAmount() / 1000.0f;
var y = Mth.lerp(percentage, 1.0f, 14.0f) / 16f;
var col = RenderUtil.getFluidColor(fluid, level, pos);
var inputFluidColor = RenderUtil.getFluidColor(fluid, level, pos);
// Split into RGB components
var r = (col >> 16) & 0xff;
var g = (col >> 8) & 0xff;
var b = col & 0xff;
var r = (inputFluidColor >> 16) & 0xff;
var g = (inputFluidColor >> 8) & 0xff;
var b = inputFluidColor & 0xff;
if (barrel.isBrewing()) {
float progress = barrel.progress;
// Transition between water color and witch water color (200B41)
r = (int) Mth.lerp(progress, r, 32);
g = (int) Mth.lerp(progress, g, 11);
b = (int) Mth.lerp(progress, b, 65);
r = (int) Mth.lerp(progress, r, barrel.r);
g = (int) Mth.lerp(progress, g, barrel.g);
b = (int) Mth.lerp(progress, b, barrel.b);
}
if (barrel.transparent) {

View File

@ -42,6 +42,7 @@ public class PreferredOres {
private static final Map<TagKey<Item>, Item> PREFERRED_ORE_ITEMS = new Object2ObjectOpenHashMap<>(11, Hash.DEFAULT_LOAD_FACTOR);
static {
// todo these should update whenever data is reloaded
putPreferredOre(EItemTags.ORES_ALUMINUM, EConfig.COMMON.preferredAluminumOre, getDefaultAluminumOre());
putPreferredOre(EItemTags.ORES_COBALT, EConfig.COMMON.preferredCobaltOre, getDefaultCobaltOre());
putPreferredOre(EItemTags.ORES_SILVER, EConfig.COMMON.preferredSilverOre, getDefaultSilverOre());

View File

@ -18,7 +18,6 @@
package thedarkcolour.exdeorum.compat.kubejs;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import dev.latvian.mods.kubejs.bindings.event.ServerEvents;
import dev.latvian.mods.kubejs.recipe.RecipesEventJS;
import dev.latvian.mods.kubejs.recipe.ReplacementMatch;
@ -26,8 +25,6 @@ import dev.latvian.mods.kubejs.recipe.filter.RecipeFilter;
import dev.latvian.mods.kubejs.script.ScriptType;
import dev.latvian.mods.rhino.util.HideFromJS;
import net.minecraft.advancements.critereon.StatePropertiesPredicate;
import net.minecraft.commands.arguments.blocks.BlockStateParser;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
@ -35,6 +32,7 @@ import net.minecraft.world.level.block.state.properties.Property;
import net.minecraftforge.registries.RegistryObject;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.crucible.FinishedCrucibleHeatRecipe;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
@ -59,17 +57,12 @@ class ExDeorumKubeJsBindings {
@SuppressWarnings({"rawtypes", "unchecked"})
public void setCrucibleHeatValueForState(String stateString, int value) {
onRecipesEvent(event -> {
try {
var state = BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK.asLookup(), stateString, false).blockState();
var properties = StatePropertiesPredicate.Builder.properties();
for (Property prop : state.getProperties()) {
bypassTypeChecking(properties, prop, state);
}
event.custom(new FinishedCrucibleHeatRecipe(null, BlockPredicate.blockState(state.getBlock(), properties.build()), value).serializeRecipe());
} catch (CommandSyntaxException exception) {
// Throw a more appropriate exception.
throw new IllegalArgumentException("Failed to parse BlockState string \"" + stateString + "\"");
var state = RecipeUtil.parseBlockState(stateString);
var properties = StatePropertiesPredicate.Builder.properties();
for (Property prop : state.getProperties()) {
bypassTypeChecking(properties, prop, state);
}
event.custom(new FinishedCrucibleHeatRecipe(null, BlockPredicate.blockState(state.getBlock(), properties.build()), value).serializeRecipe());
});
}

View File

@ -34,6 +34,7 @@ import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.CampfireBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
@ -53,9 +54,8 @@ import thedarkcolour.exdeorum.compat.ModIds;
import thedarkcolour.exdeorum.data.ModCompatData;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import thedarkcolour.exdeorum.recipe.TagResultRecipe;
import thedarkcolour.exdeorum.recipe.barrel.FinishedBarrelCompostRecipe;
import thedarkcolour.exdeorum.recipe.barrel.FinishedBarrelFluidMixingRecipe;
import thedarkcolour.exdeorum.recipe.barrel.FinishedBarrelMixingRecipe;
import thedarkcolour.exdeorum.recipe.WeightedList;
import thedarkcolour.exdeorum.recipe.barrel.*;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.crook.FinishedCrookRecipe;
import thedarkcolour.exdeorum.recipe.crucible.FinishedCrucibleHeatRecipe;
@ -89,6 +89,7 @@ public class Recipes {
crucibleHeatSources(writer);
barrelCompostRecipes(writer);
barrelMixingRecipes(writer);
fluidTransformationRecipes(writer);
}
private static void craftingRecipes(Consumer<FinishedRecipe> writer, MKRecipeProvider recipes) {
@ -648,6 +649,14 @@ public class Recipes {
writer.accept(new FinishedBarrelFluidMixingRecipe(new ResourceLocation(ExDeorum.ID, "barrel_fluid_mixing/" + path(result)), base, 1000, additive, result, consumesAdditive));
}
private static void fluidTransformationRecipes(Consumer<FinishedRecipe> writer) {
writer.accept(new FinishedFluidTransformationRecipe(modLoc("barrel_fluid_transformation/witch_water"), Fluids.WATER, EFluids.WITCH_WATER.get(), 0x2B1057, BlockPredicate.singleBlock(Blocks.MYCELIUM), WeightedList.<BlockState>builder().add(50, Blocks.RED_MUSHROOM.defaultBlockState()).add(50, Blocks.BROWN_MUSHROOM.defaultBlockState()).build(), 1700));
}
static ResourceLocation modLoc(String path) {
return new ResourceLocation(ExDeorum.ID, path);
}
static ICondition tagNotEmpty(TagKey<Item> tag) {
return new NotCondition(new TagEmptyCondition(tag.location()));
}

View File

@ -58,6 +58,7 @@ public class WitchWaterFluid extends FluidType {
@Override
public void initializeClient(Consumer<IClientFluidTypeExtensions> consumer) {
consumer.accept(new IClientFluidTypeExtensions() {
private static final Vector3f FOG_COLOR = new Vector3f(32f / 255f, 12f / 255f, 64f / 255f);
@Override
public ResourceLocation getStillTexture() {
return STILL_TEXTURE;
@ -75,13 +76,12 @@ public class WitchWaterFluid extends FluidType {
@Override
public @NotNull Vector3f modifyFogColor(Camera camera, float partialTick, ClientLevel level, int renderDistance, float darkenWorldAmount, Vector3f fluidFogColor) {
return new Vector3f(32f / 255f, 12f / 255f, 64f / 255f);
return FOG_COLOR;
}
// todo return the correct value here
@Override
public int getTintColor() {
return 0xFFFFFFFF;
return 0xffffffff;
}
});
}

View File

@ -1,36 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe;
import com.google.gson.JsonElement;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
@SuppressWarnings("OptionalGetWithoutIsPresent")
public class CodecUtil {
public static <T> JsonElement encode(Codec<T> codec, T object) {
return codec.encodeStart(JsonOps.INSTANCE, object).result().get();
}
public static <T> T decode(Codec<T> codec, JsonElement json) {
return codec.parse(JsonOps.INSTANCE, json).result().get();
}
}

View File

@ -23,16 +23,27 @@ import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
public interface EFinishedRecipe extends FinishedRecipe {
public abstract class EFinishedRecipe implements FinishedRecipe {
private final ResourceLocation id;
public EFinishedRecipe(ResourceLocation id) {
this.id = id;
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Nullable
@Override
default JsonObject serializeAdvancement() {
public JsonObject serializeAdvancement() {
return null;
}
@Nullable
@Override
default ResourceLocation getAdvancementId() {
public ResourceLocation getAdvancementId() {
return null;
}
}

View File

@ -18,11 +18,15 @@
package thedarkcolour.exdeorum.recipe;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import net.minecraft.commands.arguments.blocks.BlockStateParser;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
@ -38,6 +42,7 @@ import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.level.storage.loot.LootContext;
@ -54,6 +59,7 @@ import thedarkcolour.exdeorum.item.HammerItem;
import thedarkcolour.exdeorum.loot.SummationGenerator;
import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe;
import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe;
import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe;
import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe;
import thedarkcolour.exdeorum.recipe.cache.*;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;
@ -82,6 +88,7 @@ public final class RecipeUtil {
private static SingleIngredientRecipeCache<HammerRecipe> hammerRecipeCache;
private static SieveRecipeCache sieveRecipeCache;
private static BarrelFluidMixingRecipeCache barrelFluidMixingRecipeCache;
private static FluidTransformationRecipeCache fluidTransformationRecipeCache;
private static CrookRecipeCache crookRecipeCache;
private static CrucibleHeatRecipeCache crucibleHeatRecipeCache;
@ -92,6 +99,7 @@ public final class RecipeUtil {
hammerRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.HAMMER).trackAllRecipes();
sieveRecipeCache = new SieveRecipeCache(recipes);
barrelFluidMixingRecipeCache = new BarrelFluidMixingRecipeCache(recipes);
fluidTransformationRecipeCache = new FluidTransformationRecipeCache(recipes);
crookRecipeCache = new CrookRecipeCache(recipes);
crucibleHeatRecipeCache = new CrucibleHeatRecipeCache(recipes);
HammerItem.refreshValidBlocks();
@ -104,6 +112,7 @@ public final class RecipeUtil {
hammerRecipeCache = null;
sieveRecipeCache = null;
barrelFluidMixingRecipeCache = null;
fluidTransformationRecipeCache = null;
crookRecipeCache = null;
crucibleHeatRecipeCache = null;
}
@ -321,6 +330,15 @@ public final class RecipeUtil {
}
}
@Nullable
public static FluidTransformationRecipe getFluidTransformationRecipe(Fluid baseFluid, BlockState catalystState) {
if (baseFluid != Fluids.EMPTY) {
return fluidTransformationRecipeCache.getRecipe(baseFluid, catalystState);
} else {
return null;
}
}
public static double getExpectedValue(NumberProvider provider) {
if (provider instanceof ConstantValue constant) {
return constant.value;
@ -349,11 +367,11 @@ public final class RecipeUtil {
}
@Nullable
public static BlockPredicate readBlockPredicate(ResourceLocation recipeId, JsonObject json) {
BlockPredicate blockPredicate = BlockPredicate.fromJson(json.getAsJsonObject("block_predicate"));
public static BlockPredicate readBlockPredicate(ResourceLocation recipeId, JsonObject json, String key) {
BlockPredicate blockPredicate = BlockPredicate.fromJson(json.getAsJsonObject(key));
if (blockPredicate == null) {
ExDeorum.LOGGER.error("Invalid block_predicate for recipe {}, refer to Ex Deorum documentation for syntax: {}", recipeId, json.getAsJsonObject("block_predicate"));
ExDeorum.LOGGER.error("Invalid {} for recipe {}, refer to Ex Deorum documentation for syntax: {}", key, recipeId, json.getAsJsonObject(key));
}
return blockPredicate;
}
@ -388,4 +406,78 @@ public final class RecipeUtil {
public static ObjectSet<Object2IntMap.Entry<BlockState>> getHeatSources() {
return crucibleHeatRecipeCache.getEntries();
}
public static FluidStack readFluidStack(JsonObject json, String key) {
if (json.has(key)) {
var fluidJson = json.getAsJsonObject(key);
// Since we aren't using codec anymore, we can use consistent naming with other JSON objects
if (fluidJson.has("FluidName")) {
var stack = new FluidStack(RecipeUtil.readFluid(fluidJson, "FluidName"), GsonHelper.getAsInt(fluidJson, "Amount"));
if (fluidJson.has("Tag")) {
stack.setTag(CraftingHelper.getNBT(fluidJson.get("Tag")));
}
return stack;
} else {
var stack = new FluidStack(RecipeUtil.readFluid(fluidJson, "fluid"), GsonHelper.getAsInt(fluidJson, "amount"));
if (fluidJson.has("nbt")) {
stack.setTag(CraftingHelper.getNBT(fluidJson.get("nbt")));
}
return stack;
}
} else {
throw new JsonSyntaxException("Missing fluid");
}
}
public static JsonElement writeFluidStackJson(FluidStack fluidStack) {
JsonObject object = new JsonObject();
object.addProperty("fluid", getFluidId(fluidStack.getFluid()));
object.addProperty("amount", fluidStack.getAmount());
if (fluidStack.hasTag()) {
object.addProperty("nbt", fluidStack.getTag().getAsString());
}
return object;
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static JsonPrimitive writeBlockState(BlockState state) {
var registryKey = BuiltInRegistries.BLOCK.getKey(state.getBlock());
Collection<Property> properties = (Collection<Property>) ((Collection)state.getProperties());
if (properties.isEmpty()) {
return new JsonPrimitive(registryKey.toString());
} else {
StringBuilder builder = new StringBuilder();
builder.append(registryKey);
builder.append('[');
for (Iterator<Property> iterator = properties.iterator(); iterator.hasNext(); ) {
var property = iterator.next();
builder.append(property.getName());
builder.append('=');
builder.append(property.getName(state.getValue(property)));
if (iterator.hasNext()) {
builder.append(',');
}
}
builder.append(']');
return new JsonPrimitive(builder.toString());
}
}
public static BlockState parseBlockState(String stateString) {
try {
return BlockStateParser.parseForBlock(BuiltInRegistries.BLOCK.asLookup(), stateString, false).blockState();
} catch (CommandSyntaxException e) {
throw new IllegalArgumentException("Failed to parse BlockState string \"" + stateString + "\"");
}
}
public static String getFluidId(Fluid baseFluid) {
return BuiltInRegistries.FLUID.getKey(baseFluid).toString();
}
public static String writeItemJson(Item result) {
return BuiltInRegistries.ITEM.getKey(result).toString();
}
}

View File

@ -0,0 +1,161 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe;
import com.google.common.base.Preconditions;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.util.GsonHelper;
import net.minecraft.util.RandomSource;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Function;
// much simpler version of SimpleWeightedRandomList that supports .equals
public class WeightedList<T> {
private final int totalWeight;
private final Object[] values;
private final int[] weights;
private WeightedList(int totalWeight, Object[] values, int[] weights) {
Preconditions.checkArgument(values.length == weights.length, "Values and weights arrays are different sizes");
this.totalWeight = totalWeight;
this.values = values;
this.weights = weights;
}
public boolean isEmpty() {
return this.values.length == 0;
}
// list must not be empty
@SuppressWarnings("unchecked")
public T getRandom(RandomSource rand) {
int chosenIndex = rand.nextInt(this.totalWeight);
for (int i = 0; i < this.values.length; i++) {
chosenIndex -= this.weights[i];
if (chosenIndex < 0) {
return (T) this.values[i];
}
}
throw new IllegalStateException("Could not get random element");
}
@SuppressWarnings("unchecked")
public void toNetwork(FriendlyByteBuf buffer, BiConsumer<FriendlyByteBuf, T> valueWriter) {
buffer.writeVarInt(this.values.length);
for (int i = 0; i < this.values.length; i++) {
valueWriter.accept(buffer, (T) this.values[i]);
buffer.writeVarInt(this.weights[i]);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WeightedList<?> that = (WeightedList<?>) o;
return Arrays.equals(this.values, that.values) && Arrays.equals(this.weights, that.weights);
}
@Override
public int hashCode() {
int result = Arrays.hashCode(this.values);
result = 31 * result + Arrays.hashCode(this.weights);
return result;
}
public static <T> Builder<T> builder() {
return new Builder<>();
}
public static <T> WeightedList<T> fromNetwork(FriendlyByteBuf buffer, Function<FriendlyByteBuf, T> valueReader) {
int size = buffer.readVarInt();
Object[] values = new Object[size];
int[] weights = new int[size];
int totalWeight = 0;
for (int i = 0; i < size; i++) {
values[i] = Objects.requireNonNull(valueReader.apply(buffer), "Failed to read weighted list value from network");
totalWeight += weights[i] = buffer.readVarInt();
}
return new WeightedList<>(totalWeight, values, weights);
}
public JsonArray toJson(Function<T, JsonElement> serializer) {
JsonArray array = new JsonArray();
for (int i = 0; i < this.values.length; i++) {
@SuppressWarnings("unchecked")
var value = serializer.apply((T) this.values[i]);
var weight = this.weights[i];
var json = new JsonObject();
json.add("value", value);
json.addProperty("weight", weight);
array.add(json);
}
return array;
}
@Nullable
public static <T> WeightedList<T> fromJson(JsonArray array, Function<JsonElement, @Nullable T> deserializer) {
WeightedList.Builder<T> list = WeightedList.builder();
for (var element : array) {
if (element instanceof JsonObject obj) {
int weight = GsonHelper.getAsInt(obj, "weight");
var value = deserializer.apply(obj.get("value"));
if (value == null) {
return null;
} else {
list.add(weight, value);
}
} else {
throw new JsonSyntaxException("Invalid weighted list entry");
}
}
return list.build();
}
public static class Builder<T> {
private final ArrayList<T> values = new ArrayList<>();
private final IntArrayList weights = new IntArrayList();
private int totalWeight;
public Builder<T> add(int weight, T element) {
this.totalWeight += weight;
this.values.add(element);
this.weights.add(weight);
return this;
}
public WeightedList<T> build() {
return new WeightedList<>(this.totalWeight, this.values.toArray(), this.weights.toArray(new int[0]));
}
}
}

View File

@ -76,7 +76,7 @@ public class BarrelFluidMixingRecipe implements Recipe<Container> {
@Override
public ItemStack getResultItem(RegistryAccess pRegistryAccess) {
return ItemStack.EMPTY;
return new ItemStack(this.result);
}
@Override

View File

@ -25,13 +25,12 @@ import net.minecraft.world.item.crafting.RecipeSerializer;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedBarrelCompostRecipe implements EFinishedRecipe {
private final ResourceLocation id;
public class FinishedBarrelCompostRecipe extends EFinishedRecipe {
private final Ingredient ingredient;
private final int volume;
public FinishedBarrelCompostRecipe(ResourceLocation id, Ingredient ingredient, int volume) {
this.id = id;
super(id);
this.ingredient = ingredient;
this.volume = volume;
}
@ -42,11 +41,6 @@ public class FinishedBarrelCompostRecipe implements EFinishedRecipe {
json.addProperty("volume", this.volume);
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.BARREL_COMPOST.get();

View File

@ -19,16 +19,15 @@
package thedarkcolour.exdeorum.recipe.barrel;
import com.google.gson.JsonObject;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.material.Fluid;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedBarrelFluidMixingRecipe implements EFinishedRecipe {
private final ResourceLocation id;
public class FinishedBarrelFluidMixingRecipe extends EFinishedRecipe {
private final Fluid baseFluid;
private final int baseFluidAmount;
private final Fluid additiveFluid;
@ -36,7 +35,7 @@ public class FinishedBarrelFluidMixingRecipe implements EFinishedRecipe {
private final boolean consumesAdditive;
public FinishedBarrelFluidMixingRecipe(ResourceLocation id, Fluid baseFluid, int baseFluidAmount, Fluid additiveFluid, Item result, boolean consumesAdditive) {
this.id = id;
super(id);
this.baseFluid = baseFluid;
this.baseFluidAmount = baseFluidAmount;
this.additiveFluid = additiveFluid;
@ -46,16 +45,11 @@ public class FinishedBarrelFluidMixingRecipe implements EFinishedRecipe {
@Override
public void serializeRecipeData(JsonObject json) {
json.addProperty("base_fluid", BuiltInRegistries.FLUID.getKey(this.baseFluid).toString());
json.addProperty("base_fluid", RecipeUtil.getFluidId(this.baseFluid));
json.addProperty("base_fluid_amount", this.baseFluidAmount);
json.addProperty("additive_fluid", BuiltInRegistries.FLUID.getKey(this.additiveFluid).toString());
json.addProperty("additive_fluid", RecipeUtil.getFluidId(this.additiveFluid));
json.addProperty("consumes_additive", this.consumesAdditive);
json.addProperty("result", BuiltInRegistries.ITEM.getKey(this.result).toString());
}
@Override
public ResourceLocation getId() {
return this.id;
json.addProperty("result", RecipeUtil.writeItemJson(this.result));
}
@Override

View File

@ -28,15 +28,14 @@ import net.minecraft.world.level.material.Fluid;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedBarrelMixingRecipe implements EFinishedRecipe {
private final ResourceLocation id;
public class FinishedBarrelMixingRecipe extends EFinishedRecipe {
private final Ingredient ingredient;
private final Fluid fluid;
private final int fluidAmount;
private final Item result;
public FinishedBarrelMixingRecipe(ResourceLocation id, Ingredient ingredient, Fluid fluid, int fluidAmount, Item result) {
this.id = id;
super(id);
this.ingredient = ingredient;
this.fluid = fluid;
this.fluidAmount = fluidAmount;
@ -51,11 +50,6 @@ public class FinishedBarrelMixingRecipe implements EFinishedRecipe {
json.addProperty("result", BuiltInRegistries.ITEM.getKey(this.result).toString());
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.BARREL_MIXING.get();

View File

@ -0,0 +1,64 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe.barrel;
import com.google.gson.JsonObject;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.WeightedList;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedFluidTransformationRecipe extends EFinishedRecipe {
private final Fluid baseFluid;
private final Fluid resultFluid;
private final int resultColor;
private final BlockPredicate catalyst;
private final WeightedList<BlockState> byproducts;
private final int duration;
public FinishedFluidTransformationRecipe(ResourceLocation id, Fluid baseFluid, Fluid resultFluid, int resultColor, BlockPredicate catalyst, WeightedList<BlockState> byproducts, int duration) {
super(id);
this.baseFluid = baseFluid;
this.resultFluid = resultFluid;
this.resultColor = resultColor;
this.catalyst = catalyst;
this.byproducts = byproducts;
this.duration = duration;
}
@Override
public void serializeRecipeData(JsonObject json) {
json.addProperty("base_fluid", RecipeUtil.getFluidId(this.baseFluid));
json.addProperty("result_fluid", RecipeUtil.getFluidId(this.resultFluid));
json.addProperty("result_color", this.resultColor);
json.addProperty("duration", this.duration);
json.add("catalyst", this.catalyst.toJson());
json.add("byproducts", this.byproducts.toJson(RecipeUtil::writeBlockState));
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.BARREL_FLUID_TRANSFORMATION.get();
}
}

View File

@ -0,0 +1,165 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe.barrel;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.Container;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.WeightedList;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
import java.util.Objects;
// todo consider NBT tag of input fluid?
public class FluidTransformationRecipe implements Recipe<Container> {
private final ResourceLocation id;
public final Fluid baseFluid;
public final Fluid resultFluid;
public final int resultColor;
public final BlockPredicate catalyst;
public final WeightedList<BlockState> byproducts;
public final int duration;
public FluidTransformationRecipe(ResourceLocation id, Fluid baseFluid, Fluid resultFluid, int resultColor, BlockPredicate catalyst, WeightedList<BlockState> byproducts, int duration) {
this.id = id;
this.baseFluid = baseFluid;
this.resultFluid = resultFluid;
this.resultColor = resultColor;
this.catalyst = catalyst;
this.byproducts = byproducts;
this.duration = duration;
}
@Override
public boolean matches(Container pContainer, Level pLevel) {
return false;
}
@Override
public ItemStack assemble(Container pContainer, RegistryAccess pRegistryAccess) {
return ItemStack.EMPTY;
}
@Override
public boolean canCraftInDimensions(int pWidth, int pHeight) {
return false;
}
@Override
public ItemStack getResultItem(RegistryAccess pRegistryAccess) {
return ItemStack.EMPTY;
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
public RecipeSerializer<?> getSerializer() {
return ERecipeSerializers.BARREL_FLUID_TRANSFORMATION.get();
}
@Override
public RecipeType<?> getType() {
return ERecipeTypes.BARREL_FLUID_TRANSFORMATION.get();
}
public static class Serializer implements RecipeSerializer<FluidTransformationRecipe> {
@Override
public FluidTransformationRecipe fromJson(ResourceLocation id, JsonObject json) {
Fluid baseFluid = RecipeUtil.readFluid(json, "base_fluid");
Fluid resultFluid = RecipeUtil.readFluid(json, "result_fluid");
int resultColor = GsonHelper.getAsInt(json, "result_color");
int duration = GsonHelper.getAsInt(json, "duration");
BlockPredicate catalyst = RecipeUtil.readBlockPredicate(id, json, "catalyst");
var byproducts = WeightedList.fromJson(json.getAsJsonArray("byproducts"), element -> {
if (element.isJsonPrimitive()) {
return RecipeUtil.parseBlockState(element.getAsString());
} else {
return null;
}
});
if (catalyst == null) {
throw new JsonSyntaxException("Failed to read barrel fluid transformation recipe catalyst");
}
if (byproducts == null) {
throw new JsonSyntaxException("Failed to read barrel fluid transformation recipe byproducts");
}
return new FluidTransformationRecipe(id, baseFluid, resultFluid, resultColor, catalyst, byproducts, duration);
}
@Override
public void toNetwork(FriendlyByteBuf buffer, FluidTransformationRecipe recipe) {
buffer.writeRegistryId(ForgeRegistries.FLUIDS, recipe.baseFluid);
buffer.writeRegistryId(ForgeRegistries.FLUIDS, recipe.resultFluid);
buffer.writeInt(recipe.resultColor);
recipe.catalyst.toNetwork(buffer);
recipe.byproducts.toNetwork(buffer, (buf, state) -> buf.writeId(Block.BLOCK_STATE_REGISTRY, state));
buffer.writeVarInt(recipe.duration);
}
@Override
public @Nullable FluidTransformationRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) {
Fluid baseFluid = buffer.readRegistryId();
Fluid resultFluid = buffer.readRegistryId();
int resultColor = buffer.readInt();
BlockPredicate catalyst = RecipeUtil.readBlockPredicateNetwork(id, buffer);
if (catalyst == null) {
return null;
}
WeightedList<BlockState> byproducts = WeightedList.fromNetwork(buffer, buf -> buf.readById(Block.BLOCK_STATE_REGISTRY));
int duration = buffer.readVarInt();
return new FluidTransformationRecipe(id, baseFluid, resultFluid, resultColor, catalyst, byproducts, duration);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FluidTransformationRecipe that = (FluidTransformationRecipe) o;
return this.resultColor == that.resultColor && this.duration == that.duration && Objects.equals(this.id, that.id) && Objects.equals(this.baseFluid, that.baseFluid) && Objects.equals(this.resultFluid, that.resultFluid) && Objects.equals(this.catalyst, that.catalyst) && Objects.equals(this.byproducts, that.byproducts);
}
@Override
public int hashCode() {
return Objects.hash(this.id, this.baseFluid, this.resultFluid, this.resultColor, this.catalyst, this.byproducts, this.duration);
}
}

View File

@ -0,0 +1,69 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe.cache;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
import java.util.HashMap;
import java.util.Map;
public class FluidTransformationRecipeCache {
private RecipeManager recipeManager;
@Nullable
private Map<BlockState, Map<Fluid, FluidTransformationRecipe>> recipes;
public FluidTransformationRecipeCache(RecipeManager manager) {
this.recipeManager = manager;
}
@Nullable
public FluidTransformationRecipe getRecipe(Fluid baseFluid, BlockState catalystState) {
if (this.recipes == null) {
buildRecipes();
}
var recipesForBase = this.recipes.get(catalystState);
if (recipesForBase != null) {
return recipesForBase.get(baseFluid);
}
return null;
}
private void buildRecipes() {
this.recipes = new HashMap<>();
for (var recipe : this.recipeManager.byType(ERecipeTypes.BARREL_FLUID_TRANSFORMATION.get()).values()) {
recipe.catalyst.possibleStates().forEach(state -> {
this.recipes.computeIfAbsent(state, key -> new HashMap<>()).put(recipe.baseFluid, recipe);
});
}
var dedupe = new HashMap<Map<Fluid, FluidTransformationRecipe>, Map<Fluid, FluidTransformationRecipe>>();
for (var entry : this.recipes.entrySet()) {
entry.setValue(dedupe.computeIfAbsent(entry.getValue(), Map::copyOf));
}
this.recipes = Map.copyOf(this.recipes);
this.recipeManager = null;
}
}

View File

@ -76,7 +76,7 @@ public record CrookRecipe(ResourceLocation id, BlockPredicate blockPredicate, It
public static class Serializer implements RecipeSerializer<CrookRecipe> {
@Override
public CrookRecipe fromJson(ResourceLocation id, JsonObject json) {
BlockPredicate blockPredicate = RecipeUtil.readBlockPredicate(id, json);
BlockPredicate blockPredicate = RecipeUtil.readBlockPredicate(id, json, "block_predicate");
if (blockPredicate == null) return null;
Item result = RecipeUtil.readItem(json, "result");

View File

@ -27,14 +27,13 @@ import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedCrookRecipe implements EFinishedRecipe {
private final ResourceLocation id;
public class FinishedCrookRecipe extends EFinishedRecipe {
private final BlockPredicate predicate;
private final Item result;
private final float chance;
public FinishedCrookRecipe(ResourceLocation id, BlockPredicate predicate, Item result, float chance) {
this.id = id;
super(id);
this.predicate = predicate;
this.result = result;
this.chance = chance;
@ -47,11 +46,6 @@ public class FinishedCrookRecipe implements EFinishedRecipe {
json.addProperty("chance", this.chance);
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.CROOK.get();

View File

@ -72,7 +72,7 @@ public record CrucibleHeatRecipe(ResourceLocation id, BlockPredicate blockPredic
public static class Serializer implements RecipeSerializer<CrucibleHeatRecipe> {
@Override
public CrucibleHeatRecipe fromJson(ResourceLocation id, JsonObject json) {
BlockPredicate blockPredicate = RecipeUtil.readBlockPredicate(id, json);
BlockPredicate blockPredicate = RecipeUtil.readBlockPredicate(id, json, "block_predicate");
if (blockPredicate == null) return null;
int heatValue = json.get("heat_value").getAsInt();
return new CrucibleHeatRecipe(id, blockPredicate, heatValue);

View File

@ -26,7 +26,6 @@ import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraftforge.fluids.FluidStack;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.CodecUtil;
import thedarkcolour.exdeorum.recipe.SingleIngredientRecipe;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
@ -42,7 +41,7 @@ public class CrucibleRecipe extends SingleIngredientRecipe {
this.result = result;
if (this.dependsOnNbt) {
throw new IllegalArgumentException("Cannot use NBT to determine Ex Nihilo Reborn Crucible output");
throw new IllegalArgumentException("Cannot use NBT to determine Ex Deorum Crucible output");
}
}
@ -70,7 +69,7 @@ public class CrucibleRecipe extends SingleIngredientRecipe {
@Override
public CrucibleRecipe fromJson(ResourceLocation id, JsonObject json) {
Ingredient ingredient = RecipeUtil.readIngredient(json, "ingredient");
FluidStack stack = CodecUtil.decode(FluidStack.CODEC, json.get("fluid"));
FluidStack stack = RecipeUtil.readFluidStack(json, "fluid");
return new CrucibleRecipe(id, this.type, ingredient, stack);
}

View File

@ -25,13 +25,12 @@ import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedCrucibleHeatRecipe implements EFinishedRecipe {
private final ResourceLocation id;
public class FinishedCrucibleHeatRecipe extends EFinishedRecipe {
private final BlockPredicate blockPredicate;
private final int heatValue;
public FinishedCrucibleHeatRecipe(ResourceLocation id, BlockPredicate blockPredicate, int heatValue) {
this.id = id;
super(id);
this.blockPredicate = blockPredicate;
this.heatValue = heatValue;
}
@ -42,11 +41,6 @@ public class FinishedCrucibleHeatRecipe implements EFinishedRecipe {
json.addProperty("heat_value", this. heatValue);
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.CRUCIBLE_HEAT_SOURCE.get();

View File

@ -24,11 +24,10 @@ import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.material.Fluid;
import net.minecraftforge.fluids.FluidStack;
import thedarkcolour.exdeorum.recipe.CodecUtil;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
public class FinishedCrucibleRecipe implements EFinishedRecipe {
private final ResourceLocation id;
public class FinishedCrucibleRecipe extends EFinishedRecipe {
private final RecipeSerializer<?> serializer;
private final Ingredient ingredient;
private final FluidStack fluidStack;
@ -38,7 +37,7 @@ public class FinishedCrucibleRecipe implements EFinishedRecipe {
}
public FinishedCrucibleRecipe(ResourceLocation id, RecipeSerializer<?> serializer, Ingredient ingredient, FluidStack fluidStack) {
this.id = id;
super(id);
this.serializer = serializer;
this.ingredient = ingredient;
this.fluidStack = fluidStack;
@ -47,12 +46,8 @@ public class FinishedCrucibleRecipe implements EFinishedRecipe {
@Override
public void serializeRecipeData(JsonObject json) {
json.add("ingredient", this.ingredient.toJson());
json.add("fluid", CodecUtil.encode(FluidStack.CODEC, this.fluidStack));
}
@Override
public ResourceLocation getId() {
return this.id;
JsonObject fluidObj = new JsonObject();
json.add("fluid", RecipeUtil.writeFluidStackJson(this.fluidStack));
}
@Override

View File

@ -29,14 +29,13 @@ import net.minecraft.world.level.storage.loot.providers.number.NumberProvider;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedHammerRecipe implements EFinishedRecipe {
private final ResourceLocation id;
public class FinishedHammerRecipe extends EFinishedRecipe {
private final Ingredient ingredient;
private final Item result;
private final NumberProvider resultAmount;
public FinishedHammerRecipe(ResourceLocation id, Ingredient ingredient, Item result, NumberProvider resultAmount) {
this.id = id;
super(id);
this.ingredient = ingredient;
this.result = result;
this.resultAmount = resultAmount;
@ -49,11 +48,6 @@ public class FinishedHammerRecipe implements EFinishedRecipe {
object.add("result_amount", LootDataType.PREDICATE.parser().toJsonTree(this.resultAmount));
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.HAMMER.get();

View File

@ -31,15 +31,14 @@ import net.minecraft.world.level.storage.loot.providers.number.NumberProvider;
import thedarkcolour.exdeorum.recipe.EFinishedRecipe;
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
public class FinishedSieveRecipe implements EFinishedRecipe {
private final ResourceLocation id;
public class FinishedSieveRecipe extends EFinishedRecipe {
private final Ingredient ingredient;
private final Item mesh;
private final Either<Item, TagKey<Item>> result;
private final NumberProvider resultAmount;
public FinishedSieveRecipe(ResourceLocation id, Item mesh, Ingredient ingredient, Either<Item, TagKey<Item>> result, NumberProvider resultAmount) {
this.id = id;
super(id);
this.mesh = mesh;
this.ingredient = ingredient;
this.result = result;
@ -58,11 +57,6 @@ public class FinishedSieveRecipe implements EFinishedRecipe {
object.add("result_amount", LootDataType.PREDICATE.parser().toJsonTree(this.resultAmount));
}
@Override
public ResourceLocation getId() {
return this.id;
}
@Override
public RecipeSerializer<?> getType() {
return ERecipeSerializers.SIEVE.get();

View File

@ -26,6 +26,7 @@ import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.recipe.TagResultRecipe;
import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe;
import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe;
import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe;
import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;
import thedarkcolour.exdeorum.recipe.crucible.CrucibleHeatRecipe;
@ -39,6 +40,7 @@ public class ERecipeSerializers {
public static final RegistryObject<RecipeSerializer<BarrelCompostRecipe>> BARREL_COMPOST = RECIPE_SERIALIZERS.register("barrel_compost", BarrelCompostRecipe.Serializer::new);
public static final RegistryObject<RecipeSerializer<BarrelMixingRecipe>> BARREL_MIXING = RECIPE_SERIALIZERS.register("barrel_mixing", BarrelMixingRecipe.Serializer::new);
public static final RegistryObject<RecipeSerializer<BarrelFluidMixingRecipe>> BARREL_FLUID_MIXING = RECIPE_SERIALIZERS.register("barrel_fluid_mixing", BarrelFluidMixingRecipe.Serializer::new);
public static final RegistryObject<RecipeSerializer<FluidTransformationRecipe>> BARREL_FLUID_TRANSFORMATION = RECIPE_SERIALIZERS.register("barrel_fluid_transformation", FluidTransformationRecipe.Serializer::new);
public static final RegistryObject<RecipeSerializer<HammerRecipe>> HAMMER = RECIPE_SERIALIZERS.register("hammer", HammerRecipe.Serializer::new);
public static final RegistryObject<RecipeSerializer<CrookRecipe>> CROOK = RECIPE_SERIALIZERS.register("crook", CrookRecipe.Serializer::new);

View File

@ -25,6 +25,7 @@ import net.minecraftforge.registries.RegistryObject;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe;
import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe;
import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe;
import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;
import thedarkcolour.exdeorum.recipe.crucible.CrucibleHeatRecipe;
@ -38,6 +39,7 @@ public class ERecipeTypes {
public static final RegistryObject<RecipeType<BarrelCompostRecipe>> BARREL_COMPOST = RECIPE_TYPES.register("barrel_compost", () -> RecipeType.simple(ERecipeTypes.BARREL_COMPOST.getId()));
public static final RegistryObject<RecipeType<BarrelMixingRecipe>> BARREL_MIXING = RECIPE_TYPES.register("barrel_mixing", () -> RecipeType.simple(ERecipeTypes.BARREL_MIXING.getId()));
public static final RegistryObject<RecipeType<BarrelFluidMixingRecipe>> BARREL_FLUID_MIXING = RECIPE_TYPES.register("barrel_fluid_mixing", () -> RecipeType.simple(ERecipeTypes.BARREL_FLUID_MIXING.getId()));
public static final RegistryObject<RecipeType<FluidTransformationRecipe>> BARREL_FLUID_TRANSFORMATION = RECIPE_TYPES.register("barrel_fluid_transformation", () -> RecipeType.simple(ERecipeTypes.BARREL_FLUID_TRANSFORMATION.getId()));
public static final RegistryObject<RecipeType<CrucibleRecipe>> LAVA_CRUCIBLE = RECIPE_TYPES.register("lava_crucible", () -> RecipeType.simple(ERecipeTypes.LAVA_CRUCIBLE.getId()));
public static final RegistryObject<RecipeType<CrucibleRecipe>> WATER_CRUCIBLE = RECIPE_TYPES.register("water_crucible", () -> RecipeType.simple(ERecipeTypes.WATER_CRUCIBLE.getId()));

View File

@ -18,6 +18,7 @@
package thedarkcolour.exdeorum.recipe;
import com.google.gson.JsonObject;
import io.netty.buffer.Unpooled;
import net.minecraft.SharedConstants;
import net.minecraft.network.FriendlyByteBuf;
@ -26,10 +27,17 @@ import net.minecraft.tags.BlockTags;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluids;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import thedarkcolour.exdeorum.recipe.barrel.FinishedFluidTransformationRecipe;
import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;
import thedarkcolour.exdeorum.recipe.crucible.CrucibleHeatRecipe;
import thedarkcolour.exdeorum.recipe.crucible.FinishedCrucibleHeatRecipe;
import java.util.function.Function;
import static org.junit.jupiter.api.Assertions.*;
@ -48,7 +56,21 @@ public class RecipeSerializationTests {
@Test
void crucibleHeatSourceJson() {
fail();
testJson(new CrucibleHeatRecipe(null, BlockPredicate.blockTag(BlockTags.DIRT), 3), new CrucibleHeatRecipe.Serializer(), recipe -> {
return new FinishedCrucibleHeatRecipe(recipe.id(), recipe.blockPredicate(), recipe.heatValue());
});
}
@Test
void barrelFluidTransformationNetwork() {
testNetwork(new FluidTransformationRecipe(null, Fluids.WATER, Fluids.LAVA, 1, BlockPredicate.blockTag(BlockTags.DIRT), WeightedList.<BlockState>builder().build(), 1000), new FluidTransformationRecipe.Serializer());
}
@Test
void barrelFluidTransformationJson() {
testJson(new FluidTransformationRecipe(null, Fluids.WATER, Fluids.LAVA, 1, BlockPredicate.blockTag(BlockTags.DIRT), WeightedList.<BlockState>builder().build(), 1000), new FluidTransformationRecipe.Serializer(), recipe -> {
return new FinishedFluidTransformationRecipe(recipe.getId(), recipe.baseFluid, recipe.resultFluid, recipe.resultColor, recipe.catalyst, recipe.byproducts, recipe.duration);
});
}
@Test
@ -64,4 +86,12 @@ public class RecipeSerializationTests {
serializer.toNetwork(buffer, recipe);
assertEquals(recipe, serializer.fromNetwork(id, buffer));
}
private static <T extends Recipe<?>> void testJson(T recipe, RecipeSerializer<T> serializer, Function<T, EFinishedRecipe> toJson) {
var id = recipe.getId();
var finishedRecipe = toJson.apply(recipe);
var json = new JsonObject();
finishedRecipe.serializeRecipeData(json);
assertEquals(recipe, serializer.fromJson(id, json));
}
}

View File

@ -18,11 +18,17 @@
package thedarkcolour.exdeorum.recipe;
import com.google.gson.JsonObject;
import net.minecraft.SharedConstants;
import net.minecraft.core.Direction;
import net.minecraft.server.Bootstrap;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.material.Fluids;
import net.minecraftforge.common.Tags;
import net.minecraftforge.fluids.FluidStack;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -35,6 +41,19 @@ class RecipeUtilTest {
Bootstrap.bootStrap();
}
@Test
void jsonFluidStack() {
var fluidStack = new FluidStack(Fluids.LAVA, 345);
var root = new JsonObject();
root.add("test", RecipeUtil.writeFluidStackJson(fluidStack));
var testStack = RecipeUtil.readFluidStack(root, "test");
assertTrue(
testStack.getAmount() == fluidStack.getAmount() &&
testStack.getFluid() == fluidStack.getFluid() &&
testStack.getTag() == fluidStack.getTag()
);
}
@Test
void areIngredientsEqual() {
assertTrue(RecipeUtil.areIngredientsEqual(Ingredient.of(Items.OAK_SLAB), Ingredient.of(Items.OAK_SLAB)));
@ -45,4 +64,10 @@ class RecipeUtilTest {
assertTrue(RecipeUtil.areIngredientsEqual(Ingredient.of(Items.OAK_SLAB, Items.SPRUCE_SLAB), Ingredient.of(Items.SPRUCE_SLAB, Items.OAK_SLAB)));
assertFalse(RecipeUtil.areIngredientsEqual(Ingredient.of(Items.OAK_SLAB, Items.SPRUCE_SLAB), Ingredient.of(Items.SPRUCE_SLAB, Items.OAK_SLAB, Items.OAK_SLAB)));
}
@Test
void stringBlockState() {
var state = Blocks.ACACIA_LOG.defaultBlockState().setValue(BlockStateProperties.AXIS, Direction.Axis.Z);
assertEquals(state, RecipeUtil.parseBlockState(RecipeUtil.writeBlockState(state).getAsString()));
}
}

View File

@ -0,0 +1,105 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.recipe;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.levelgen.XoroshiroRandomSource;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class WeightedListTest {
@Test
void isEmpty() {
WeightedList.Builder<Object> list = WeightedList.builder();
assertTrue(list.build().isEmpty());
}
@Test
void getRandom() {
RandomSource rand = new XoroshiroRandomSource(123, 123);
// An equal list should give all elements a roughly equal chance of appearing randomly
WeightedList<String> equalList = WeightedList.<String>builder()
.add(20, "Hello")
.add(20, "Hi")
.add(20, "How ya doin")
.build();
int hellos = 0;
int his = 0;
int howYaDoins = 0;
for (int i = 0; i < 1_000_000; i++) {
String choice = equalList.getRandom(rand);
switch (choice) {
case "Hello" -> hellos++;
case "Hi" -> his++;
case "How ya doin" -> howYaDoins++;
default -> fail("Bad test");
}
}
System.out.println("Hello: " + hellos + String.format(" (%.2f)", (float) hellos / 1000000));
System.out.println("Hi: " + his + String.format(" (%.2f)", (float) his / 1000000));
System.out.println("How ya doin: " + howYaDoins + String.format(" (%.2f)", (float) howYaDoins / 1000000));
// Ensure that these two elements have roughly the same frequency
assertTrue(Mth.abs((float) hellos / 1_000_000f - (float) his / 1_000_000f) < 0.025f);
// Test that the weights specified in the list roughly match the random results
WeightedList<String> unbalanced = WeightedList.<String>builder()
.add(60, "Hello")
.add(20, "Hi")
.add(20, "How ya doin")
.build();
hellos = 0;
his = 0;
howYaDoins = 0;
for (int i = 0; i < 1_000_000; i++) {
String choice = unbalanced.getRandom(rand);
switch (choice) {
case "Hello" -> hellos++;
case "Hi" -> his++;
case "How ya doin" -> howYaDoins++;
default -> fail("Bad test");
}
}
// Ensure the dominant element has the 60% frequency, just as its 60/100 weight specifies
assertTrue(Mth.abs((float) hellos / 1_000_000f - 0.6f) < 0.025f);
}
@Test
void testEquals() {
// regular equality
assertNotEquals(
WeightedList.builder().add(20, new Object()).add(30, new Object()).build(),
WeightedList.builder().add(20, new Object()).add(30, new Object()).build()
);
// deep equality
assertEquals(
WeightedList.<String>builder().add(20, "Hi").add(30, "Hello").build(),
WeightedList.<String>builder().add(20, "Hi").add(30, "Hello").build()
);
}
}