Merge remote-tracking branch 'origin/main' into eval/cc

This commit is contained in:
Alwinfy 2023-02-23 15:51:01 -05:00
commit 29074ab4fe
No known key found for this signature in database
GPG key ID: 2CCB99445F0C949E
672 changed files with 10609 additions and 6555 deletions

View file

@ -1,21 +1,25 @@
// 1.19.2 2022-11-09T19:44:43.409223 Item Models: hexcasting
// 1.19.2 2023-02-17T23:19:00.76285061 Item Models: hexcasting
9af2754cb1e53eeaa85618cf92651b4878cf62b1 assets/hexcasting/models/block/quenched_allay_0.json
de4ff723b4332d4e26bd01f74e0485e28c9a2178 assets/hexcasting/models/block/quenched_allay_1.json
4c29163e07f3a903017e38a9cc102f4b37db20b1 assets/hexcasting/models/block/quenched_allay_2.json
487d34cd8e70b3e468337228b74af5c1b4d14c53 assets/hexcasting/models/block/quenched_allay_3.json
f2156b3a7041cf99891b528393db64c6b9ca1a4f assets/hexcasting/models/item/abacus.json
783d8454d6b74f926be0d3e02d87c6505e9d76d0 assets/hexcasting/models/item/acacia_staff.json
f183fcd384db929bf56e397965057218abc32ddb assets/hexcasting/models/item/acacia_staff.json
19730853397b109cfedd0c3bbda83d5de6cd15b9 assets/hexcasting/models/item/akashic_record.json
8c735feff09d46d00ed681311f46f61a50cfdc9b assets/hexcasting/models/item/amethyst_dust.json
d1b0892de9d751e7bebc763e6407d5285363c851 assets/hexcasting/models/item/artifact.json
7eb3eb776e70eb616c12ada500b9d1d6a3249a6a assets/hexcasting/models/item/artifact_filled.json
82e3be7bbdad92d2b4c728be54d9d2f2809a0ac2 assets/hexcasting/models/item/battery.json
3dcc41ab5cbf7004f9c959d89be961aff0ce6032 assets/hexcasting/models/item/birch_staff.json
f05937151873b1de302a011851edc62d0554e4db assets/hexcasting/models/item/bosnia_staff.json
71acb8ff7f0457c46683c16da339363f39c7ea8b assets/hexcasting/models/item/birch_staff.json
ec7c3a51882a432185fdbb6a449e66165b6a4c4c assets/hexcasting/models/item/charged_amethyst.json
d614c0fd8acb1c18b4211b090d438326d74507f8 assets/hexcasting/models/item/cherry_staff.json
c64ed609ece68994ce23dd2809145040bce13579 assets/hexcasting/models/item/conjured.json
c64ed609ece68994ce23dd2809145040bce13579 assets/hexcasting/models/item/conjured_block.json
c8da4227db3c80e3e2e7f2fb2ae2649656429d68 assets/hexcasting/models/item/creative_unlocker.json
21c0b8d424043a1b0d2748f59d292b129193d9a5 assets/hexcasting/models/item/crimson_staff.json
fd00d0c14663804b78911d7aa73606b88e90ef22 assets/hexcasting/models/item/crimson_staff.json
e47acd1d6ef29a3e1941afb1b212bd40b963cb72 assets/hexcasting/models/item/cypher.json
2db55347092ad6bc9e58bc968e88a3b6c5fd77c1 assets/hexcasting/models/item/cypher_filled.json
81eed736b6bae7e427d3c6972ef15a8d967489e5 assets/hexcasting/models/item/dark_oak_staff.json
73ded6154a6e2f6929a05c5625372c9e0498db3d assets/hexcasting/models/item/dark_oak_staff.json
113c51af571a92009f5f687a82e10bc5ce97b010 assets/hexcasting/models/item/dye_colorizer_black.json
b5a04716775ba2e1b137abc513025b2f1065e5d1 assets/hexcasting/models/item/dye_colorizer_blue.json
0bb3afbd937b2e07523a581f6e3f389e11078595 assets/hexcasting/models/item/dye_colorizer_brown.json
@ -37,7 +41,7 @@ c9faada6299f388afc2d2798843d2b45159950d1 assets/hexcasting/models/item/edified_d
7f22e012a844cc2c5e30b0fcbdc2e7e4afac1c40 assets/hexcasting/models/item/edified_log.json
6b2c9d4aca0c869d7e18707c22b00c14e1d30f0c assets/hexcasting/models/item/edified_pressure_plate.json
31b4d60ff15a6d6de7aecb6feeba25a366bba2fd assets/hexcasting/models/item/edified_slab.json
66d951804b32cb77bbe6e81d5053ea14c9690b1b assets/hexcasting/models/item/edified_staff.json
aec5d99a7501bdbe7fd7d4ab3640e726682ef0f1 assets/hexcasting/models/item/edified_staff.json
2584421c2e9e1cdf22a703018b54cf449613d7d9 assets/hexcasting/models/item/edified_stairs.json
ae58c5b7c304d33cbde60caf44a4c4ee4ec1a633 assets/hexcasting/models/item/edified_trapdoor.json
084183e4351973c8165f6f459c0f0dba2463d957 assets/hexcasting/models/item/edified_wood.json
@ -45,10 +49,12 @@ ae58c5b7c304d33cbde60caf44a4c4ee4ec1a633 assets/hexcasting/models/item/edified_t
947d1539d88f9d6fd0afcdf831f4327356d19baf assets/hexcasting/models/item/focus_filled.json
cb2d973af25a2ec07e6094ecc106c896a06918dc assets/hexcasting/models/item/focus_sealed.json
6ec61fea7d8c49cc0c45b64857fd926451b4845f assets/hexcasting/models/item/jeweler_hammer.json
e8ce683966f007b56cc551b3137c77f0a1fe2d9a assets/hexcasting/models/item/jungle_staff.json
0777d2158566f7389f4becd2fb2c77664de90c6a assets/hexcasting/models/item/jungle_staff.json
abfc028c974a02780aed3d7a5859352503bbd920 assets/hexcasting/models/item/lens.json
a34a6d777ae265c7e49c8bb23c15f04359236544 assets/hexcasting/models/item/lore_fragment.json
9c79526e19bfafb8370718ddcc9126204ed85e3a assets/hexcasting/models/item/oak_staff.json
dbd52dd3d429578cc81b8b3142d25f8d84501273 assets/hexcasting/models/item/mangrove_staff.json
b8fe3a6b792c6014831f047d4c40eaae9f939b1b assets/hexcasting/models/item/mindsplice_staff.json
4b65b6848d43cc27adf7e59ebdffd59281fe3937 assets/hexcasting/models/item/oak_staff.json
38d1dc73c49d185b86c098b13611bf3ec07b255c assets/hexcasting/models/item/old_staff.json
82fa0a2bb17e40c0b3f826e97b2e95445ec24ab8 assets/hexcasting/models/item/patchouli_book.json
d69d10e6cb967b98b3294cc86174182c671de671 assets/hexcasting/models/item/phial_large_0.json
@ -82,6 +88,13 @@ d60b723c44183b59cbadfd02a911dab5e89e0e61 assets/hexcasting/models/item/pride_col
6253bab7bd9162f75782c5bc899f46cd941d01ad assets/hexcasting/models/item/pride_colorizer_pansexual.json
c67e74e2a323872c3b34b113df99da8b77a501c6 assets/hexcasting/models/item/pride_colorizer_plural.json
7c4191ec2479b0a67e578da49d459deea8294ec4 assets/hexcasting/models/item/pride_colorizer_transgender.json
5038e069909e2dcf8664bcde81b229c8e27191ae assets/hexcasting/models/item/quenched_allay.json
a8859c93236b88f9ed46a4957f5723965ce04e03 assets/hexcasting/models/item/quenched_allay_shard.json
8105007d186fe2c6bea6958dd85d1b2ed3cecb58 assets/hexcasting/models/item/quenched_shard_0.json
aef7d4b759bcc8a1d5b886b8a0170657e447a8d8 assets/hexcasting/models/item/quenched_shard_1.json
4a08374ef00de51381df9659488cb305e7c8674f assets/hexcasting/models/item/quenched_shard_2.json
181aac0f66e5c3937f49da3f5d577f1c8045c635 assets/hexcasting/models/item/quenched_shard_3.json
628df1d43bb959bd7424253d2cf367947e147155 assets/hexcasting/models/item/quenched_staff.json
1ac1d158da25a8f8ec4b8771445d1ec9d42e9519 assets/hexcasting/models/item/scroll.json
ae2a8b6eb8a4ef17926e20c6982bc01120ff32b7 assets/hexcasting/models/item/scroll_ancient_large.json
7478e4b91169a3ab9def5af8662db9696eb33a34 assets/hexcasting/models/item/scroll_ancient_medium.json
@ -97,11 +110,17 @@ e6452f95b60240e0067769d7f32a0b9fa7718a1b assets/hexcasting/models/item/slate_wri
986674763b45e0f9381f9f34a708082e5230652a assets/hexcasting/models/item/spellbook.json
f962c13ab9e299885387cee35b16006651821e81 assets/hexcasting/models/item/spellbook_filled.json
c29e6e7b2168eeeb13b1fc3e93ffc3e0c9bd11ce assets/hexcasting/models/item/spellbook_sealed.json
7f03c6ea7a07cfedc7d580bb9ba5fcdc54cccb86 assets/hexcasting/models/item/spruce_staff.json
bc2dbafadff333484c397675325df15f95e8b9f1 assets/hexcasting/models/item/spruce_staff.json
65bbc32202a58cdae91165e059e53bcfb2c54e10 assets/hexcasting/models/item/staves/quenched_0.json
9d8d276d077fc9ee355d4af5b62d5f63087ed6e1 assets/hexcasting/models/item/staves/quenched_1.json
ff1f37ac81e58185d9ea63d1ef75558e30f2e193 assets/hexcasting/models/item/staves/quenched_2.json
5cb3a83a9e601d4955e0c5456c621c4ac3f3d76e assets/hexcasting/models/item/staves/quenched_3.json
d6ebc87cb0fa6f86bee3a4eade7329ebb0cf2d38 assets/hexcasting/models/item/stripped_edified_log.json
ea3f18f75776022127f3a108119e3f7a5c211c0f assets/hexcasting/models/item/stripped_edified_wood.json
0a100b64e77394606018320bbc5752a546fe0af4 assets/hexcasting/models/item/sub_sandwich.json
6a7f5af82cf8ec72c3457ef4c1ae11a76717bf88 assets/hexcasting/models/item/thought_knot.json
93b2191ffab47003f661b75a85cd833ec64f0c15 assets/hexcasting/models/item/thought_knot_written.json
5f4831d11d8f45b037a6f48e12d2e794ada7b961 assets/hexcasting/models/item/trinket.json
946970e74b8d3c76c15191f494bc1f3d7e36aa43 assets/hexcasting/models/item/trinket_filled.json
c6523de66cbfae3a1e6361c635cc693a0a089bb3 assets/hexcasting/models/item/uuid_colorizer.json
f5b45d5997acc8abe8cc70065a5790b642234fcb assets/hexcasting/models/item/warped_staff.json
30e95dd075eab5379410ce5a7e0cd53dfb606005 assets/hexcasting/models/item/warped_staff.json

View file

@ -1,4 +1,4 @@
// 1.19.2 2022-11-05T14:30:43.69127 Block States: hexcasting
// 1.19.2 2023-02-17T23:01:49.857526865 Block States: hexcasting
901e38574bdaa40ea4a0f6e773a88a95d9c03e55 assets/hexcasting/blockstates/akashic_bookshelf.json
32a77ef668198002563d68be35a24fa93c8d454a assets/hexcasting/blockstates/akashic_connector.json
85080ce0a0387583a839e4788517d675a1a35e24 assets/hexcasting/blockstates/akashic_record.json
@ -29,6 +29,7 @@ e44322f1178e121b70f45e5242d5b0e9a11c211c assets/hexcasting/blockstates/edified_w
4ffe2f23f6774045d40e3763efa161da84d777c8 assets/hexcasting/blockstates/impetus_look.json
1e45bbe847d2edbec8189249f9afb58acda3fe05 assets/hexcasting/blockstates/impetus_rightclick.json
1d568faf935ff3c67d6a7f074a5d0d3ef6406101 assets/hexcasting/blockstates/impetus_storedplayer.json
c41c3f2f39c9fa8a319a705e2183112df18cb4f8 assets/hexcasting/blockstates/quenched_allay.json
0aca7e2e67793a21ffc794c02fb2b22d02d2058a assets/hexcasting/blockstates/scroll_paper.json
e5c88e23be0552d4c06062510e8feeab510472ef assets/hexcasting/blockstates/scroll_paper_lantern.json
ef6b44bd2360926cb9dcde5bb3f1380385acea90 assets/hexcasting/blockstates/slate.json
@ -134,6 +135,7 @@ de2a5fd9b621e5086852f2191c360d9274b9b10c assets/hexcasting/models/block/impetus_
7ac5cb74f321b061c1e93b859540b508c7dcdaa4 assets/hexcasting/models/block/impetus_storedplayer_lit_south.json
46c29660e3fa78aeaa264268b43017f4b0c0d655 assets/hexcasting/models/block/impetus_storedplayer_lit_up.json
4d22557274958179da4671c43c2f387336a701a2 assets/hexcasting/models/block/impetus_storedplayer_lit_west.json
9af2754cb1e53eeaa85618cf92651b4878cf62b1 assets/hexcasting/models/block/quenched_allay.json
e1e7ce0bcc08a53b3e6634f7e5b7a6cf488cf45b assets/hexcasting/models/block/redstone_directrix_powered_dim_down.json
fb22e529f1ca638b7e952176694ab1912eb4274b assets/hexcasting/models/block/redstone_directrix_powered_dim_east.json
a5a53ec6a3cd54592dcb224245a4515a2b3b72ed assets/hexcasting/models/block/redstone_directrix_powered_dim_north.json

View file

@ -1,7 +1,7 @@
// 1.19.2 2022-11-09T19:44:43.405259 Advancements
// 1.19.2 2022-11-29T13:33:14.877218824 Advancements
b21f0b7f0cda29a7e84693df8139f2fecfeea960 data/hexcasting/advancements/aaa_wasteful_cast.json
9d8b41dd8ddfccdf2cd19433d8d7d3cf934e64db data/hexcasting/advancements/aab_big_cast.json
ef61c93d776c6f212820af20909a4c1d92822baf data/hexcasting/advancements/enlightenment.json
425b42f6da5fd6498053f565dce1f171997dbb8b data/hexcasting/advancements/enlightenment.json
8f97205fa79270eab688aa3019d6fe7dd8c8b0d3 data/hexcasting/advancements/lore.json
2f5ad49936d58c7097ac7f8fbbf3f66f9f90fd2c data/hexcasting/advancements/lore/experiment1.json
9a4eba1c9d7868906e8ea1b4ec287f54a2c379b5 data/hexcasting/advancements/lore/experiment2.json
@ -11,6 +11,6 @@ ef06ae5bd79e2c52291fbfb3c69bc2f74a604477 data/hexcasting/advancements/lore/terab
74fbb1ce0e3acf982325b9e9205f774a67956c3c data/hexcasting/advancements/lore/terabithia3.json
861374b7c144ccdbbd031a3f5042af6718ba42bf data/hexcasting/advancements/lore/terabithia4.json
e26db8dfa825b7ac572d59a548b610db7c7bf736 data/hexcasting/advancements/lore/terabithia5.json
2acbfb4efe2a72a1986c8dbe62ad8d93e9613e99 data/hexcasting/advancements/opened_eyes.json
bf319d71d9e706f9131c9484be1bc83ca2b8b6a3 data/hexcasting/advancements/opened_eyes.json
d19039a73324eb7532d035d08442f3b68bb13bcb data/hexcasting/advancements/root.json
b1b82068d65d6872c258d905d4f78499e8227ccf data/hexcasting/advancements/y_u_no_cast_angy.json

View file

@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "hexcasting:block/quenched_allay"
}
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "hexcasting:block/quenched_allay_0"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "hexcasting:block/quenched_allay_0"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "hexcasting:block/quenched_allay_1"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "hexcasting:block/quenched_allay_2"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "hexcasting:block/quenched_allay_3"
}
}

View file

@ -8,13 +8,7 @@
}
},
{
"model": "hexcasting:item/old_staff",
"predicate": {
"hexcasting:funny_level": 1.0
}
},
{
"model": "hexcasting:item/bosnia_staff",
"model": "hexcasting:item/cherry_staff",
"predicate": {
"hexcasting:funny_level": 2.0
}

View file

@ -8,13 +8,7 @@
}
},
{
"model": "hexcasting:item/old_staff",
"predicate": {
"hexcasting:funny_level": 1.0
}
},
{
"model": "hexcasting:item/bosnia_staff",
"model": "hexcasting:item/cherry_staff",
"predicate": {
"hexcasting:funny_level": 2.0
}

View file

@ -1,6 +1,6 @@
{
"parent": "minecraft:item/handheld_rod",
"textures": {
"layer0": "hexcasting:item/staves/bosnia"
"layer0": "hexcasting:item/staves/cherry"
}
}

View file

@ -8,13 +8,7 @@
}
},
{
"model": "hexcasting:item/old_staff",
"predicate": {
"hexcasting:funny_level": 1.0
}
},
{
"model": "hexcasting:item/bosnia_staff",
"model": "hexcasting:item/cherry_staff",
"predicate": {
"hexcasting:funny_level": 2.0
}

View file

@ -8,13 +8,7 @@
}
},
{
"model": "hexcasting:item/old_staff",
"predicate": {
"hexcasting:funny_level": 1.0
}
},
{
"model": "hexcasting:item/bosnia_staff",
"model": "hexcasting:item/cherry_staff",
"predicate": {
"hexcasting:funny_level": 2.0
}

View file

@ -8,13 +8,7 @@
}
},
{
"model": "hexcasting:item/old_staff",
"predicate": {
"hexcasting:funny_level": 1.0
}
},
{
"model": "hexcasting:item/bosnia_staff",
"model": "hexcasting:item/cherry_staff",
"predicate": {
"hexcasting:funny_level": 2.0
}

View file

@ -8,13 +8,7 @@
}
},
{
"model": "hexcasting:item/old_staff",
"predicate": {
"hexcasting:funny_level": 1.0
}
},
{
"model": "hexcasting:item/bosnia_staff",
"model": "hexcasting:item/cherry_staff",
"predicate": {
"hexcasting:funny_level": 2.0
}

View file

@ -0,0 +1,20 @@
{
"parent": "minecraft:item/handheld_rod",
"overrides": [
{
"model": "hexcasting:item/mangrove_staff",
"predicate": {
"hexcasting:funny_level": 0.0
}
},
{
"model": "hexcasting:item/cherry_staff",
"predicate": {
"hexcasting:funny_level": 2.0
}
}
],
"textures": {
"layer0": "hexcasting:item/staves/mangrove"
}
}

View file

@ -0,0 +1,20 @@
{
"parent": "minecraft:item/handheld_rod",
"overrides": [
{
"model": "hexcasting:item/mindsplice_staff",
"predicate": {
"hexcasting:funny_level": 0.0
}
},
{
"model": "hexcasting:item/cherry_staff",
"predicate": {
"hexcasting:funny_level": 2.0
}
}
],
"textures": {
"layer0": "hexcasting:item/staves/mindsplice"
}
}

View file

@ -8,13 +8,7 @@
}
},
{
"model": "hexcasting:item/old_staff",
"predicate": {
"hexcasting:funny_level": 1.0
}
},
{
"model": "hexcasting:item/bosnia_staff",
"model": "hexcasting:item/cherry_staff",
"predicate": {
"hexcasting:funny_level": 2.0
}

View file

@ -0,0 +1,28 @@
{
"overrides": [
{
"model": "hexcasting:block/quenched_allay_0",
"predicate": {
"hexcasting:variant": 0.0
}
},
{
"model": "hexcasting:block/quenched_allay_1",
"predicate": {
"hexcasting:variant": 1.0
}
},
{
"model": "hexcasting:block/quenched_allay_2",
"predicate": {
"hexcasting:variant": 2.0
}
},
{
"model": "hexcasting:block/quenched_allay_3",
"predicate": {
"hexcasting:variant": 3.0
}
}
]
}

View file

@ -0,0 +1,28 @@
{
"overrides": [
{
"model": "hexcasting:item/quenched_shard_0",
"predicate": {
"hexcasting:variant": 0.0
}
},
{
"model": "hexcasting:item/quenched_shard_1",
"predicate": {
"hexcasting:variant": 1.0
}
},
{
"model": "hexcasting:item/quenched_shard_2",
"predicate": {
"hexcasting:variant": 2.0
}
},
{
"model": "hexcasting:item/quenched_shard_3",
"predicate": {
"hexcasting:variant": 3.0
}
}
]
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld",
"textures": {
"layer0": "hexcasting:item/quenched_shard_0"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld",
"textures": {
"layer0": "hexcasting:item/quenched_shard_1"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld",
"textures": {
"layer0": "hexcasting:item/quenched_shard_2"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld",
"textures": {
"layer0": "hexcasting:item/quenched_shard_3"
}
}

View file

@ -0,0 +1,28 @@
{
"overrides": [
{
"model": "hexcasting:item/staves/quenched_0",
"predicate": {
"hexcasting:variant": 0.0
}
},
{
"model": "hexcasting:item/staves/quenched_1",
"predicate": {
"hexcasting:variant": 1.0
}
},
{
"model": "hexcasting:item/staves/quenched_2",
"predicate": {
"hexcasting:variant": 2.0
}
},
{
"model": "hexcasting:item/staves/quenched_3",
"predicate": {
"hexcasting:variant": 3.0
}
}
]
}

View file

@ -8,13 +8,7 @@
}
},
{
"model": "hexcasting:item/old_staff",
"predicate": {
"hexcasting:funny_level": 1.0
}
},
{
"model": "hexcasting:item/bosnia_staff",
"model": "hexcasting:item/cherry_staff",
"predicate": {
"hexcasting:funny_level": 2.0
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld_rod",
"textures": {
"layer0": "hexcasting:item/staves/quenched_0"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld_rod",
"textures": {
"layer0": "hexcasting:item/staves/quenched_1"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld_rod",
"textures": {
"layer0": "hexcasting:item/staves/quenched_2"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld_rod",
"textures": {
"layer0": "hexcasting:item/staves/quenched_3"
}
}

View file

@ -0,0 +1,20 @@
{
"parent": "minecraft:item/generated",
"overrides": [
{
"model": "hexcasting:item/thought_knot",
"predicate": {
"hexcasting:written": 0.0
}
},
{
"model": "hexcasting:item/thought_knot_written",
"predicate": {
"hexcasting:written": 1.0
}
}
],
"textures": {
"layer0": "hexcasting:item/thought_knot"
}
}

View file

@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "hexcasting:item/thought_knot",
"layer1": "hexcasting:item/thought_knot_overlay"
}
}

View file

@ -8,13 +8,7 @@
}
},
{
"model": "hexcasting:item/old_staff",
"predicate": {
"hexcasting:funny_level": 1.0
}
},
{
"model": "hexcasting:item/bosnia_staff",
"model": "hexcasting:item/cherry_staff",
"predicate": {
"hexcasting:funny_level": 2.0
}

View file

@ -7,8 +7,8 @@
"min": 0.8
},
"mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": {
"max": 2.05,
"min": 0.1
"max": 1.0,
"min": 2.2250738585072014E-308
}
},
"trigger": "hexcasting:overcast"

View file

@ -4,7 +4,7 @@
"health_used": {
"conditions": {
"mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion": {
"min": 0.1
"min": 0.0
}
},
"trigger": "hexcasting:overcast"

View file

@ -2,8 +2,8 @@ Hello, intrepid Github reader!
The "flavor text" words for things in this mod and the internal names are different. (Sorry.)
- A "Hex" is a `Cast`, cast through a [`CastingHarness`](api/spell/casting/CastingHarness.kt)
- A "Pattern" is a [`HexPattern`](api/spell/math/HexPattern.kt)
- An "Action" is an [`Operator`](api/spell/Action.kt)
- An action that pushes a spell is a [`Spell`](api/spell/SpellAction.kt)
- A "Hex" is a `Cast`, cast through a [`CastingHarness`](api/casting/eval/CastingHarness.kt)
- A "Pattern" is a [`HexPattern`](api/casting/math/HexPattern.kt)
- An "Action" is an [`Operator`](api/casting/castables/Action.kt)
- An action that pushes a spell is a [`Spell`](api/casting/castables/SpellAction.kt)

View file

@ -1,7 +1,15 @@
package at.petrak.hexcasting.api;
import at.petrak.hexcasting.api.casting.ActionRegistryEntry;
import at.petrak.hexcasting.api.casting.castables.SpecialHandler;
import com.google.common.base.Suppliers;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.phys.Vec3;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -22,6 +30,63 @@ public interface HexAPI {
}
});
/**
* Return the localization key for the given action.
* <p>
* Note we're allowed to have action <em>resource keys</em> on the client, just no actual actions.
* <p>
* Special handlers should be calling {@link SpecialHandler#getName()}
*/
default String getActionI18nKey(ResourceKey<ActionRegistryEntry> action) {
return "hexcasting.action.%s".formatted(action.location().toString());
}
default String getSpecialHandlerI18nKey(ResourceKey<SpecialHandler.Factory<?>> action) {
return "hexcasting.special.%s".formatted(action.location().toString());
}
/**
* Currently introspection/retrospection/consideration are hardcoded, but at least their names won't be
*/
default String getRawHookI18nKey(ResourceLocation name) {
return "hexcasting.rawhook.%s".formatted(name);
}
default Component getActionI18n(ResourceKey<ActionRegistryEntry> key, boolean isGreat) {
return Component.translatable(getActionI18nKey(key))
.withStyle(isGreat ? ChatFormatting.GOLD : ChatFormatting.LIGHT_PURPLE);
}
default Component getSpecialHandlerI18n(ResourceKey<SpecialHandler.Factory<?>> key) {
return Component.translatable(getSpecialHandlerI18nKey(key))
.withStyle(ChatFormatting.LIGHT_PURPLE);
}
default Component getRawHookI18n(ResourceLocation name) {
return Component.translatable(getRawHookI18nKey(name)).withStyle(ChatFormatting.LIGHT_PURPLE);
}
/**
* Register an entity with the given ID to have its velocity as perceived by OpEntityVelocity be different
* than it's "normal" velocity
*/
// Should be OK to use the type directly as the key as they're singleton identity objects
default <T extends Entity> void registerSpecialVelocityGetter(EntityType<T> key, EntityVelocityGetter<T> getter) {
}
/**
* If the entity has had a special getter registered with {@link HexAPI#registerSpecialVelocityGetter} then
* return that, otherwise return its normal delta movement
*/
default Vec3 getEntityVelocitySpecial(Entity entity) {
return entity.getDeltaMovement();
}
@FunctionalInterface
interface EntityVelocityGetter<T extends Entity> {
Vec3 getVelocity(T entity);
}
static HexAPI instance() {
return INSTANCE.get();
}

View file

@ -1,332 +0,0 @@
package at.petrak.hexcasting.api;
import at.petrak.hexcasting.api.spell.Action;
import at.petrak.hexcasting.api.spell.math.EulerPathFinder;
import at.petrak.hexcasting.api.spell.math.HexDir;
import at.petrak.hexcasting.api.spell.math.HexPattern;
import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidPattern;
import com.mojang.datafixers.util.Pair;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.saveddata.SavedData;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
public class PatternRegistry {
private static final ConcurrentMap<ResourceLocation, Action> actionLookup = new ConcurrentHashMap<>();
private static final ConcurrentMap<Action, ResourceLocation> keyLookup = new ConcurrentHashMap<>();
private static final ConcurrentLinkedDeque<SpecialHandlerEntry> specialHandlers = new ConcurrentLinkedDeque<>();
// Map signatures to the "preferred" direction they start in and their operator ID.
private static final ConcurrentMap<String, RegularEntry> regularPatternLookup =
new ConcurrentHashMap<>();
private static final ConcurrentMap<ResourceLocation, PerWorldEntry> perWorldPatternLookup =
new ConcurrentHashMap<>();
public static void mapPattern(HexPattern pattern, ResourceLocation id,
Action action) throws RegisterPatternException {
mapPattern(pattern, id, action, false);
}
/**
* Associate a given angle signature with a SpellOperator.
*/
public static void mapPattern(HexPattern pattern, ResourceLocation id, Action action,
boolean isPerWorld) throws RegisterPatternException {
if (actionLookup.containsKey(id)) {
throw new RegisterPatternException("The operator with id `%s` was already registered to: %s", id,
actionLookup.get(id));
}
actionLookup.put(id, action);
keyLookup.put(action, id);
if (isPerWorld) {
perWorldPatternLookup.put(id, new PerWorldEntry(pattern, id));
} else {
regularPatternLookup.put(pattern.anglesSignature(), new RegularEntry(pattern.getStartDir(), id));
}
}
/**
* Add a special handler, to take an arbitrary pattern and return whatever kind of operator you like.
*/
public static void addSpecialHandler(SpecialHandlerEntry handler) {
specialHandlers.add(handler);
}
/**
* Add a special handler, to take an arbitrary pattern and return whatever kind of operator you like.
*/
public static void addSpecialHandler(ResourceLocation id, SpecialHandler handler) {
addSpecialHandler(new SpecialHandlerEntry(id, handler));
}
/**
* Internal use only.
*/
public static Action matchPattern(HexPattern pat, ServerLevel overworld) throws MishapInvalidPattern {
return matchPatternAndID(pat, overworld).getFirst();
}
/**
* Internal use only.
*/
public static Pair<Action, ResourceLocation> matchPatternAndID(HexPattern pat,
ServerLevel overworld) throws MishapInvalidPattern {
// Pipeline:
// patterns are registered here every time the game boots
// when we try to look
for (var handler : specialHandlers) {
var op = handler.handler.handlePattern(pat);
if (op != null) {
return new Pair<>(op, handler.id);
}
}
// Is it global?
var sig = pat.anglesSignature();
if (regularPatternLookup.containsKey(sig)) {
var it = regularPatternLookup.get(sig);
if (!actionLookup.containsKey(it.opId)) {
throw new MishapInvalidPattern();
}
var op = actionLookup.get(it.opId);
return new Pair<>(op, it.opId);
}
// Look it up in the world?
var ds = overworld.getDataStorage();
Save perWorldPatterns =
ds.computeIfAbsent(Save::load, () -> Save.create(overworld.getSeed()), TAG_SAVED_DATA);
perWorldPatterns.fillMissingEntries(overworld.getSeed());
if (perWorldPatterns.lookup.containsKey(sig)) {
var it = perWorldPatterns.lookup.get(sig);
return new Pair<>(actionLookup.get(it.getFirst()), it.getFirst());
}
throw new MishapInvalidPattern();
}
/**
* Internal use only.
*/
@Nullable
public static Action lookupPatternByShape(HexPattern pat) {
// Pipeline:
// patterns are registered here every time the game boots
// when we try to look
for (var handler : specialHandlers) {
var op = handler.handler.handlePattern(pat);
if (op != null) {
return op;
}
}
// Is it global?
var sig = pat.anglesSignature();
if (regularPatternLookup.containsKey(sig)) {
var it = regularPatternLookup.get(sig);
if (!actionLookup.containsKey(it.opId)) {
return null;
}
return actionLookup.get(it.opId);
}
// Currently, there's no way to look up the name of a Great Spell, as the client is unaware of the correct mapping.
// TODO: add code to match any pattern in the shape of a Great Spell to its operator.
// var ds = overworld.getDataStorage();
// Save perWorldPatterns =
// ds.computeIfAbsent(Save::load, () -> Save.create(overworld.getSeed()), TAG_SAVED_DATA);
// perWorldPatterns.fillMissingEntries(overworld.getSeed());
// if (perWorldPatterns.lookup.containsKey(sig)) {
// var it = perWorldPatterns.lookup.get(sig);
// return new Pair<>(actionLookup.get(it.getFirst()), it.getFirst());
// }
return null;
}
/**
* Internal use only.
*/
public static Map<String, Pair<ResourceLocation, HexDir>> getPerWorldPatterns(ServerLevel overworld) {
var ds = overworld.getDataStorage();
Save perWorldPatterns =
ds.computeIfAbsent(Save::load, () -> Save.create(overworld.getSeed()), TAG_SAVED_DATA);
return perWorldPatterns.lookup;
}
public static ResourceLocation lookupPattern(Action action) {
return keyLookup.get(action);
}
/**
* Internal use only.
*/
public static PatternEntry lookupPattern(ResourceLocation opId) {
if (perWorldPatternLookup.containsKey(opId)) {
var it = perWorldPatternLookup.get(opId);
return new PatternEntry(it.prototype, actionLookup.get(it.opId), true);
}
for (var kv : regularPatternLookup.entrySet()) {
var sig = kv.getKey();
var entry = kv.getValue();
if (entry.opId.equals(opId)) {
var pattern = HexPattern.fromAngles(sig, entry.preferredStart);
return new PatternEntry(pattern, actionLookup.get(entry.opId), false);
}
}
throw new IllegalArgumentException("could not find a pattern for " + opId);
}
/**
* Internal use only.
*/
public static Set<ResourceLocation> getAllPerWorldPatternNames() {
return perWorldPatternLookup.keySet();
}
/**
* Special handling of a pattern. Before checking any of the normal angle-signature based patterns,
* a given pattern is run by all of these special handlers patterns. If none of them return non-null,
* then its signature is checked.
* <p>
* In the base mod, this is used for number patterns and Bookkeeper's Gambit.
*/
@FunctionalInterface
public interface SpecialHandler {
@Nullable Action handlePattern(HexPattern pattern);
}
public record SpecialHandlerEntry(ResourceLocation id, SpecialHandler handler) {
}
public static class RegisterPatternException extends Exception {
public RegisterPatternException(String msg, Object... formats) {
super(String.format(msg, formats));
}
}
private record RegularEntry(HexDir preferredStart, ResourceLocation opId) {
}
private record PerWorldEntry(HexPattern prototype, ResourceLocation opId) {
}
// Fake class we pretend to use internally
public record PatternEntry(HexPattern prototype, Action action, boolean isPerWorld) {
}
/**
* Maps angle sigs to resource locations and their preferred start dir so we can look them up in the main registry
* Save this on the world in case the random algorithm changes.
*/
public static class Save extends SavedData {
private static final String TAG_OP_ID = "op_id";
private static final String TAG_START_DIR = "start_dir";
// Maps hex signatures to (op ids, canonical start dir)
private Map<String, Pair<ResourceLocation, HexDir>> lookup;
private boolean missingEntries;
public Save(Map<String, Pair<ResourceLocation, HexDir>> lookup, boolean missingEntries) {
this.lookup = lookup;
this.missingEntries = missingEntries;
}
public Save(Map<String, Pair<ResourceLocation, HexDir>> lookup) {
this(lookup, missingEntries(lookup));
}
private static boolean missingEntries(Map<String, Pair<ResourceLocation, HexDir>> lookup) {
var allIds = lookup.values().stream().map(Pair::getFirst).collect(Collectors.toSet());
return perWorldPatternLookup.values().stream().anyMatch(it -> allIds.contains(it.opId));
}
private void fillMissingEntries(long seed) {
if (missingEntries) {
var doneAny = false;
var allIds = lookup.values().stream().map(Pair::getFirst).collect(Collectors.toSet());
for (var entry : perWorldPatternLookup.values()) {
if (!allIds.contains(entry.opId)) {
scrungle(lookup, entry.prototype, entry.opId, seed);
doneAny = true;
}
}
if (doneAny) {
setDirty();
missingEntries = false;
}
}
}
@Override
public CompoundTag save(CompoundTag tag) {
this.lookup.forEach((sig, rhs) -> {
var entry = new CompoundTag();
entry.putString(TAG_OP_ID, rhs.getFirst().toString());
entry.putInt(TAG_START_DIR, rhs.getSecond().ordinal());
tag.put(sig, entry);
});
return tag;
}
private static Save load(CompoundTag tag) {
var map = new HashMap<String, Pair<ResourceLocation, HexDir>>();
var allIds = new HashSet<ResourceLocation>();
for (var sig : tag.getAllKeys()) {
var entry = tag.getCompound(sig);
var opId = ResourceLocation.tryParse(entry.getString(TAG_OP_ID));
allIds.add(opId);
var startDir = HexDir.values()[entry.getInt(TAG_START_DIR)];
map.put(sig, new Pair<>(opId, startDir));
}
var missingEntries = perWorldPatternLookup.values().stream().anyMatch(it -> allIds.contains(it.opId));
return new Save(map, missingEntries);
}
private static void scrungle(Map<String, Pair<ResourceLocation, HexDir>> lookup, HexPattern prototype, ResourceLocation opId, long seed) {
var scrungled = EulerPathFinder.findAltDrawing(prototype, seed, it -> {
var sig = it.anglesSignature();
return !lookup.containsKey(sig) &&
!regularPatternLookup.containsKey(sig)
&& specialHandlers.stream().noneMatch(handler -> handler.handler.handlePattern(it) != null);
});
lookup.put(scrungled.anglesSignature(), new Pair<>(opId, scrungled.getStartDir()));
}
public static Save create(long seed) {
var map = new HashMap<String, Pair<ResourceLocation, HexDir>>();
PatternRegistry.perWorldPatternLookup.values().forEach(it -> scrungle(map, it.prototype, it.opId, seed));
var save = new Save(map);
save.setDirty();
return save;
}
}
public static final String TAG_SAVED_DATA = "hex.per-world-patterns";
public static String getPatternCountInfo() {
return String.format(
"Loaded %d regular patterns, " +
"%d per-world patterns, and " +
"%d special handlers.", regularPatternLookup.size(), perWorldPatternLookup.size(),
specialHandlers.size());
}
}

View file

@ -1,6 +1,6 @@
package at.petrak.hexcasting.api.addldata;
import at.petrak.hexcasting.api.spell.iota.Iota;
import at.petrak.hexcasting.api.casting.iota.Iota;
import net.minecraft.server.level.ServerLevel;
import org.jetbrains.annotations.Nullable;

View file

@ -1,6 +1,6 @@
package at.petrak.hexcasting.api.addldata;
import at.petrak.hexcasting.api.spell.iota.Iota;
import at.petrak.hexcasting.api.casting.iota.Iota;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;

View file

@ -42,7 +42,7 @@ public interface ADMediaHolder {
/**
* The priority for this media holder to be selected when casting a hex. Higher priorities are taken first.
*
* <p>
* By default,
* * Charged Amethyst has priority 1000
* * Amethyst Shards have priority 2000
@ -58,9 +58,9 @@ public interface ADMediaHolder {
/**
* Withdraws media from the holder. Returns the amount of media extracted, which may be less or more than the cost.
*
* <p>
* Even if {@link ADMediaHolder#canProvide} is false, you can still withdraw media this way.
*
* <p>
* Withdrawing a negative amount will act as though you attempted to withdraw as much media as the holder contains.
*/
default int withdrawMedia(int cost, boolean simulate) {
@ -77,10 +77,11 @@ public interface ADMediaHolder {
/**
* Inserts media into the holder. Returns the amount of media inserted, which may be less than the requested amount.
*
* <p>
* Even if {@link ADMediaHolder#canRecharge} is false, you can still insert media this way.
*
* Inserting a negative amount will act as though you attempted to insert exactly as much media as the holder was missing.
* <p>
* Inserting a negative amount will act as though you attempted to insert exactly as much media as the holder was
* missing.
*/
default int insertMedia(int amount, boolean simulate) {
var mediaHere = getMedia();
@ -101,6 +102,7 @@ public interface ADMediaHolder {
return inserting;
}
int QUENCHED_ALLAY_PRIORITY = 900;
int CHARGED_AMETHYST_PRIORITY = 1000;
int AMETHYST_SHARD_PRIORITY = 2000;
int AMETHYST_DUST_PRIORITY = 3000;

View file

@ -1,6 +1,6 @@
package at.petrak.hexcasting.api.addldata;
import at.petrak.hexcasting.api.spell.iota.Iota;
import at.petrak.hexcasting.api.casting.iota.Iota;
import at.petrak.hexcasting.common.entities.EntityWallScroll;
import at.petrak.hexcasting.xplat.IXplatAbstractions;
import net.minecraft.nbt.CompoundTag;

View file

@ -15,7 +15,8 @@ public class OvercastTrigger extends SimpleCriterionTrigger<OvercastTrigger.Inst
private static final String TAG_MEDIA_GENERATED = "media_generated";
private static final String TAG_HEALTH_USED = "health_used";
// HEY KIDS DID YOYU KNOW THERE'S NOT A CRITERIA FOR HOW MUCH ***HEALTH*** AN ENTITY HAS
private static final String TAG_HEALTH_LEFT = "mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion";
private static final String TAG_HEALTH_LEFT =
"mojang_i_am_begging_and_crying_please_add_an_entity_health_criterion";
@Override
public ResourceLocation getId() {
@ -41,6 +42,7 @@ public class OvercastTrigger extends SimpleCriterionTrigger<OvercastTrigger.Inst
public static class Instance extends AbstractCriterionTriggerInstance {
protected final MinMaxBounds.Ints mediaGenerated;
// This is the *proporttion* of the health bar.
protected final MinMaxBounds.Doubles healthUsed;
// DID YOU KNOW THERES ONE TO CHECK THE WORLD TIME, BUT NOT THE HEALTH!?
protected final MinMaxBounds.Doubles healthLeft;

View file

@ -1,6 +1,6 @@
package at.petrak.hexcasting.api.block.circle;
import at.petrak.hexcasting.api.spell.math.HexPattern;
import at.petrak.hexcasting.api.casting.math.HexPattern;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;

View file

@ -1,6 +1,6 @@
package at.petrak.hexcasting.api.block.circle;
import at.petrak.hexcasting.api.spell.math.HexPattern;
import at.petrak.hexcasting.api.casting.math.HexPattern;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.Level;

View file

@ -4,11 +4,11 @@ import at.petrak.hexcasting.api.block.HexBlockEntity;
import at.petrak.hexcasting.api.misc.FrozenColorizer;
import at.petrak.hexcasting.api.misc.MediaConstants;
import at.petrak.hexcasting.api.mod.HexConfig;
import at.petrak.hexcasting.api.spell.ParticleSpray;
import at.petrak.hexcasting.api.spell.casting.CastingContext;
import at.petrak.hexcasting.api.spell.casting.CastingHarness;
import at.petrak.hexcasting.api.spell.casting.SpellCircleContext;
import at.petrak.hexcasting.api.spell.iota.PatternIota;
import at.petrak.hexcasting.api.casting.ParticleSpray;
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment;
import at.petrak.hexcasting.api.casting.eval.CastingHarness;
import at.petrak.hexcasting.api.casting.eval.SpellCircleContext;
import at.petrak.hexcasting.api.casting.iota.PatternIota;
import at.petrak.hexcasting.api.utils.MediaHelper;
import at.petrak.hexcasting.common.items.magic.ItemCreativeUnlocker;
import at.petrak.hexcasting.common.lib.HexItems;
@ -282,7 +282,7 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen
if (player instanceof ServerPlayer splayer) {
var bounds = getBounds(this.trackedBlocks);
var ctx = new CastingContext(splayer, InteractionHand.MAIN_HAND,
var ctx = new CastingEnvironment(splayer, InteractionHand.MAIN_HAND,
new SpellCircleContext(this.getBlockPos(), bounds, this.activatorAlwaysInRange()));
var harness = new CastingHarness(ctx);

View file

@ -0,0 +1,15 @@
package at.petrak.hexcasting.api.casting;
import at.petrak.hexcasting.api.casting.castables.Action;
import at.petrak.hexcasting.api.casting.math.HexPattern;
/**
* A bit of wrapper information around an action to go in the registry.
*
* @param prototype The pattern associated with this action. The start dir acts as the "canonical" start direction
* for display in the book. For per-world patterns, the angle signature is the *shape* of the pattern
* but probably not the pattern itself.
* @param action The action itself
*/
public record ActionRegistryEntry(HexPattern prototype, Action action) {
}

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.api.spell
package at.petrak.hexcasting.api.casting
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
import at.petrak.hexcasting.api.spell.casting.sideeffects.OperatorSideEffect
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect
import at.petrak.hexcasting.api.casting.iota.Iota
/**
* What happens when an operator is through?

View file

@ -1,11 +1,12 @@
@file:JvmName("OperatorUtils")
package at.petrak.hexcasting.api.spell
package at.petrak.hexcasting.api.casting
import at.petrak.hexcasting.api.spell.iota.*
import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
import at.petrak.hexcasting.api.casting.iota.*
import at.petrak.hexcasting.api.casting.iota.ContinuationIota
import at.petrak.hexcasting.api.casting.math.HexPattern
import at.petrak.hexcasting.api.casting.mishaps.MishapInvalidIota
import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughArgs
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import com.mojang.datafixers.util.Either
import com.mojang.math.Vector3f
@ -13,9 +14,9 @@ import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.Mob
import net.minecraft.world.entity.decoration.ArmorStand
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.entity.npc.Villager
import net.minecraft.world.phys.Vec3
import java.util.function.DoubleUnaryOperator
import kotlin.math.abs
@ -99,14 +100,14 @@ fun List<Iota>.getPlayer(idx: Int, argc: Int = 0): ServerPlayer {
throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.player")
}
fun List<Iota>.getVillager(idx: Int, argc: Int = 0): Villager {
fun List<Iota>.getMob(idx: Int, argc: Int = 0): Mob {
val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) }
if (x is EntityIota) {
val e = x.entity
if (e is Villager)
if (e is Mob)
return e
}
throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.villager")
throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.mob")
}
fun List<Iota>.getLivingEntityButNotArmorStand(idx: Int, argc: Int = 0): LivingEntity {
@ -216,7 +217,7 @@ fun List<Iota>.getPositiveIntUnderInclusive(idx: Int, max: Int, argc: Int = 0):
if (x is DoubleIota) {
val double = x.double
val rounded = double.roundToInt()
if (abs(double - rounded) <= DoubleIota.TOLERANCE && rounded in 0 .. max) {
if (abs(double - rounded) <= DoubleIota.TOLERANCE && rounded in 0..max) {
return rounded
}
}

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell
package at.petrak.hexcasting.api.casting
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.common.network.MsgCastParticleAck
@ -6,6 +6,10 @@ import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.phys.Vec3
/**
* @param fuzziness the radius of the sphere the particle might happen in (pos)
* @param spread the max angle in radians the particle can move in, in relation to vel
*/
data class ParticleSpray(val pos: Vec3, val vel: Vec3, val fuzziness: Double, val spread: Double, val count: Int = 20) {
companion object {
@JvmStatic

View file

@ -0,0 +1,57 @@
package at.petrak.hexcasting.api.casting;
import at.petrak.hexcasting.api.casting.castables.SpecialHandler;
import net.minecraft.resources.ResourceKey;
/**
* Possible things we find when trying to match a pattern's shape.
*/
public abstract sealed class PatternShapeMatch {
/**
* I've never met that pattern in my life
*/
public static final class Nothing extends PatternShapeMatch {
}
/**
* The shape exactly matches a pattern that isn't altered per world
*/
public static final class Normal extends PatternShapeMatch {
public final ResourceKey<ActionRegistryEntry> key;
public Normal(ResourceKey<ActionRegistryEntry> key) {
this.key = key;
}
}
/**
* The pattern is the right <em>shape</em> to be one of the per-world patterns.
* <p>
* On the server, {@link PerWorld#certain} means whether this is an exact match, or if it's just the
* right shape. (In other words it should only actually be casted if it is true.)
* <p>
* On the client, it is always false.
*/
public static final class PerWorld extends PatternShapeMatch {
public final ResourceKey<ActionRegistryEntry> key;
public final boolean certain;
public PerWorld(ResourceKey<ActionRegistryEntry> key, boolean certain) {
this.key = key;
this.certain = certain;
}
}
/**
* The shape matches a special handler
*/
public static final class Special extends PatternShapeMatch {
public final ResourceKey<SpecialHandler.Factory<?>> key;
public final SpecialHandler handler;
public Special(ResourceKey<SpecialHandler.Factory<?>> key, SpecialHandler handler) {
this.key = key;
this.handler = handler;
}
}
}

View file

@ -0,0 +1,7 @@
package at.petrak.hexcasting.api.casting
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
interface RenderedSpell {
fun cast(ctx: CastingEnvironment)
}

View file

@ -1,6 +1,6 @@
package at.petrak.hexcasting.api.spell
package at.petrak.hexcasting.api.casting
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.casting.iota.Iota
/**
* Restricted interface for functional lists.

View file

@ -0,0 +1,59 @@
package at.petrak.hexcasting.api.casting.castables
import at.petrak.hexcasting.api.casting.OperationResult
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation
import at.petrak.hexcasting.api.casting.iota.Iota
import net.minecraft.world.phys.Vec3
import java.text.DecimalFormat
/**
* Manipulates the stack in some way, usually by popping some number of values off the stack
* and pushing one new value.
* For a more "traditional" pop arguments, push return experience, see [ConstMediaAction].
*
* Instances of this can exist on the client, but they should NEVER be used there. They only
* exist on the client because Minecraft's registry system demands they do; any information
* the client needs about them is stored elsewhere. (For example, their canonical stroke order
* is stored in [ActionRegistryEntry], and their localization key is gotten from the resource key
* via [at.petrak.hexcasting.api.HexAPI.getActionI18nKey].)
*/
interface Action {
/**
* Operate on the stack. Return the new stack and any side effects of the cast.
*
* Although this is passed a [MutableList], this is only for the convenience of implementors.
* It is a clone of the stack and modifying it does nothing. You must return the new stack
* with the [OperationResult].
*
* A particle effect at the cast site and various messages and advancements are done automagically.
*/
fun operate(
continuation: SpellContinuation,
stack: MutableList<Iota>,
ravenmind: Iota?,
ctx: CastingEnvironment
): OperationResult
companion object {
// I see why vzakii did this: you can't raycast out to infinity!
const val MAX_DISTANCE: Double = 32.0
const val MAX_DISTANCE_FROM_SENTINEL: Double = 16.0
@JvmStatic
fun raycastEnd(origin: Vec3, look: Vec3): Vec3 =
origin.add(look.normalize().scale(MAX_DISTANCE))
@JvmStatic
fun makeConstantOp(x: Iota): Action = object : ConstMediaAction {
override val argc: Int
get() = 0
override fun execute(args: List<Iota>, ctx: CastingEnvironment): List<Iota> =
listOf(x)
}
public val DOUBLE_FORMATTER = DecimalFormat("####.####")
}
}

View file

@ -1,10 +1,11 @@
package at.petrak.hexcasting.api.spell
package at.petrak.hexcasting.api.casting.castables
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
import at.petrak.hexcasting.api.spell.casting.sideeffects.OperatorSideEffect
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
import at.petrak.hexcasting.api.casting.OperationResult
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughArgs
/**
* A SimpleOperator that always costs the same amount of media.
@ -14,13 +15,13 @@ interface ConstMediaAction : Action {
val mediaCost: Int
get() = 0
fun execute(args: List<Iota>, ctx: CastingContext): List<Iota>
fun execute(args: List<Iota>, ctx: CastingEnvironment): List<Iota>
override fun operate(
continuation: SpellContinuation,
stack: MutableList<Iota>,
ravenmind: Iota?,
ctx: CastingContext
ctx: CastingEnvironment
): OperationResult {
if (this.argc > stack.size)
throw MishapNotEnoughArgs(this.argc, stack.size)

View file

@ -0,0 +1,40 @@
package at.petrak.hexcasting.api.casting.castables;
import at.petrak.hexcasting.api.casting.math.HexPattern;
import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.Nullable;
/**
* Special handling of a pattern. Before checking any of the normal angle-signature based patterns,
* a given pattern is run by all of these special handlers patterns. If none of them return non-null,
* then its signature is checked.
* <p>
* In the base mod, this is used for number patterns and Bookkeeper's Gambit.
* <p>
* There's a separation between the special handlers and their factories so we never have to use
* {@link Action} instances on the client. We can have SpecialHandlers on the client though because they're just
* wrappers.
*/
public interface SpecialHandler {
/**
* Convert this to an action, for modification of the stack and state.
* <p>
* This is called on the SERVER-SIDE ONLY.
*/
Action act();
/**
* Get the name of this handler.
*/
Component getName();
/**
* Given a pattern, possibly make up the special handler from it.
* <p>
* This is what goes in the registry! Think of it like BlockEntityType vs BlockEntity.
*/
@FunctionalInterface
public interface Factory<T extends SpecialHandler> {
@Nullable T tryMatch(HexPattern pattern);
}
}

View file

@ -1,28 +1,31 @@
package at.petrak.hexcasting.api.spell
package at.petrak.hexcasting.api.casting.castables
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
import at.petrak.hexcasting.api.spell.casting.sideeffects.OperatorSideEffect
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
import at.petrak.hexcasting.api.casting.OperationResult
import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.RenderedSpell
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect
import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughArgs
interface SpellAction : Action {
val argc: Int
fun hasCastingSound(ctx: CastingContext): Boolean = true
fun hasCastingSound(ctx: CastingEnvironment): Boolean = true
fun awardsCastingStat(ctx: CastingContext): Boolean = true
fun awardsCastingStat(ctx: CastingEnvironment): Boolean = true
fun execute(
args: List<Iota>,
ctx: CastingContext
ctx: CastingEnvironment
): Triple<RenderedSpell, Int, List<ParticleSpray>>?
override fun operate(
continuation: SpellContinuation,
stack: MutableList<Iota>,
ravenmind: Iota?,
ctx: CastingContext
ctx: CastingEnvironment
): OperationResult {
if (this.argc > stack.size)
throw MishapNotEnoughArgs(this.argc, stack.size)
@ -36,8 +39,6 @@ interface SpellAction : Action {
if (media > 0)
sideEffects.add(OperatorSideEffect.ConsumeMedia(media))
// Don't have an effect if the caster isn't enlightened, even if processing other side effects
if (!isGreat || ctx.isCasterEnlightened)
sideEffects.add(
OperatorSideEffect.AttemptSpell(
spell,

View file

@ -0,0 +1,20 @@
package at.petrak.hexcasting.api.casting.eval
import at.petrak.hexcasting.api.casting.eval.sideeffects.EvalSound
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect
import at.petrak.hexcasting.api.casting.eval.vm.FunctionalData
import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation
/**
* The result of doing something to a cast harness.
*
* Contains the next thing to execute after this is finished, the modified state of the stack,
* and side effects, as well as display information for the client.
*/
data class CastResult(
val continuation: SpellContinuation,
val newData: FunctionalData?,
val sideEffects: List<OperatorSideEffect>,
val resolutionType: ResolvedPatternType,
val sound: EvalSound,
)

View file

@ -1,12 +1,12 @@
package at.petrak.hexcasting.api.spell.casting
package at.petrak.hexcasting.api.casting.eval
import at.petrak.hexcasting.api.HexAPI.modLoc
import at.petrak.hexcasting.api.casting.castables.Action
import at.petrak.hexcasting.api.casting.mishaps.MishapEntityTooFarAway
import at.petrak.hexcasting.api.casting.mishaps.MishapEvalTooDeep
import at.petrak.hexcasting.api.casting.mishaps.MishapLocationTooFarAway
import at.petrak.hexcasting.api.misc.DiscoveryHandlers
import at.petrak.hexcasting.api.mod.HexConfig
import at.petrak.hexcasting.api.spell.Action
import at.petrak.hexcasting.api.spell.mishaps.MishapEntityTooFarAway
import at.petrak.hexcasting.api.spell.mishaps.MishapEvalTooDeep
import at.petrak.hexcasting.api.spell.mishaps.MishapLocationTooFarAway
import at.petrak.hexcasting.api.utils.otherHand
import at.petrak.hexcasting.common.items.magic.ItemCreativeUnlocker
import at.petrak.hexcasting.xplat.IXplatAbstractions
@ -25,7 +25,7 @@ import kotlin.math.min
/**
* Transient info about the moment the spell started being cast.
*/
data class CastingContext(
data class CastingEnvironment(
val caster: ServerPlayer,
val castingHand: InteractionHand,
val source: CastSource,
@ -49,6 +49,8 @@ data class CastingContext(
private val entitiesGivenMotion = mutableSetOf<Entity>()
// TODO: what the hell does this function even do. why are we using it. why do we continually put a predicate
// into here and then do the *same* predicate *again*
inline fun getHeldItemToOperateOn(acceptItemIf: (ItemStack) -> Boolean): Pair<ItemStack, InteractionHand> {
val handItem = caster.getItemInHand(otherHand)
if (!acceptItemIf(handItem)) {

View file

@ -1,48 +1,53 @@
package at.petrak.hexcasting.api.spell.casting
package at.petrak.hexcasting.api.casting.eval
import at.petrak.hexcasting.api.PatternRegistry
import at.petrak.hexcasting.api.HexAPI
import at.petrak.hexcasting.api.advancements.HexAdvancementTriggers
import at.petrak.hexcasting.api.block.circle.BlockEntityAbstractImpetus
import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.PatternShapeMatch
import at.petrak.hexcasting.api.casting.PatternShapeMatch.*
import at.petrak.hexcasting.api.casting.SpellList
import at.petrak.hexcasting.api.casting.castables.Action
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect
import at.petrak.hexcasting.api.casting.eval.vm.FrameEvaluate
import at.petrak.hexcasting.api.casting.eval.vm.FunctionalData
import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.ListIota
import at.petrak.hexcasting.api.casting.iota.PatternIota
import at.petrak.hexcasting.api.casting.iota.ContinuationIota
import at.petrak.hexcasting.api.casting.math.HexDir
import at.petrak.hexcasting.api.casting.math.HexPattern
import at.petrak.hexcasting.api.casting.mishaps.*
import at.petrak.hexcasting.api.misc.DiscoveryHandlers
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.misc.HexDamageSources
import at.petrak.hexcasting.api.mod.HexConfig
import at.petrak.hexcasting.api.mod.HexItemTags
import at.petrak.hexcasting.api.mod.HexStatistics
import at.petrak.hexcasting.api.spell.Action
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.eval.ContinuationFrame
import at.petrak.hexcasting.api.spell.casting.eval.FrameEvaluate
import at.petrak.hexcasting.api.spell.casting.eval.FunctionalData
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
import at.petrak.hexcasting.api.spell.casting.sideeffects.EvalSound
import at.petrak.hexcasting.api.spell.casting.sideeffects.OperatorSideEffect
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.iota.ListIota
import at.petrak.hexcasting.api.spell.iota.PatternIota
import at.petrak.hexcasting.api.spell.iota.ContinuationIota
import at.petrak.hexcasting.api.spell.math.HexDir
import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.spell.mishaps.*
import at.petrak.hexcasting.api.mod.HexTags
import at.petrak.hexcasting.api.utils.*
import at.petrak.hexcasting.common.casting.PatternRegistryManifest
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes
import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.ChatFormatting
import com.mojang.datafixers.util.Either
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.sounds.SoundSource
import net.minecraft.util.Mth
import net.minecraft.world.level.gameevent.GameEvent
import net.minecraft.world.phys.Vec3
import kotlin.math.max
import kotlin.math.min
/**
* Keeps track of a player casting a spell on the server.
* It's stored as NBT on the wand.
* It's stored as NBT on the player.
*
* TODO oh god this entire class needs a gigantic refactor. why are there like 6 different entrypoints for casting
* a pattern. oh god.
*/
class CastingHarness private constructor(
var stack: MutableList<Iota>,
@ -50,13 +55,13 @@ class CastingHarness private constructor(
var parenCount: Int,
var parenthesized: List<Iota>,
var escapeNext: Boolean,
val ctx: CastingContext,
val ctx: CastingEnvironment,
val prepackagedColorizer: FrozenColorizer? // for trinkets with colorizers
) {
@JvmOverloads
constructor(
ctx: CastingContext,
ctx: CastingEnvironment,
prepackagedColorizer: FrozenColorizer? = null
) : this(mutableListOf(), null, 0, mutableListOf(), false, ctx, prepackagedColorizer)
@ -65,7 +70,7 @@ class CastingHarness private constructor(
*/
fun executeIota(iota: Iota, world: ServerLevel): ControllerInfo = executeIotas(listOf(iota), world)
private fun displayPattern(escapeNext: Boolean, parenCount: Int, iotaRepresentation: Component) {
private fun displayPatternDebug(escapeNext: Boolean, parenCount: Int, iotaRepresentation: Component) {
if (this.ctx.debugPatterns) {
val display = " ".repeat(parenCount).asTextComponent
if (escapeNext)
@ -76,24 +81,6 @@ class CastingHarness private constructor(
}
}
private fun getOperatorForPattern(iota: Iota, world: ServerLevel): Action? {
if (iota is PatternIota)
return PatternRegistry.matchPattern(iota.pattern, world)
return null
}
private fun getPatternForFrame(frame: ContinuationFrame): HexPattern? {
if (frame !is FrameEvaluate) return null
return (frame.list.car as? PatternIota)?.pattern
}
private fun getOperatorForFrame(frame: ContinuationFrame, world: ServerLevel): Action? {
if (frame !is FrameEvaluate) return null
return getOperatorForPattern(frame.list.car, world)
}
/**
* Given a list of iotas, execute them in sequence.
*/
@ -108,24 +95,9 @@ class CastingHarness private constructor(
// Take the top of the continuation stack...
val next = continuation.frame
// ...and execute it.
val result = try {
next.evaluate(continuation.next, world, this)
} catch (mishap: Mishap) {
val pattern = getPatternForFrame(next)
val operator = getOperatorForFrame(next, world)
CastResult(
continuation,
null,
mishap.resolutionType(ctx),
listOf(
OperatorSideEffect.DoMishap(
mishap,
Mishap.Context(pattern ?: HexPattern(HexDir.WEST), operator)
)
),
HexEvalSounds.MISHAP,
)
}
// TODO there used to be error checking code here; I'm pretty sure any and all mishaps should already
// get caught and folded into CastResult by evaluate.
val result = next.evaluate(continuation.next, world, this)
// Then write all pertinent data back to the harness for the next iteration.
if (result.newData != null) {
this.applyFunctionalData(result.newData)
@ -167,11 +139,35 @@ class CastingHarness private constructor(
)
}
/**
* this DOES NOT THROW THINGS
*/
@Throws()
fun getUpdate(iota: Iota, world: ServerLevel, continuation: SpellContinuation): CastResult {
try {
// TODO we can have a special intro/retro sound
// ALSO TODO need to add reader macro-style things
try {
this.handleParentheses(iota)?.let { (data, resolutionType) ->
return@getUpdate CastResult(continuation, data, resolutionType, listOf(), HexEvalSounds.OPERATOR)
return@getUpdate CastResult(continuation, data, listOf(), resolutionType, HexEvalSounds.OPERATOR)
}
} catch (e: MishapTooManyCloseParens) {
// This is ridiculous and needs to be fixed
return CastResult(
continuation,
null,
listOf(
OperatorSideEffect.DoMishap(
e,
Mishap.Context(
(iota as? PatternIota)?.pattern ?: HexPattern(HexDir.WEST),
HexAPI.instance().getRawHookI18n(HexAPI.modLoc("close_paren"))
)
)
),
ResolvedPatternType.ERRORED,
HexEvalSounds.MISHAP
)
}
if (iota is PatternIota) {
@ -181,56 +177,40 @@ class CastingHarness private constructor(
return CastResult(
iota.continuation!!,
null,
ResolvedPatternType.EVALUATED,
listOf(),
ResolvedPatternType.EVALUATED,
HexEvalSounds.HERMES
)
} else {
return CastResult(
continuation,
null,
ResolvedPatternType.INVALID, // Should never matter
listOf(
OperatorSideEffect.DoMishap(
MishapUnescapedValue(iota),
Mishap.Context(HexPattern(HexDir.WEST), null)
)
),
), // Should never matter
ResolvedPatternType.INVALID,
HexEvalSounds.MISHAP
)
}
} catch (mishap: Mishap) {
return CastResult(
continuation,
null,
mishap.resolutionType(ctx),
listOf(
OperatorSideEffect.DoMishap(
mishap,
Mishap.Context(
(iota as? PatternIota)?.pattern ?: HexPattern(HexDir.WEST),
getOperatorForPattern(iota, world)
)
)
),
HexEvalSounds.MISHAP
)
} catch (exception: Exception) {
// This means something very bad has happened
exception.printStackTrace()
return CastResult(
continuation,
null,
ResolvedPatternType.ERRORED,
listOf(
OperatorSideEffect.DoMishap(
MishapError(exception),
Mishap.Context(
(iota as? PatternIota)?.pattern ?: HexPattern(HexDir.WEST),
getOperatorForPattern(iota, world)
null
)
)
),
ResolvedPatternType.ERRORED,
HexEvalSounds.MISHAP
)
}
@ -240,33 +220,48 @@ class CastingHarness private constructor(
* When the server gets a packet from the client with a new pattern,
* handle it functionally.
*/
fun updateWithPattern(newPat: HexPattern, world: ServerLevel, continuation: SpellContinuation): CastResult {
var actionIdPair: Pair<Action, ResourceLocation>? = null
private fun updateWithPattern(newPat: HexPattern, world: ServerLevel, continuation: SpellContinuation): CastResult {
var castedName: Component? = null
try {
// Don't catch this one
val mojangPair = PatternRegistry.matchPatternAndID(newPat, world)
actionIdPair = mojangPair.first to mojangPair.second
if (this.ctx.spellCircle == null && !HexConfig.server().isActionAllowed(actionIdPair.second)) {
throw MishapDisallowedSpell()
} else if (this.ctx.spellCircle != null
&& !HexConfig.server().isActionAllowedInCircles(actionIdPair.second)
) {
throw MishapDisallowedSpell("disallowed_circle")
val lookup = PatternRegistryManifest.matchPattern(newPat, world, false)
val lookupResult: Either<Action, List<OperatorSideEffect>> = if (lookup is Normal || lookup is PerWorld) {
val key = when (lookup) {
is Normal -> lookup.key
is PerWorld -> lookup.key
else -> throw IllegalStateException()
}
val pattern = actionIdPair.first
val reqsEnlightenment = isOfTag(IXplatAbstractions.INSTANCE.actionRegistry, key, HexTags.Actions.REQUIRES_ENLIGHTENMENT)
val canEnlighten = isOfTag(IXplatAbstractions.INSTANCE.actionRegistry, key, HexTags.Actions.CAN_START_ENLIGHTEN)
val unenlightened = pattern.isGreat && !ctx.isCasterEnlightened
castedName = HexAPI.instance().getActionI18n(key, reqsEnlightenment)
if (!ctx.isCasterEnlightened && reqsEnlightenment) {
Either.right(listOf(OperatorSideEffect.RequiredEnlightenment(canEnlighten)))
} else {
val regiEntry = IXplatAbstractions.INSTANCE.actionRegistry.get(key)!!
Either.left(regiEntry.action)
}
} else if (lookup is Special) {
castedName = lookup.handler.name
Either.left(lookup.handler.act())
} else if (lookup is PatternShapeMatch.Nothing) {
throw MishapInvalidPattern()
} else {
throw IllegalStateException()
}
// TODO: the config denylist should be handled per VM type.
// I just removed it for now, should re-add it...
val sideEffects = mutableListOf<OperatorSideEffect>()
var stack2: List<Iota>? = null
var cont2 = continuation
var ravenmind2: Iota? = null
if (!unenlightened || pattern.alwaysProcessGreatSpell) {
displayPattern(false, 0, pattern.displayName)
val result = pattern.operate(
if (lookupResult.left().isPresent) {
val action = lookupResult.left().get()
displayPatternDebug(false, 0, castedName)
val result = action.operate(
continuation,
this.stack.toMutableList(),
this.ravenmind,
@ -277,13 +272,13 @@ class CastingHarness private constructor(
ravenmind2 = result.newRavenmind
// TODO parens also break prescience
sideEffects.addAll(result.sideEffects)
}
if (unenlightened) {
sideEffects.add(OperatorSideEffect.RequiredEnlightenment(pattern.causesBlindDiversion))
} else {
val problems = lookupResult.right().get()
sideEffects.addAll(problems)
}
// Stick a poofy particle effect at the caster position
// TODO again this should be on the VM lalala
if (this.ctx.spellCircle == null)
sideEffects.add(
OperatorSideEffect.Particles(
@ -305,7 +300,8 @@ class CastingHarness private constructor(
hereFd
}
var soundType = if (this.ctx.source == CastingContext.CastSource.STAFF) {
// TODO again this should be per VM
var soundType = if (this.ctx.source == CastingEnvironment.CastSource.STAFF) {
HexEvalSounds.OPERATOR
} else {
HexEvalSounds.NOTHING
@ -326,8 +322,8 @@ class CastingHarness private constructor(
return CastResult(
cont2,
fd,
ResolvedPatternType.EVALUATED,
sideEffects,
ResolvedPatternType.EVALUATED,
soundType,
)
@ -335,8 +331,8 @@ class CastingHarness private constructor(
return CastResult(
continuation,
null,
listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(newPat, castedName))),
mishap.resolutionType(ctx),
listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(newPat, actionIdPair?.first))),
HexEvalSounds.MISHAP
)
}
@ -388,6 +384,7 @@ class CastingHarness private constructor(
* Return a non-null value if we handled this in some sort of parenthesey way,
* either escaping it onto the stack or changing the parenthese-handling state.
*/
@Throws(MishapTooManyCloseParens::class)
private fun handleParentheses(iota: Iota): Pair<FunctionalData, ResolvedPatternType>? {
val sig = (iota as? PatternIota)?.pattern?.anglesSignature()
@ -485,14 +482,17 @@ class CastingHarness private constructor(
}
}
// TODO: replace this once we can read things from the client
/*
if (out != null) {
val display = if (iota is PatternIota) {
PatternNameHelper.representationForPattern(iota.pattern)
.copy()
.withStyle(if (out.second == ResolvedPatternType.ESCAPED) ChatFormatting.YELLOW else ChatFormatting.AQUA)
} else iota.display()
displayPattern(this.escapeNext, displayDepth, display)
displayPatternDebug(this.escapeNext, displayDepth, display)
}
*/
return out
}
@ -539,7 +539,7 @@ class CastingHarness private constructor(
false
}
if (casterStack.`is`(HexItemTags.STAVES) || hexHolderDrawsFromInventory) {
if (casterStack.`is`(HexTags.Items.STAVES) || hexHolderDrawsFromInventory) {
val mediaSources = DiscoveryHandlers.collectMediaHolders(this)
.sortedWith(Comparator(::compareMediaItem).reversed())
for (source in mediaSources) {
@ -551,14 +551,14 @@ class CastingHarness private constructor(
if (allowOvercast && costLeft > 0) {
// Cast from HP!
val mediaToHealth = HexConfig.common().mediaToHealthRate()
val healthtoRemove = costLeft.toDouble() / mediaToHealth
val healthToRemove = max(costLeft.toDouble() / mediaToHealth, 0.5)
val mediaAbleToCastFromHP = this.ctx.caster.health * mediaToHealth
val mediaToActuallyPayFor = min(mediaAbleToCastFromHP.toInt(), costLeft)
costLeft -= if (!fake) {
Mishap.trulyHurt(this.ctx.caster, HexDamageSources.OVERCAST, healthtoRemove.toFloat())
Mishap.trulyHurt(this.ctx.caster, HexDamageSources.OVERCAST, healthToRemove.toFloat())
val actuallyTaken = (mediaAbleToCastFromHP - (this.ctx.caster.health * mediaToHealth)).toInt()
val actuallyTaken = Mth.ceil(mediaAbleToCastFromHP - (this.ctx.caster.health * mediaToHealth))
HexAdvancementTriggers.OVERCAST_TRIGGER.trigger(this.ctx.caster, actuallyTaken)
this.ctx.caster.awardStat(HexStatistics.MEDIA_OVERCAST, mediaCost - costLeft)
@ -633,7 +633,7 @@ class CastingHarness private constructor(
}
@JvmStatic
fun fromNBT(nbt: CompoundTag, ctx: CastingContext): CastingHarness {
fun fromNBT(nbt: CompoundTag, ctx: CastingEnvironment): CastingHarness {
return try {
val stack = mutableListOf<Iota>()
val stackTag = nbt.getList(TAG_STACK, Tag.TAG_COMPOUND)
@ -672,12 +672,4 @@ class CastingHarness private constructor(
data class TempControllerInfo(
var earlyExit: Boolean,
)
data class CastResult(
val continuation: SpellContinuation,
val newData: FunctionalData?,
val resolutionType: ResolvedPatternType,
val sideEffects: List<OperatorSideEffect>,
val sound: EvalSound,
)
}

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.casting
package at.petrak.hexcasting.api.casting.eval
import net.minecraft.nbt.CompoundTag

View file

@ -1,7 +1,7 @@
package at.petrak.hexcasting.api.spell.casting
package at.petrak.hexcasting.api.casting.eval
import at.petrak.hexcasting.api.spell.math.HexCoord
import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.casting.math.HexCoord
import at.petrak.hexcasting.api.casting.math.HexPattern
import at.petrak.hexcasting.api.utils.NBTBuilder
import net.minecraft.nbt.CompoundTag
import java.util.*

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.casting
package at.petrak.hexcasting.api.casting.eval
import at.petrak.hexcasting.api.utils.getSafe

View file

@ -0,0 +1,10 @@
package at.petrak.hexcasting.api.casting.eval;
import at.petrak.hexcasting.api.casting.math.HexDir;
import at.petrak.hexcasting.api.casting.math.HexPattern;
public final class SpecialPatterns {
public static final HexPattern INTROSPECTION = HexPattern.fromAngles("qqq", HexDir.WEST);
public static final HexPattern RETROSPECTION = HexPattern.fromAngles("eee", HexDir.EAST);
public static final HexPattern CONSIDERATION = HexPattern.fromAngles("qqqaw", HexDir.WEST);
}

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.casting
package at.petrak.hexcasting.api.casting.eval
import at.petrak.hexcasting.api.utils.NBTBuilder
import net.minecraft.core.BlockPos
@ -6,7 +6,7 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.world.phys.AABB
/**
* Optional field on a [CastingContext] for the spell circle
* Optional field on a [CastingEnvironment] for the spell circle
*/
data class SpellCircleContext(val impetusPos: BlockPos, val aabb: AABB, val activatorAlwaysInRange: Boolean) {
fun serializeToNBT() = NBTBuilder {

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.casting.sideeffects;
package at.petrak.hexcasting.api.casting.eval.sideeffects;
import net.minecraft.sounds.SoundEvent;
import org.jetbrains.annotations.Nullable;

View file

@ -1,13 +1,13 @@
package at.petrak.hexcasting.api.spell.casting.sideeffects
package at.petrak.hexcasting.api.casting.eval.sideeffects
import at.petrak.hexcasting.api.advancements.HexAdvancementTriggers
import at.petrak.hexcasting.api.block.circle.BlockEntityAbstractImpetus
import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.RenderedSpell
import at.petrak.hexcasting.api.casting.eval.CastingHarness
import at.petrak.hexcasting.api.casting.mishaps.Mishap
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.mod.HexStatistics
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.RenderedSpell
import at.petrak.hexcasting.api.spell.casting.CastingHarness
import at.petrak.hexcasting.api.spell.mishaps.Mishap
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import at.petrak.hexcasting.common.lib.HexItems
import net.minecraft.Util
@ -69,7 +69,7 @@ sealed class OperatorSideEffect {
data class DoMishap(val mishap: Mishap, val errorCtx: Mishap.Context) : OperatorSideEffect() {
override fun performEffect(harness: CastingHarness): Boolean {
val msg = mishap.errorMessage(harness.ctx, errorCtx);
val msg = mishap.errorMessageWithName(harness.ctx, errorCtx);
if (harness.ctx.spellCircle != null) {
val tile = harness.ctx.world.getBlockEntity(harness.ctx.spellCircle.impetusPos)
if (tile is BlockEntityAbstractImpetus) {

View file

@ -1,9 +1,9 @@
package at.petrak.hexcasting.api.spell.casting.eval
package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingHarness
import at.petrak.hexcasting.api.spell.casting.CastingHarness.CastResult
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.casting.SpellList
import at.petrak.hexcasting.api.casting.eval.CastingHarness
import at.petrak.hexcasting.api.casting.eval.CastResult
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.utils.getList
import at.petrak.hexcasting.api.utils.hasList
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes

View file

@ -1,9 +1,10 @@
package at.petrak.hexcasting.api.spell.casting.eval
package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingHarness
import at.petrak.hexcasting.api.spell.casting.ResolvedPatternType
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.casting.SpellList
import at.petrak.hexcasting.api.casting.eval.CastResult
import at.petrak.hexcasting.api.casting.eval.CastingHarness
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.utils.NBTBuilder
import at.petrak.hexcasting.api.utils.serializeToNBT
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds
@ -23,7 +24,7 @@ data class FrameEvaluate(val list: SpellList, val isMetacasting: Boolean) : Cont
continuation: SpellContinuation,
level: ServerLevel,
harness: CastingHarness
): CastingHarness.CastResult {
): CastResult {
// If there are patterns left...
return if (list.nonEmpty) {
val newCont = if (list.cdr.nonEmpty) { // yay TCO
@ -39,7 +40,7 @@ data class FrameEvaluate(val list: SpellList, val isMetacasting: Boolean) : Cont
}
} else {
// If there are no patterns (e.g. empty Hermes), just return OK.
CastingHarness.CastResult(continuation, null, ResolvedPatternType.EVALUATED, listOf(), HexEvalSounds.HERMES)
CastResult(continuation, null, listOf(), ResolvedPatternType.EVALUATED, HexEvalSounds.HERMES)
}
}

View file

@ -1,8 +1,9 @@
package at.petrak.hexcasting.api.spell.casting.eval
package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.spell.casting.CastingHarness
import at.petrak.hexcasting.api.spell.casting.ResolvedPatternType
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.casting.eval.CastResult
import at.petrak.hexcasting.api.casting.eval.CastingHarness
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.utils.NBTBuilder
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds
import net.minecraft.server.level.ServerLevel
@ -20,12 +21,12 @@ object FrameFinishEval : ContinuationFrame {
continuation: SpellContinuation,
level: ServerLevel,
harness: CastingHarness
): CastingHarness.CastResult {
return CastingHarness.CastResult(
): CastResult {
return CastResult(
continuation,
FunctionalData(harness.stack.toList(), 0, listOf(), false, harness.ravenmind),
ResolvedPatternType.EVALUATED,
listOf(),
ResolvedPatternType.EVALUATED,
HexEvalSounds.NOTHING,
)
}

View file

@ -1,10 +1,11 @@
package at.petrak.hexcasting.api.spell.casting.eval
package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingHarness
import at.petrak.hexcasting.api.spell.casting.ResolvedPatternType
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.iota.ListIota
import at.petrak.hexcasting.api.casting.SpellList
import at.petrak.hexcasting.api.casting.eval.CastResult
import at.petrak.hexcasting.api.casting.eval.CastingHarness
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.ListIota
import at.petrak.hexcasting.api.utils.NBTBuilder
import at.petrak.hexcasting.api.utils.serializeToNBT
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds
@ -39,7 +40,7 @@ data class FrameForEach(
continuation: SpellContinuation,
level: ServerLevel,
harness: CastingHarness
): CastingHarness.CastResult {
): CastResult {
// If this isn't the very first Thoth step (i.e. no Thoth computations run yet)...
val stack = if (baseStack == null) {
// init stack to the harness stack...
@ -67,11 +68,11 @@ data class FrameForEach(
val tStack = stack.toMutableList()
tStack.add(stackTop)
// TODO: this means we could have Thoth casting do a different sound
return CastingHarness.CastResult(
return CastResult(
newCont,
FunctionalData(tStack, 0, listOf(), false, harness.ravenmind),
ResolvedPatternType.EVALUATED,
listOf(),
ResolvedPatternType.EVALUATED,
HexEvalSounds.THOTH,
)
}

View file

@ -1,6 +1,6 @@
package at.petrak.hexcasting.api.spell.casting.eval
package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.casting.iota.Iota
/**
* A change to the data in a CastHarness after a pattern is drawn.

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.casting.eval
package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.utils.NBTBuilder
import at.petrak.hexcasting.api.utils.getList

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.iota;
package at.petrak.hexcasting.api.casting.iota;
import at.petrak.hexcasting.api.utils.HexUtils;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;

View file

@ -1,6 +1,6 @@
package at.petrak.hexcasting.api.spell.iota;
package at.petrak.hexcasting.api.casting.iota;
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation;
import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation;
import at.petrak.hexcasting.api.utils.HexUtils;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.ChatFormatting;

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.iota;
package at.petrak.hexcasting.api.casting.iota;
import at.petrak.hexcasting.api.utils.HexUtils;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.iota;
package at.petrak.hexcasting.api.casting.iota;
import at.petrak.hexcasting.api.utils.HexUtils;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.iota;
package at.petrak.hexcasting.api.casting.iota;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.ChatFormatting;

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.iota;
package at.petrak.hexcasting.api.casting.iota;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.nbt.Tag;

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.iota;
package at.petrak.hexcasting.api.casting.iota;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.nbt.Tag;

View file

@ -1,6 +1,6 @@
package at.petrak.hexcasting.api.spell.iota;
package at.petrak.hexcasting.api.casting.iota;
import at.petrak.hexcasting.api.spell.SpellList;
import at.petrak.hexcasting.api.casting.SpellList;
import at.petrak.hexcasting.api.utils.HexUtils;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.ChatFormatting;

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.iota;
package at.petrak.hexcasting.api.casting.iota;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.ChatFormatting;

View file

@ -1,6 +1,6 @@
package at.petrak.hexcasting.api.spell.iota;
package at.petrak.hexcasting.api.casting.iota;
import at.petrak.hexcasting.api.spell.math.HexPattern;
import at.petrak.hexcasting.api.casting.math.HexPattern;
import at.petrak.hexcasting.api.utils.HexUtils;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.ChatFormatting;

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.iota;
package at.petrak.hexcasting.api.casting.iota;
import at.petrak.hexcasting.api.utils.HexUtils;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.math
package at.petrak.hexcasting.api.casting.math
import at.petrak.hexcasting.api.HexAPI
import java.util.*

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.math
package at.petrak.hexcasting.api.casting.math
enum class HexAngle {
FORWARD, RIGHT, RIGHT_BACK, BACK, LEFT_BACK, LEFT;

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.math
package at.petrak.hexcasting.api.casting.math
import kotlin.math.abs
import kotlin.math.max

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.math
package at.petrak.hexcasting.api.casting.math
import at.petrak.hexcasting.api.utils.getSafe

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.api.spell.math
package at.petrak.hexcasting.api.casting.math
import at.petrak.hexcasting.api.utils.NBTBuilder
import at.petrak.hexcasting.api.utils.coordToPx
@ -129,10 +129,8 @@ data class HexPattern(public val startDir: HexDir, public val angles: MutableLis
@JvmStatic
fun isPattern(tag: CompoundTag): Boolean {
return tag.contains(TAG_START_DIR, Tag.TAG_ANY_NUMERIC.toInt()) && tag.contains(
TAG_ANGLES,
Tag.TAG_BYTE_ARRAY.toInt()
)
return tag.contains(TAG_START_DIR, Tag.TAG_ANY_NUMERIC.toInt())
&& tag.contains(TAG_ANGLES, Tag.TAG_BYTE_ARRAY.toInt())
}
@JvmStatic

View file

@ -1,13 +1,12 @@
package at.petrak.hexcasting.api.spell.mishaps
package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.math.HexPattern
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.mod.HexItemTags
import at.petrak.hexcasting.api.spell.Action
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.casting.ResolvedPatternType
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.mod.HexTags
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import at.petrak.hexcasting.api.utils.lightPurple
import at.petrak.hexcasting.common.lib.HexItems
@ -26,22 +25,33 @@ import net.minecraft.world.phys.Vec3
abstract class Mishap : Throwable() {
/** Mishaps spray half-red, half-this-color. */
abstract fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer
abstract fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer
open fun particleSpray(ctx: CastingContext): ParticleSpray {
open fun particleSpray(ctx: CastingEnvironment): ParticleSpray {
return ParticleSpray(ctx.position.add(0.0, 0.2, 0.0), Vec3(0.0, 2.0, 0.0), 0.2, Math.PI / 4, 40)
}
open fun resolutionType(ctx: CastingContext): ResolvedPatternType = ResolvedPatternType.ERRORED
open fun resolutionType(ctx: CastingEnvironment): ResolvedPatternType = ResolvedPatternType.ERRORED
/**
* Execute the actual effect, not any sfx.
*
* You can also mess up the stack with this.
*/
abstract fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>)
abstract fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>)
abstract fun errorMessage(ctx: CastingContext, errorCtx: Context): Component
abstract protected fun errorMessage(ctx: CastingEnvironment, errorCtx: Context): Component
/**
* Every error message should be prefixed with the name of the action...
*/
public fun errorMessageWithName(ctx: CastingEnvironment, errorCtx: Context): Component {
return if (errorCtx.name != null) {
"hexcasting.mishap".asTranslatedComponent(errorCtx.name, this.errorMessage(ctx, errorCtx))
} else {
this.errorMessage(ctx, errorCtx)
}
}
// Useful helper functions
@ -54,14 +64,14 @@ abstract class Mishap : Throwable() {
protected fun error(stub: String, vararg args: Any): Component =
"hexcasting.mishap.$stub".asTranslatedComponent(*args)
protected fun actionName(action: Action?): Component =
action?.displayName ?: "hexcasting.spell.null".asTranslatedComponent.lightPurple
protected fun actionName(name: Component?): Component =
name ?: "hexcasting.spell.null".asTranslatedComponent.lightPurple
protected fun yeetHeldItemsTowards(ctx: CastingContext, targetPos: Vec3) {
protected fun yeetHeldItemsTowards(ctx: CastingEnvironment, targetPos: Vec3) {
// Knock the player's items out of their hands
val items = mutableListOf<ItemStack>()
for (hand in InteractionHand.values()) {
if (hand != ctx.castingHand || ctx.caster.getItemInHand(hand).`is`(HexItemTags.STAVES)) {
if (hand != ctx.castingHand || ctx.caster.getItemInHand(hand).`is`(HexTags.Items.STAVES)) {
items.add(ctx.caster.getItemInHand(hand).copy())
ctx.caster.setItemInHand(hand, ItemStack.EMPTY)
}
@ -74,7 +84,7 @@ abstract class Mishap : Throwable() {
}
}
protected fun yeetHeldItem(ctx: CastingContext, hand: InteractionHand) {
protected fun yeetHeldItem(ctx: CastingEnvironment, hand: InteractionHand) {
val item = ctx.caster.getItemInHand(hand).copy()
if (hand == ctx.castingHand && IXplatAbstractions.INSTANCE.findHexHolder(item) != null)
return
@ -84,7 +94,7 @@ abstract class Mishap : Throwable() {
yeetItem(item, ctx, delta)
}
protected fun yeetItem(stack: ItemStack, ctx: CastingContext, delta: Vec3) {
protected fun yeetItem(stack: ItemStack, ctx: CastingEnvironment, delta: Vec3) {
val entity = ItemEntity(
ctx.world,
ctx.position.x, ctx.position.y, ctx.position.z,
@ -97,11 +107,11 @@ abstract class Mishap : Throwable() {
ctx.world.addWithUUID(entity)
}
protected fun blockAtPos(ctx: CastingContext, pos: BlockPos): Component {
protected fun blockAtPos(ctx: CastingEnvironment, pos: BlockPos): Component {
return ctx.world.getBlockState(pos).block.name
}
data class Context(val pattern: HexPattern, val action: Action?)
data class Context(val pattern: HexPattern, val name: Component?)
companion object {
fun trulyHurt(entity: LivingEntity, source: DamageSource, amount: Float) {

View file

@ -0,0 +1,25 @@
package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.misc.HexDamageSources
import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.iota.Iota
import net.minecraft.world.entity.Mob
import net.minecraft.world.item.DyeColor
class MishapAlreadyBrainswept(val mob: Mob) : Mishap() {
override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.GREEN)
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
mob.hurt(HexDamageSources.overcastDamageFrom(ctx.caster), mob.health)
}
override fun particleSpray(ctx: CastingEnvironment) =
ParticleSpray.burst(mob.eyePosition, 1.0)
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =
error("already_brainswept")
}

View file

@ -1,9 +1,9 @@
package at.petrak.hexcasting.api.spell.mishaps
package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
@ -12,17 +12,17 @@ import net.minecraft.world.level.Explosion
import net.minecraft.world.phys.Vec3
class MishapBadBlock(val pos: BlockPos, val expected: Component) : Mishap() {
override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer =
override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.LIME)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) {
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
ctx.world.explode(null, pos.x + 0.5, pos.y + 0.5, pos.z + 0.5, 0.25f, Explosion.BlockInteraction.NONE)
}
override fun particleSpray(ctx: CastingContext) =
override fun particleSpray(ctx: CastingEnvironment) =
ParticleSpray.burst(Vec3.atCenterOf(pos), 1.0)
override fun errorMessage(ctx: CastingContext, errorCtx: Context) =
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =
error("bad_block", expected, this.pos.toShortString(), blockAtPos(ctx, this.pos))
companion object {

View file

@ -0,0 +1,27 @@
package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.misc.HexDamageSources
import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.iota.Iota
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.Mob
import net.minecraft.world.item.DyeColor
import net.minecraft.world.phys.Vec3
class MishapBadBrainsweep(val mob: Mob, val pos: BlockPos) : Mishap() {
override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.GREEN)
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
trulyHurt(mob, HexDamageSources.overcastDamageFrom(ctx.caster), mob.health)
}
override fun particleSpray(ctx: CastingEnvironment): ParticleSpray {
return ParticleSpray.burst(Vec3.atCenterOf(pos), 1.0)
}
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =
error("bad_brainsweep", blockAtPos(ctx, this.pos))
}

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.api.spell.mishaps
package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.utils.aqua
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import net.minecraft.network.chat.Component
@ -11,15 +11,15 @@ import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.item.DyeColor
class MishapBadEntity(val entity: Entity, val wanted: Component) : Mishap() {
override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer =
override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.BROWN)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) {
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
yeetHeldItemsTowards(ctx, entity.position())
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context) =
error("bad_entity", actionName(errorCtx.action), wanted, entity.displayName.plainCopy().aqua)
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =
error("bad_entity", wanted, entity.displayName.plainCopy().aqua)
companion object {
@JvmStatic

View file

@ -1,25 +1,25 @@
package at.petrak.hexcasting.api.spell.mishaps
package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.item.DyeColor
class MishapBadItem(val item: ItemEntity, val wanted: Component) : Mishap() {
override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer =
override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.BROWN)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) {
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
item.deltaMovement = item.deltaMovement.add((Math.random() - 0.5) * 0.05, 0.75, (Math.random() - 0.5) * 0.05)
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context) = if (item.item.isEmpty)
error("no_item", actionName(errorCtx.action), wanted)
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = if (item.item.isEmpty)
error("no_item", wanted)
else
error("bad_item", actionName(errorCtx.action), wanted, item.item.count, item.item.displayName)
error("bad_item", wanted, item.item.count, item.item.displayName)
companion object {
@JvmStatic

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.api.spell.mishaps
package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import net.minecraft.network.chat.Component
import net.minecraft.world.InteractionHand
@ -10,17 +10,17 @@ import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.ItemStack
class MishapBadOffhandItem(val item: ItemStack, val hand: InteractionHand, val wanted: Component) : Mishap() {
override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer =
override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.BROWN)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) {
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
yeetHeldItem(ctx, hand)
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context) = if (item.isEmpty)
error("no_item.offhand", actionName(errorCtx.action), wanted)
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = if (item.isEmpty)
error("no_item.offhand", wanted)
else
error("bad_item.offhand", actionName(errorCtx.action), wanted, item.count, item.displayName)
error("bad_item.offhand", wanted, item.count, item.displayName)
companion object {
@JvmStatic

View file

@ -0,0 +1,21 @@
package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.misc.FrozenColorizer
import net.minecraft.world.item.DyeColor
class MishapDisallowedSpell(val type: String = "disallowed") : Mishap() {
override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.BLACK)
override fun resolutionType(ctx: CastingEnvironment) = ResolvedPatternType.INVALID
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
// NO-OP
}
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =
error(type)
}

View file

@ -1,12 +1,12 @@
package at.petrak.hexcasting.api.spell.mishaps
package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.misc.HexDamageSources
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.DoubleIota
import at.petrak.hexcasting.api.spell.iota.GarbageIota
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.iota.Vec3Iota
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.iota.DoubleIota
import at.petrak.hexcasting.api.casting.iota.GarbageIota
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.Vec3Iota
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import net.minecraft.network.chat.Component
import net.minecraft.world.item.DyeColor
@ -14,15 +14,15 @@ import net.minecraft.world.phys.Vec3
class MishapDivideByZero(val operand1: Component, val operand2: Component, val suffix: String = "divide") : Mishap() {
override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer =
override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.RED)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) {
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
stack.add(GarbageIota())
trulyHurt(ctx.caster, HexDamageSources.OVERCAST, ctx.caster.health / 2)
}
override fun errorMessage(ctx: CastingContext, errorCtx: Context) =
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =
error("divide_by_zero.$suffix", operand1, operand2)
companion object {

View file

@ -0,0 +1,21 @@
package at.petrak.hexcasting.api.casting.mishaps
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.misc.FrozenColorizer
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.Entity
import net.minecraft.world.item.DyeColor
class MishapEntityTooFarAway(val entity: Entity) : Mishap() {
override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.PINK)
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
// Knock the player's items out of their hands
yeetHeldItemsTowards(ctx, entity.position())
}
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context): Component =
error("entity_too_far", entity.displayName)
}

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