forked from mirrors/cobblemon
Compare commits
475
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b79e73928a | ||
|
|
c89ea759a6 | ||
|
|
c6479525f9 | ||
|
|
2a7dababab | ||
|
|
7ec6e61d4a | ||
|
|
7735af5c11 | ||
|
|
18d25dcf04 | ||
|
|
e259dc18a2 | ||
|
|
7439436e93 | ||
|
|
1c51d5ca98 | ||
|
|
d94952347f | ||
|
|
7fe6141640 | ||
|
|
4b1653ca6c | ||
|
|
068b55be7b | ||
|
|
3f6bd52d43 | ||
|
|
4ca3f25ab2 | ||
|
|
70e81f1cbe | ||
|
|
df8abf4ddb | ||
|
|
26dd0b9d42 | ||
|
|
2f16ba5470 | ||
|
|
cbdfbc9745 | ||
|
|
ac210e027b | ||
|
|
1fc91a794f | ||
|
|
f78b289171 | ||
|
|
c46461c843 | ||
|
|
386a897295 | ||
|
|
8328f741d8 | ||
|
|
2b19943416 | ||
|
|
550b99be36 | ||
|
|
bfbee7b1d7 | ||
|
|
f5d71390dd | ||
|
|
6ff5d3df06 | ||
|
|
988766894a | ||
|
|
34805ea496 | ||
|
|
b670d44e21 | ||
|
|
159905eb3b | ||
|
|
c10213480b | ||
|
|
3d5a365a6e | ||
|
|
4b64b4307a | ||
|
|
382f741db8 | ||
|
|
6d62d911d6 | ||
|
|
a1d40084c5 | ||
|
|
8b1b63e110 | ||
|
|
baf3cd5f30 | ||
|
|
2327f1aa2c | ||
|
|
62036c0ac6 | ||
|
|
9e2e95e287 | ||
|
|
2db494ff5e | ||
|
|
7fe1415551 | ||
|
|
ca4d4ed3be | ||
|
|
700227be41 | ||
|
|
985a4f65dc | ||
|
|
e117100e34 | ||
|
|
93ea13fa4d | ||
|
|
6694680c50 | ||
|
|
cd14881d17 | ||
|
|
1393cc3ef3 | ||
|
|
23ebd0573a | ||
|
|
6447c2e2eb | ||
|
|
8cafce0a4a | ||
|
|
039a18a2bf | ||
|
|
de271f81b1 | ||
|
|
feb78c5c58 | ||
|
|
71736341f0 | ||
|
|
bb6e5607f1 | ||
|
|
4603f5ac7a | ||
|
|
c683294227 | ||
|
|
f29c2343e6 | ||
|
|
3a2da5a87d | ||
|
|
27d1de8e4e | ||
|
|
e5d052a6bf | ||
|
|
1c13ab24e8 | ||
|
|
380cf0ea71 | ||
|
|
8ded7334bb | ||
|
|
8af62f800b | ||
|
|
a50da47a8e | ||
|
|
f690781b0d | ||
|
|
6a7fc67ae1 | ||
|
|
0ac34bf1a4 | ||
|
|
9716ea0806 | ||
|
|
ffea94f3b2 | ||
|
|
3061ba69e2 | ||
|
|
741e38d606 | ||
|
|
7265ab57b9 | ||
|
|
02f2c072c9 | ||
|
|
27e3a95b06 | ||
|
|
4722defec2 | ||
|
|
c54849f415 | ||
|
|
d44e625e9d | ||
|
|
7b7acb97d1 | ||
|
|
53af92f254 | ||
|
|
91bce4b153 | ||
|
|
511130d353 | ||
|
|
476c3e54f1 | ||
|
|
6a74d5982a | ||
|
|
03905c77d2 | ||
|
|
4bfe8b808c | ||
|
|
8db943d2a9 | ||
|
|
fdff6ecfa5 | ||
|
|
2eb698969d | ||
|
|
bba60f0098 | ||
|
|
8ee2c95853 | ||
|
|
77db2ce17a | ||
|
|
da9558f5f9 | ||
|
|
5c65dffac8 | ||
|
|
b67b37c99e | ||
|
|
fbb7ee31c5 | ||
|
|
d3ef26976b | ||
|
|
dac01a3730 | ||
|
|
ddb05768e4 | ||
|
|
5374940d24 | ||
|
|
1fd6a660dd | ||
|
|
fd45934775 | ||
|
|
38de3c6267 | ||
|
|
5e0ffd8bd3 | ||
|
|
b4b315360d | ||
|
|
a44c70648b | ||
|
|
c41b0cdca2 | ||
|
|
88f743ee48 | ||
|
|
15b9afacf8 | ||
|
|
0ea4641536 | ||
|
|
babcf7430b | ||
|
|
3439ca2011 | ||
|
|
ff5ea6fa21 | ||
|
|
6539f3dea1 | ||
|
|
4820d78416 | ||
|
|
2f417e953c | ||
|
|
8fde0ed4f6 | ||
|
|
6715874a8f | ||
|
|
31f88a1f68 | ||
|
|
1677598ec0 | ||
|
|
fcde1eb171 | ||
|
|
a30a5644df | ||
|
|
a5672a38b9 | ||
|
|
3b14ea319b | ||
|
|
57e2765f90 | ||
|
|
a090c90831 | ||
|
|
f80aa2769a | ||
|
|
20aa4d43b8 | ||
|
|
9bec3e088f | ||
|
|
5b4dbe1957 | ||
|
|
48f248d481 | ||
|
|
d726c4d0ed | ||
|
|
5dcc9ba46d | ||
|
|
f8e4ea70df | ||
|
|
5dc1c749f3 | ||
|
|
3accfa29b7 | ||
|
|
1af1569f63 | ||
|
|
c9c421ba2a | ||
|
|
2436a8ddcc | ||
|
|
3364944c26 | ||
|
|
9e6a6eabc7 | ||
|
|
78def7318e | ||
|
|
fdf062bd4c | ||
|
|
ef5a682adb | ||
|
|
dbd2f5d340 | ||
|
|
86bf413f00 | ||
|
|
f76d28d29e | ||
|
|
9c70aad64d | ||
|
|
25de1ad180 | ||
|
|
f967d1ec11 | ||
|
|
efd0497de1 | ||
|
|
f13e7d03a1 | ||
|
|
4a025ac65e | ||
|
|
8a0c98c9ab | ||
|
|
36c5fe2419 | ||
|
|
0c79d102cf | ||
|
|
b14b25ae19 | ||
|
|
b30c0a4a9a | ||
|
|
c99b26a44b | ||
|
|
bd8f644b9a | ||
|
|
7c84cdb05d | ||
|
|
b19bc1e4c7 | ||
|
|
bc5ffda1a5 | ||
|
|
491d6c9fd6 | ||
|
|
ccc6ad77a5 | ||
|
|
00fd9d1278 | ||
|
|
01464f8b71 | ||
|
|
d91fe0b876 | ||
|
|
0293c0e811 | ||
|
|
125975e25f | ||
|
|
c7223ae898 | ||
|
|
baf766298a | ||
|
|
83580e7e8b | ||
|
|
38f5c12dce | ||
|
|
e6a9a27692 | ||
|
|
7ff413c401 | ||
|
|
90335ccb2d | ||
|
|
603f99e5f3 | ||
|
|
1b53a127af | ||
|
|
9679929694 | ||
|
|
fd6fb5db47 | ||
|
|
a80ada8590 | ||
|
|
3f6faf7796 | ||
|
|
c4a4b9cb86 | ||
|
|
5af96e75eb | ||
|
|
d5efdeee68 | ||
|
|
023a01befd | ||
|
|
4912a89e6e | ||
|
|
f2e10d1b01 | ||
|
|
25eb197491 | ||
|
|
8de233b572 | ||
|
|
83972ca9e6 | ||
|
|
35e2190cae | ||
|
|
b966cd2db0 | ||
|
|
57f446260c | ||
|
|
3e492541cc | ||
|
|
cc2022ed59 | ||
|
|
298fdf45d5 | ||
|
|
4e9541d7f5 | ||
|
|
1dab5b8c7c | ||
|
|
2875e9efa9 | ||
|
|
2b42fff66b | ||
|
|
643a33a643 | ||
|
|
e348c48eff | ||
|
|
473f58cab9 | ||
|
|
d4cf44f8f0 | ||
|
|
a074ebbcce | ||
|
|
987b8619a3 | ||
|
|
87632941e8 | ||
|
|
6578ed55e3 | ||
|
|
041acab7ca | ||
|
|
b3de7d1c1a | ||
|
|
afcb2dd77c | ||
|
|
a7bd6d2bf4 | ||
|
|
b096cb60a3 | ||
|
|
f567ceadd8 | ||
|
|
5de92f78c6 | ||
|
|
a2402f78e7 | ||
|
|
1ad6d63137 | ||
|
|
39d417c651 | ||
|
|
ce1bf9f4f2 | ||
|
|
a6136906f8 | ||
|
|
37a99b528e | ||
|
|
048b237302 | ||
|
|
131773f9c8 | ||
|
|
22e55b7e77 | ||
|
|
6c288f9cc8 | ||
|
|
b5e86a9460 | ||
|
|
f199e7c1c0 | ||
|
|
4161d96707 | ||
|
|
59927dd701 | ||
|
|
220d8ddc0f | ||
|
|
0dd143e67e | ||
|
|
7f1c0c3d4c | ||
|
|
d83eb62821 | ||
|
|
a716fda023 | ||
|
|
d14aad787c | ||
|
|
2eb7b60dd1 | ||
|
|
bc4699e354 | ||
|
|
a4f0bf9d2f | ||
|
|
f46c748e9f | ||
|
|
065479c58c | ||
|
|
eee3d46a2d | ||
|
|
d79ffc631b | ||
|
|
d7b43fcbfc | ||
|
|
c82e011f73 | ||
|
|
bf1b996962 | ||
|
|
fc46cdcda0 | ||
|
|
4e7b029afb | ||
|
|
5430f02770 | ||
|
|
6a51abe3ee | ||
|
|
008652b442 | ||
|
|
c1e088eb33 | ||
|
|
1669a2f428 | ||
|
|
2ba63f4641 | ||
|
|
41b9e9001d | ||
|
|
679920b786 | ||
|
|
f058d6e635 | ||
|
|
f9377b7489 | ||
|
|
9270119675 | ||
|
|
e59b5094ad | ||
|
|
c8ec4e6f1f | ||
|
|
a2fef9f1be | ||
|
|
3d4df2c098 | ||
|
|
7557cab03d | ||
|
|
0058906022 | ||
|
|
f1018b1da9 | ||
|
|
7cd1870f23 | ||
|
|
cbcc6abe40 | ||
|
|
5af4e3bddb | ||
|
|
64c9d47b0f | ||
|
|
1f519cae50 | ||
|
|
c0d2803f61 | ||
|
|
e249d5238f | ||
|
|
e32e505e95 | ||
|
|
7642a84108 | ||
|
|
b6e20d69cc | ||
|
|
9d04e20a30 | ||
|
|
d2624813f7 | ||
|
|
a2789e70ed | ||
|
|
f6f607904e | ||
|
|
22ea0296c0 | ||
|
|
24ae2f5324 | ||
|
|
9284497cec | ||
|
|
36cb12952a | ||
|
|
2700dc7f39 | ||
|
|
14d2a76211 | ||
|
|
7669000962 | ||
|
|
716d1b848e | ||
|
|
4878fc517d | ||
|
|
4d9d543110 | ||
|
|
c9d27d46b6 | ||
|
|
718a9b922b | ||
|
|
b68756378c | ||
|
|
1ff1880951 | ||
|
|
fea2d32de8 | ||
|
|
e3e6d4452c | ||
|
|
f687e8e658 | ||
|
|
e2a152aeb3 | ||
|
|
3e21226b27 | ||
|
|
c46c5b806c | ||
|
|
3c37d93046 | ||
|
|
2413981f6f | ||
|
|
4ac244003a | ||
|
|
9ac92a084f | ||
|
|
aacbcb1f28 | ||
|
|
39ff7e418c | ||
|
|
58498a091d | ||
|
|
a806f77aff | ||
|
|
60ae9e3a55 | ||
|
|
4bfe147730 | ||
|
|
8912911800 | ||
|
|
963614f5fa | ||
|
|
7fdb70e3c3 | ||
|
|
62ecfaf54a | ||
|
|
6684177236 | ||
|
|
deca5cf55b | ||
|
|
37e8f0eab6 | ||
|
|
a6d17659f8 | ||
|
|
05edafa5c4 | ||
|
|
997a6de23b | ||
|
|
cea600617e | ||
|
|
376e5ac906 | ||
|
|
c948b6d885 | ||
|
|
7b2790de50 | ||
|
|
7f2bb84c85 | ||
|
|
0f75797759 | ||
|
|
5508980384 | ||
|
|
e39dee01e5 | ||
|
|
a81412e176 | ||
|
|
09f9dd91aa | ||
|
|
2efc3c72ac | ||
|
|
a92fb03093 | ||
|
|
ad5847983f | ||
|
|
bb25300513 | ||
|
|
de33804eb4 | ||
|
|
de042f71dd | ||
|
|
5a1e85bbf4 | ||
|
|
3489e0df74 | ||
|
|
afe8eec343 | ||
|
|
331e1371d4 | ||
|
|
bdd57ba1a4 | ||
|
|
c194aefce5 | ||
|
|
f4798c8783 | ||
|
|
2178a5f10e | ||
|
|
bc145a56d5 | ||
|
|
670e7e9ca1 | ||
|
|
b225283dcc | ||
|
|
476ef3bb2f | ||
|
|
460050289b | ||
|
|
01fd4dcc68 | ||
|
|
0392eb3b7e | ||
|
|
493f423a2f | ||
|
|
cbcfa1bbfb | ||
|
|
17a3ff15db | ||
|
|
9c14cccc98 | ||
|
|
850cfbe755 | ||
|
|
28afa6a9e8 | ||
|
|
7a76d95ce7 | ||
|
|
54707d0618 | ||
|
|
307c400e28 | ||
|
|
5c9b3ab25d | ||
|
|
532e991fb2 | ||
|
|
b1bf817329 | ||
|
|
c091f90487 | ||
|
|
a49d4715ff | ||
|
|
652b15532e | ||
|
|
e4064897b0 | ||
|
|
f9ca8222da | ||
|
|
3ae349aea5 | ||
|
|
91864b13d0 | ||
|
|
67480a945f | ||
|
|
e6e811e6e6 | ||
|
|
4635c531b9 | ||
|
|
3bdfac9a46 | ||
|
|
2b7a71cb1c | ||
|
|
d47a500a0e | ||
|
|
13650f98f9 | ||
|
|
d3379557fd | ||
|
|
143c2683fe | ||
|
|
72d64d36e5 | ||
|
|
c0b52c38e3 | ||
|
|
adc8e9921a | ||
|
|
5e5473acae | ||
|
|
12a0ee309e | ||
|
|
33e6dbb4c1 | ||
|
|
824e37effd | ||
|
|
3509944f1a | ||
|
|
8a5489f805 | ||
|
|
922ee95fd2 | ||
|
|
482c57dd2e | ||
|
|
503c62d78d | ||
|
|
708d0ab6d3 | ||
|
|
19727542bd | ||
|
|
c4e6714a95 | ||
|
|
c116e612c6 | ||
|
|
215a055ce6 | ||
|
|
9c0b6b8d26 | ||
|
|
5c4462ee94 | ||
|
|
04edd6f9e2 | ||
|
|
52821cc051 | ||
|
|
b90f852a71 | ||
|
|
fdf7a9703a | ||
|
|
0029deb029 | ||
|
|
c6360e2a36 | ||
|
|
2e77c647b6 | ||
|
|
c3d3b19788 | ||
|
|
219cd61beb | ||
|
|
207e5a9142 | ||
|
|
bb41f28342 | ||
|
|
c721fb534d | ||
|
|
dba2622fd7 | ||
|
|
3b7d56ff45 | ||
|
|
da68675133 | ||
|
|
975cdf050f | ||
|
|
9aea5a7daf | ||
|
|
10402575fb | ||
|
|
0f82ade57c | ||
|
|
c5ee7ebe7a | ||
|
|
450b041118 | ||
|
|
770c349ac4 | ||
|
|
f76648b6f2 | ||
|
|
56e60667db | ||
|
|
c4a60951c5 | ||
|
|
f6ae10e1d9 | ||
|
|
814eee8125 | ||
|
|
2a9ff3bfbd | ||
|
|
8fe2042127 | ||
|
|
538ad883ab | ||
|
|
136cb86492 | ||
|
|
e4eb1251d1 | ||
|
|
83350cb0db | ||
|
|
778761dbee | ||
|
|
e9881b748a | ||
|
|
dabaeefa23 | ||
|
|
0e0bec2712 | ||
|
|
48fe160334 | ||
|
|
1bc83d9045 | ||
|
|
7d599e12d0 | ||
|
|
98775ffc1e | ||
|
|
bbeb3d45f0 | ||
|
|
8fd854f7f7 | ||
|
|
f449cf27c5 | ||
|
|
50c567d264 | ||
|
|
d4964e41d3 | ||
|
|
41b1c169c3 | ||
|
|
49e2001004 | ||
|
|
bf5fd5eed8 | ||
|
|
facead5f0b | ||
|
|
66393f9293 | ||
|
|
7b3b6146a1 | ||
|
|
e1452244c2 | ||
|
|
8913d3df11 | ||
|
|
3a55965704 | ||
|
|
5358414a0c | ||
|
|
d691373919 | ||
|
|
038f13e6fa | ||
|
|
dd288a3b0c | ||
|
|
b2070b53fb | ||
|
|
7fb873dc2c | ||
|
|
641f529de3 | ||
|
|
db9fb4fefa | ||
|
|
7112c74bf2 | ||
|
|
faa1906290 |
@@ -0,0 +1,12 @@
|
||||
### Additions
|
||||
- Added functionality for marks.
|
||||
- Added data for all marks and all title ribbons from Pokémon.
|
||||
- Added marks screen within the summary UI.
|
||||
- Added `/givemark <player> <partySlot> <mark>` command to give a mark to a Pokémon.
|
||||
- Added `/takemark <player> <partySlot> <mark>` command to remove a mark from a Pokémon.
|
||||
- Added `/giveallmarks <player> <partySlot>` command to give all available marks to a Pokémon.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- Added Flows for `bobber_spawn_pokemon_post`, `pokemon_entity_spawn`, and `fossil_revived`.
|
||||
- Added `marks` datapack folder.
|
||||
- Added MoLang functions `entity.is_in_rain`, `pokemon.add_marks(Mark...)`, `pokemon.add_potential_marks(Mark...)`, `pokemon.add_marks_with_chance(Mark...)`, `pokemon.apply_potential_marks`, and `world.is_snowing_at(x, y, z)`.
|
||||
@@ -6,6 +6,7 @@
|
||||
- Added filter functionality in PC UI, which supports `PokemonProperties` (e.g. `shiny=yes` shows all shiny Pokémon).
|
||||
- Added `/changewallpaper <player> <boxNumber> <wallpaper>` command to change a box wallpaper through commands.
|
||||
- Added `/renamebox <player> <boxNumber> <name>` command to rename a PC box through commands.
|
||||
- Added IVs and EVs stat displays in PC.
|
||||
|
||||
### Developer
|
||||
- Added `RenamePCBoxEvent.Pre` and `RenamePCBoxEvent.Post` events to prevent players from renaming a box or changing their input.
|
||||
|
||||
+131
@@ -2,6 +2,7 @@
|
||||
## [1.7.0 (Month xth, 2025)](#1-7-0)
|
||||
|
||||
### Additions
|
||||
- Added `/spectateBattle <player>` command to spectate battles without having to manually walk up to the target.
|
||||
- Added an in-game configuration screen, allowing all settings from `main.json` to be edited directly in-game.
|
||||
- Added `/cobblemonconfig reload` command to reload `main.json` configuration. **Note:** Some settings require a server restart to take effect; use this command cautiously.
|
||||
- Added `blacklisted_items_to_hold` and `whitelisted_items_to_hold` tags to allow for controlling which items players can give to their Pokémon. If the whitelist is empty, it will consider all item as allowed (unless they are in the blacklist).
|
||||
@@ -10,13 +11,128 @@
|
||||
- Added cosmetic item functionality for Pokémon. Certain cosmetic items can be given to applicable Pokémon via the interact menu.
|
||||
- Added the various log blocks as cosmetic items for Timburr and Komala.
|
||||
- Added `visibility/hidden`, `visibility/hat` and `visibility/face` tags to control where and how certain items are rendered.
|
||||
- Added Pokémon markings, toggleable within the summary.
|
||||
- Added `/boxcount` command to change PC boxes amount
|
||||
- Added cosmetics for Gurdurr, Conkeldurr, Squirtle Line, Sneasler, Sandile line, Treecko line, Braixen, Delphox, and Dragonite.
|
||||
- Added cosmetics for Gurdurr, Conkeldurr, Squirtle Line, Sneasler, Sandle line, Treecko line, Braixen, Delphox, and Dragonite.
|
||||
- Added `/transformmodelpart (position|rotation|scale) <modelPart> <transform: x y z>` command that can add transformations to a pokemon's model part.
|
||||
- The player executing the command must be facing the target pokemon entity. Transformations are not persistent and will revert when resources are reloaded.
|
||||
- Added lang keys for all moves and abilities up to Generation 9.
|
||||
- Fixed Moon Ball moon phase logic to actually work correctly
|
||||
- Added `translucent_cull` boolean option into resolver's layer to allow for translucent textures with culling
|
||||
- Added [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) support for items held by Pokémon.
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
#### Gen 2
|
||||
- Dunsparce
|
||||
|
||||
#### Gen 3
|
||||
- Spoink
|
||||
- Grumpig
|
||||
- Snorunt
|
||||
- Glalie
|
||||
|
||||
#### Gen 4
|
||||
- Bronzor
|
||||
- Bronzong
|
||||
- Croagunk
|
||||
- Froslass
|
||||
|
||||
#### Gen 5
|
||||
- Pansage
|
||||
- Simisage
|
||||
- Pansear
|
||||
- Simisear
|
||||
- Panpour
|
||||
- Simipour
|
||||
- Munna
|
||||
- Musharna
|
||||
- Blitzle
|
||||
- Zebstrika
|
||||
- Trubbish
|
||||
- Garbodor
|
||||
|
||||
#### Gen 6
|
||||
- Noibat
|
||||
- Noivern
|
||||
|
||||
#### Gen 7
|
||||
- Drampa
|
||||
|
||||
#### Gen 8
|
||||
- Silicobra
|
||||
- Sandaconda
|
||||
|
||||
#### Gen 9
|
||||
- Smoliv
|
||||
- Dolliv
|
||||
- Arboliva
|
||||
- Orthworm
|
||||
- Dudunsparce
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Garchomp
|
||||
- Tropius
|
||||
- Torpius
|
||||
- Nosepass
|
||||
- Probopass
|
||||
- Sneasler
|
||||
- Braixen
|
||||
- Delphox
|
||||
- Cinderace
|
||||
- Kangaskhan
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Gyarados
|
||||
- Dragonite
|
||||
- Eevee
|
||||
- Vaporeon
|
||||
- Jolteon
|
||||
- Flareon
|
||||
- Espeon
|
||||
- Umbreon
|
||||
- Leafeon
|
||||
- Glaceon
|
||||
- Sylveon
|
||||
- Treecko
|
||||
- Grovyle
|
||||
- Sceptile
|
||||
- Honchkrow
|
||||
- Garchomp
|
||||
- Pidgeot
|
||||
- Nosepass
|
||||
- Probopass
|
||||
- Kangaskhan
|
||||
- Cinderace
|
||||
- Magnezone
|
||||
- Metagross
|
||||
- Added Syrupy Apples.
|
||||
|
||||
### Changes
|
||||
- Renamed `chargeGainedPerTick` config to `secondsToChargeHealingMachine`.
|
||||
- Made Blocks of Gold count as Big Nuggets when held by a Pokémon (for Fling functionality)
|
||||
- Players can now eat Sweet and Tart Apples, Whipped Dreams, and the Alcremie Sweets.
|
||||
- Updated Sweet and Tart Apple sprites
|
||||
- Updated the following recipes: Air Balloon, Assault Vest, Binding Band, Black Belt, Blunder Policy, Choice Band, Choice Scarf, Cleanse Tag, Covert Cloak, Destiny Knot, Eject Button, Expert Belt, Focus Band, Focus Sash, Magnet, Metronome, Muscle Band, Power Anklet, Power Band, Power Belt, Power Bracer, Power Lens, Power Weight, Protective Pads, Protein, Punching Glove, Reaper Cloth, Rocky Helmet, Room Service, Sachet, Safety Goggles, Silk Scarf, Spell Tag, Utility Umbrella, Weakness Policy, Zinc
|
||||
- Added alternate ingredient options to the following recipes: Cell Battery, Charcoal Stick, Dragon Fang, Miracle Seed, Mystic Water, Never Melt Ice, Twisted Spoon, Damp Rock, Heat Rock, Icy Rock, Smooth Rock
|
||||
- Grouped together some recipes within the Recipe Book. Groups include: the seven basic Poké Balls, the seven basic Ancient Poké Balls, Gilded Chests, Pokedexes, and the Weather Rocks.
|
||||
- Updated some item tags to better integrate behaviours between Cobblemon, Vanilla Minecraft, and other mods
|
||||
- Removed Cooked Meat, Raw Meat, Protein Ingredients, and Zinc Ingredients, the first two are now using `c` namespace tags, the latter have better integrated use of tags within their recipes which removes need for custom tags.
|
||||
- Added our seeds tag into `#c:seeds`, which is now made use of for the Miracle Seed recipe.
|
||||
- Tweaked the Natural Materials Vanilla file to fit with the changes to tags
|
||||
- Substantially optimised spawning checks mainly by front-loading biome filtering.
|
||||
- When using the `cobblemon` or `generation_9` capture calculators a critical capture with a single shake will always play for successful captures when you've already registered the Pokémon as caught in your Pokédex.
|
||||
- Improved the performance of saving Pokédex and player data.
|
||||
- Pokémon hitbox now scales with entity attribute `generic.scale`.
|
||||
- Removed Shulker aspect and replaced it with cosmetic_item-shulker_shell.
|
||||
- Shulker shell Forretress is now a cosmetic rather than a special evo and thus all shulker Forretress will revert back to normal until a shulker shell is put in their cosmetic slot.
|
||||
- Updated `doPokemonSpawning` gamerule to support per-dimension configurations.
|
||||
- The Pokedex now displays a form name of a "normal" Pokémon for when the base form is still a named form.
|
||||
- Improved the zoom functionality of the Pokédex Scanner by giving the levels logarithmic scaling.
|
||||
- Added a subtle rotation effect to the Pokédex Scanner's wheel when zooming.
|
||||
- Improved parity with vanilla mobs' drop behavior; loot and XP drop on death instead of after the entire death sequence finishes.
|
||||
- Quirk animations no longer play in the battle GUI since they were pretty distracting.
|
||||
|
||||
### Fixes
|
||||
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
|
||||
@@ -39,11 +155,15 @@
|
||||
- Fixed field name in evolution requirements for Spewpa Pokeball.
|
||||
- Fixed LevelUpCriterion logic to correctly check that the Pokémon is a preEvo.
|
||||
- Fixed `hide_additional_tooltip` vanilla flag not properly hiding tooltips on pokerod and bait items
|
||||
- Removed a number of scenarios in which a Pokémon battle may send out a Pokémon into collision geometry.
|
||||
- Fixed NPCs using Pokémon outside of their pool when a Pokémon name had a typo.
|
||||
- Fixed an issue with datapacked species features not being applied properly when relogging.
|
||||
- Fixed Pokémon marked as silent still playing shiny sounds and effects.
|
||||
- Fixed an issue with newer versions of Fabric API where underground Pokémon were spawning in The End.
|
||||
- Fixed spawning not working well when you're at high points surrounded by lower altitude spawning areas, such as flying.
|
||||
- Fixed certain Pokémon with forms not having appropriate stock Pokédex entries.
|
||||
- Fixed issue with Pokédex Scanner that caused the open/close overlay to have the wrong opacity values
|
||||
- Fixed dragon's breath not being usable on the restoration tank when it should be
|
||||
|
||||
### Developer
|
||||
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
|
||||
@@ -61,6 +181,7 @@
|
||||
- Updated NPCEntity beam positioning to properly account for the baseScale property.
|
||||
- Updated NPCEntity pokeball throw positioning to properly account for the baseScale property.
|
||||
- Fixed `[Pokemon].copyFrom` error causing forms, IVs, and EVs to not be applied properly when using `[Pokemon].loadFromJSON` or `[Pokemon].loadFromNBT`
|
||||
- Added new item class, `WearableItem`. Instances of this class should have a corresponding 3D model. These models render when the items display context is `HEAD`.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- The following usages for item predicates can now use item conditions like advancements do, you can learn about them in the [Minecraft wiki](https://minecraft.wiki/w/Advancement_definition#minecraft:filled_bucket)
|
||||
@@ -71,6 +192,15 @@
|
||||
- Added `interpolate` boolean property to animated textures to allow gradual colour changes between frames.
|
||||
- Fixed species additions not being capable of changing implemented status.
|
||||
- Added support for action effects that are triggered by `|-activate|` Showdown instructions. `activate_{effect_id}` is the syntax.
|
||||
- Added MoLang functions for rendering items `render_item(item_id, locator_name)` and `clear_items()`.
|
||||
- Fixed location spawn filter components causing crashes
|
||||
- Added `pokemon` as an available MoLang function for the `battleActor` functions.
|
||||
- Added `spawn_pokemon` as an available MoLang function for the `worldHolder` functions.
|
||||
- Added `attempt_wild_battle` as an available MoLang function.
|
||||
- Added `pokemon` as an available Molang function for the `battleActor` functions.
|
||||
- Fixed `heldItem` property inside spawn files not working and causing crashes
|
||||
- Fixed `spawn_bedrock_particles` MoLang causing crashes when used in a server environment
|
||||
- The Pokédex form lang key definition now follows `cobblemon.ui.pokedex.info.form.{species}-{formname}` instead of `cobblemon.ui.pokedex.info.form.{formname}`.
|
||||
|
||||
## [1.6.1 (January 26th, 2025)](#1-6-1)
|
||||
|
||||
@@ -176,6 +306,7 @@
|
||||
- Geodude
|
||||
- Graveler
|
||||
- Golem
|
||||
- Magnezone
|
||||
|
||||
### Cry updates for the following Pokémon
|
||||
- Sceptile
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common;
|
||||
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface OrientationControllable {
|
||||
OrientationController getOrientationController();
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface Rollable {
|
||||
|
||||
// From Minecraft's Camera
|
||||
Vector3f FORWARDS = new Vector3f(0.0F, 0.0F, -1.0F);
|
||||
Vector3f UP = new Vector3f(0.0F, 1.0F, 0.0F);
|
||||
Vector3f LEFT = new Vector3f(-1.0F, 0.0F, 0.0F);
|
||||
|
||||
@Nullable Matrix3f getOrientation();
|
||||
|
||||
Rollable updateOrientation(Function<Matrix3f, Matrix3f> update);
|
||||
|
||||
/**
|
||||
* @return The forward vector (0, 0, -1) after the rotation matrix is applied.
|
||||
*/
|
||||
default Vector3f getForwardVector() {
|
||||
if (getOrientation() == null) return new Vector3f(FORWARDS);
|
||||
return getOrientation().transform(FORWARDS, new Vector3f());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The left vector (-1, 0, 0) after the rotation matrix is applied.
|
||||
*/
|
||||
default Vector3f getLeftVector() {
|
||||
if (getOrientation() == null) return new Vector3f(LEFT);
|
||||
return getOrientation().transform(LEFT, new Vector3f());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The up vector (0, 1, 0) after the rotation matrix is applied.
|
||||
*/
|
||||
default Vector3f getUpVector() {
|
||||
if (getOrientation() == null) return new Vector3f(UP);
|
||||
return getOrientation().transform(UP, new Vector3f());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param yaw change in degrees
|
||||
* @return The Rollable object this method was called on
|
||||
*/
|
||||
|
||||
default Rollable rotateYaw(float yaw) {
|
||||
return updateOrientation(prev -> prev.rotateY((float) Math.toRadians(-yaw)));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pitch change in degrees
|
||||
* @return The Rollable object this method was called on
|
||||
*/
|
||||
|
||||
default Rollable rotatePitch(float pitch) {
|
||||
return updateOrientation(prev -> prev.rotateX((float) Math.toRadians(-pitch)));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param roll change in degrees
|
||||
* @return The Rollable object this method was called on
|
||||
*/
|
||||
default Rollable rotateRoll(float roll) {
|
||||
return updateOrientation(prev -> prev.rotateZ((float) Math.toRadians(-roll)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Order matters when rotating an object. If you need a different order, individually call rotateYaw, rotatePitch, and rotateRoll
|
||||
*
|
||||
* @param yaw change in degrees
|
||||
* @param pitch change in degrees
|
||||
* @param roll change in degrees
|
||||
* @return The Rollable object this method was called on
|
||||
*/
|
||||
default Rollable rotate(float yaw, float pitch, float roll) {
|
||||
return rotateYaw(yaw).rotatePitch(pitch).rotateRoll(roll);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The pitch angle in degrees as a float.
|
||||
* Value is between [-180, 180] with 0 being South, 90 being West, 180/-180 being North, and -90 being East
|
||||
*/
|
||||
default float getYaw() {
|
||||
return (float) Mth.wrapDegrees(-Math.toDegrees(FORWARDS.angleSigned(getForwardVector(), UP)) + 180);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The yaw angle in degrees as a float.
|
||||
* Value is between [-90, 90] with 0 being straight forward, 90 being straight down, and -90 being straight up
|
||||
*/
|
||||
default float getPitch() {
|
||||
return (float) Mth.wrapDegrees(-Math.toDegrees(Math.asin(getForwardVector().y)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The roll angle in degrees as a float.
|
||||
* Value is between [-180, 180] with 0 being no roll (normal), 90 being 90 degrees CW, 180/-180 being 180 degrees CW/CCW, and -90 being 90 degrees CCW
|
||||
*/
|
||||
default float getRoll() {
|
||||
//Cobblemon.LOGGER.info("{}", (float) Math.toDegrees(getUpVector().angleSigned(UP, getForwardVector())));
|
||||
return (float) Mth.wrapDegrees(-Math.toDegrees(getUpVector().angleSigned(UP, getForwardVector())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the angular velocity in degrees per second as a Vec3
|
||||
*/
|
||||
Vec3 angRollVel( double deltaTime );
|
||||
|
||||
public Vec3 rotationOnMouseXY(
|
||||
double yMouse,
|
||||
double xMouse,
|
||||
SmoothDouble yMouseSmoother,
|
||||
SmoothDouble xMouseSmoother,
|
||||
double sensitivity,
|
||||
double deltaTime
|
||||
);
|
||||
|
||||
boolean shouldRoll();
|
||||
|
||||
boolean useAngVelSmoothing();
|
||||
|
||||
void clearRotation();
|
||||
|
||||
}
|
||||
@@ -13,10 +13,12 @@ import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokemon.FormData;
|
||||
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
|
||||
import dev.lambdaurora.lambdynlights.LambDynLights;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightHandler;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightHandlers;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -53,15 +55,19 @@ public class LambDynamicLightsCompat {
|
||||
|
||||
private static int resolvedPokemonLightLevel(PokemonEntity pokemon) {
|
||||
var underwater = !pokemon.level().getFluidState(BlockPos.containing(pokemon.getX(), pokemon.getEyeY(), pokemon.getZ())).isEmpty();
|
||||
return extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
|
||||
|
||||
ItemStack item = pokemon.getShownItem();
|
||||
int itemLightLevel = item.isEmpty()?0:LambDynLights.getLuminanceFromItemStack(item, underwater);
|
||||
int formLightLevel = extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
|
||||
|
||||
return Math.max(itemLightLevel, formLightLevel);
|
||||
}
|
||||
|
||||
private static int resolvedShoulderLightLevel(Player player) {
|
||||
final var shoulderDataPair = PokemonOnShoulderRenderer.shoulderDataOf(player);
|
||||
var underwater = !player.level().getFluidState(BlockPos.containing(player.getX(), player.getEyeY(), player.getZ())).isEmpty();
|
||||
final Optional<Integer> leftLightLevel = extractShoulderLightLevel(shoulderDataPair.getFirst(), underwater);
|
||||
final Optional<Integer> rightLightLevel = extractShoulderLightLevel(shoulderDataPair.getSecond(), underwater);
|
||||
return Math.max(leftLightLevel.orElse(0), rightLightLevel.orElse(0));
|
||||
final int leftLightLevel = extractShoulderLightLevel(PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityLeft()), underwater);
|
||||
final int rightLightLevel = extractShoulderLightLevel(PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityRight()), underwater);
|
||||
return Math.max(leftLightLevel, rightLightLevel);
|
||||
}
|
||||
|
||||
private static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
|
||||
@@ -71,11 +77,16 @@ public class LambDynamicLightsCompat {
|
||||
return Optional.of(form.getLightingData().getLightLevel());
|
||||
}
|
||||
|
||||
private static Optional<Integer> extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
|
||||
private static int extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
|
||||
if (shoulderData == null) {
|
||||
return Optional.empty();
|
||||
return 0;
|
||||
}
|
||||
return extractFormLightLevel(shoulderData.getForm(), underwater);
|
||||
|
||||
ItemStack item = shoulderData.getShownItem();
|
||||
int itemLightLevel = item.isEmpty()?0:LambDynLights.getLuminanceFromItemStack(item, underwater);
|
||||
int formLightLevel = extractFormLightLevel(shoulderData.getForm(), underwater).orElse(0);
|
||||
|
||||
return Math.max(itemLightLevel, formLightLevel);
|
||||
}
|
||||
|
||||
private static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
|
||||
|
||||
@@ -23,16 +23,15 @@ public abstract class LocalPlayerMixin {
|
||||
|
||||
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
|
||||
public void modifyJumpRidingScale(CallbackInfoReturnable<Float> cir) {
|
||||
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
|
||||
//Use custom jump bar logic if the current ride does not jump using it.
|
||||
if( !ride.getRiding().canJump(ride, player))
|
||||
{
|
||||
cir.setReturnValue(ride.setRideBar());
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity pokemonEntity) {
|
||||
var rideValue = pokemonEntity.<Float>ifRidingAvailableSupply(null, (behaviour, settings, state) -> {
|
||||
if (behaviour.canJump(settings, state, pokemonEntity, player)) return null;
|
||||
return behaviour.setRideBar(settings, state, pokemonEntity, player);
|
||||
});
|
||||
if (rideValue != null) {
|
||||
cir.setReturnValue(rideValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,17 @@ package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents;
|
||||
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.api.riding.Seat;
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
|
||||
@@ -31,45 +34,39 @@ import com.cobblemon.mod.common.util.DataKeys;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
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.ServerPlayer;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.*;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class PlayerMixin extends LivingEntity implements Rollable, ScannableEntity {
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable {
|
||||
|
||||
@Shadow public abstract CompoundTag getShoulderEntityLeft();
|
||||
|
||||
@@ -87,7 +84,10 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
|
||||
@Shadow public abstract void displayClientMessage(Component message, boolean overlay);
|
||||
|
||||
@Unique private Matrix3f orientation = null;
|
||||
@Shadow @Final private static Map<Pose, EntityDimensions> POSES;
|
||||
@Shadow @Final public static EntityDimensions STANDING_DIMENSIONS;
|
||||
@Unique
|
||||
private final OrientationController cobblemon$orientationController = new OrientationController(this);
|
||||
|
||||
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, Level p_20967_) {
|
||||
super(p_20966_, p_20967_);
|
||||
@@ -115,6 +115,19 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRenderOrientation(CallbackInfo ci) {
|
||||
this.cobblemon$orientationController.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDimensions getDefaultDimensions(Pose pose) {
|
||||
if (this.getVehicle() instanceof PokemonEntity) {
|
||||
return STANDING_DIMENSIONS;
|
||||
}
|
||||
return POSES.getOrDefault(pose, STANDING_DIMENSIONS);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "removeEntitiesOnShoulder",
|
||||
at = @At(
|
||||
@@ -241,7 +254,7 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
|
||||
@Override
|
||||
public void absMoveTo(double x, double y, double z, float yaw, float pitch) {
|
||||
if (shouldRoll()) {
|
||||
if (cobblemon$orientationController.getActive()) {
|
||||
this.absMoveTo(x, y, z);
|
||||
this.setYRot(yaw % 360.0f);
|
||||
this.setXRot(pitch % 360.0f);
|
||||
@@ -254,120 +267,58 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
public void tick(CallbackInfo ci) {
|
||||
if (this.shouldRoll()) {
|
||||
// Proof of concept for yaw movement
|
||||
if (this.getMainHandItem().is(Items.STICK)) {
|
||||
this.rotateYaw(2);
|
||||
}
|
||||
else if (this.getMainHandItem().is(Items.BLAZE_ROD)) {
|
||||
this.rotateYaw(-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matrix3f getOrientation() {
|
||||
return orientation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rollable updateOrientation(Function<Matrix3f, Matrix3f> update) {
|
||||
//Disabled to allow non mouse inputs to modify roll
|
||||
if (!shouldRoll()) return this;
|
||||
|
||||
if (this.orientation == null) {
|
||||
this.orientation = new Matrix3f();
|
||||
this.rotate(getYRot() - 180, getXRot(), 0);
|
||||
}
|
||||
this.orientation = update.apply(this.orientation);
|
||||
setYRot(this.getYaw());
|
||||
setXRot(this.getPitch());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRoll() {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return false;
|
||||
if (player.isHolding(Items.DIAMOND)) return true;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
|
||||
return pokemonEntity.getRiding().shouldRoll(pokemonEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 rotationOnMouseXY(
|
||||
double yMouse,
|
||||
double xMouse,
|
||||
SmoothDouble yMouseSmoother,
|
||||
SmoothDouble xMouseSmoother,
|
||||
double sensitivity,
|
||||
double deltaTime
|
||||
) {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return Vec3.ZERO;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return Vec3.ZERO;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
|
||||
return pokemonEntity.getRiding().rotationOnMouseXY(
|
||||
pokemonEntity,
|
||||
player,
|
||||
yMouse,
|
||||
xMouse,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAngVelSmoothing() {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return true;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return true;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return true;
|
||||
|
||||
return pokemonEntity.getRiding().useAngVelSmoothing(pokemonEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 angRollVel( double deltaTime ) {
|
||||
var ret = new Vec3(0.0, 0.0, 0.0);
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return ret;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return ret;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return ret;
|
||||
|
||||
return pokemonEntity.getRiding().angRollVel( pokemonEntity, player, deltaTime );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clearRotation() {
|
||||
this.orientation = null;
|
||||
}
|
||||
|
||||
@WrapOperation(
|
||||
method = "rideTick()V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;wantsToStopRiding()Z")
|
||||
)
|
||||
public boolean delegateDismountToController(Player instance, Operation<Boolean> original) {
|
||||
if (this.getVehicle() instanceof Rideable vehicle) {
|
||||
return vehicle.getRiding().dismountOnShift() && original.call(instance);
|
||||
if (this.getVehicle() instanceof PokemonEntity pokemonEntity) {
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.dismountOnShift(settings, state, pokemonEntity) && original.call(instance);
|
||||
});
|
||||
}
|
||||
return original.call(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrientationController getOrientationController() {
|
||||
return cobblemon$orientationController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity) {
|
||||
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
|
||||
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemonEntity.getDelegate();
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
|
||||
|
||||
if (locator == null) {
|
||||
super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
|
||||
OrientationController controller = this.getOrientationController();
|
||||
|
||||
float currEyeHeight = this.getEyeHeight();
|
||||
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
|
||||
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(new Vector3f(0f, currEyeHeight - (this.getBbHeight() / 2), 0f)));
|
||||
|
||||
Vec3 eyePosition = locatorOffset.add(pokemonEntity.position()).add(rotatedEyeHeight);
|
||||
|
||||
Vec3 viewVector = this.getViewVector(partialTicks);
|
||||
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
|
||||
return this.level()
|
||||
.clip(
|
||||
new ClipContext(
|
||||
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.mixin.accessor.ChunkMapAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.TrackedEntityAccessor;
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.ClientboundUpdateRidingStatePacket;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.joml.Matrix3f;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(ServerEntity.class)
|
||||
public abstract class ServerEntityMixin {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private Consumer<Packet<?>> broadcast;
|
||||
@Shadow
|
||||
@Final
|
||||
private Entity entity;
|
||||
@Unique
|
||||
private Matrix3f cobblemon$lastSentOrientation;
|
||||
@Unique
|
||||
private boolean cobblemon$lastSentActive;
|
||||
|
||||
@Inject(method = "sendChanges", at = @At("TAIL"))
|
||||
private void cobblemon$sendChanges(CallbackInfo ci) {
|
||||
cobblemon$sendOrientationChanges();
|
||||
cobblemon$sendRidingStateChanges();
|
||||
}
|
||||
|
||||
private void cobblemon$sendRidingStateChanges() {
|
||||
if (!(this.entity instanceof PokemonEntity pokemonEntity)) return;
|
||||
if (pokemonEntity.getRidingState() == null) return;
|
||||
if (pokemonEntity.getRiding() == null) return;
|
||||
var ridingBehaviour = pokemonEntity.getRiding();
|
||||
var ridingState = pokemonEntity.getRidingState();
|
||||
var previousRidingState = pokemonEntity.getPreviousRidingState();
|
||||
if (previousRidingState != null && !ridingState.shouldSync(previousRidingState)) return;
|
||||
cobblemon$broadcast(new ClientboundUpdateRidingStatePacket(pokemonEntity.getId(), ridingBehaviour.getKey(), pokemonEntity.getRidingState(), null));
|
||||
}
|
||||
|
||||
private void cobblemon$sendOrientationChanges() {
|
||||
if (!(this.entity instanceof OrientationControllable controllable)) return;
|
||||
OrientationController controller = controllable.getOrientationController();
|
||||
Matrix3f currOrientation = controller.getOrientation();
|
||||
boolean currActive = controller.getActive();
|
||||
|
||||
if (currOrientation == null || currOrientation.equals(cobblemon$lastSentOrientation) && (currActive == cobblemon$lastSentActive))
|
||||
return;
|
||||
cobblemon$lastSentOrientation = new Matrix3f(currOrientation);
|
||||
cobblemon$lastSentActive = currActive;
|
||||
|
||||
cobblemon$broadcast(new ClientboundUpdateOrientationPacket(currOrientation, currActive, entity.getId()));
|
||||
}
|
||||
|
||||
private void cobblemon$broadcast(NetworkPacket<?> packet) {
|
||||
if (!(entity.level() instanceof ServerLevel level)) return;
|
||||
ChunkMap chunkMap = level.getChunkSource().chunkMap;
|
||||
Int2ObjectMap<?> entityMap = ((ChunkMapAccessor) chunkMap).getEntityMap();
|
||||
Object tracked = entityMap.get(entity.getId());
|
||||
if (!(tracked instanceof TrackedEntityAccessor tracker)) return;
|
||||
|
||||
Set<ServerPlayerConnection> seenBy = tracker.getSeenBy();
|
||||
for (ServerPlayerConnection conn : seenBy) {
|
||||
ServerPlayer player = conn.getPlayer();
|
||||
if (player == entity) continue;
|
||||
CobblemonNetwork.INSTANCE.sendPacketToPlayer(player, packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class ServerPlayerMixin {
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((ServerPlayer)(Object)this);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(ServerPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(method = "stopRiding", at = @At("HEAD"))
|
||||
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(ChunkMap.class)
|
||||
public interface ChunkMapAccessor {
|
||||
@Accessor("entityMap")
|
||||
Int2ObjectMap<?> getEntityMap();
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(targets = "net.minecraft.server.level.ChunkMap$TrackedEntity")
|
||||
public interface TrackedEntityAccessor {
|
||||
@Accessor("seenBy")
|
||||
Set<ServerPlayerConnection> getSeenBy();
|
||||
}
|
||||
@@ -8,10 +8,29 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.api.riding.Seat;
|
||||
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
@@ -23,10 +42,10 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public abstract class CameraMixin {
|
||||
@Shadow @Final private static float DEFAULT_CAMERA_DISTANCE;
|
||||
|
||||
@Shadow private Entity entity;
|
||||
@Shadow @Final private Quaternionf rotation;
|
||||
@Shadow @Final private Vector3f forwards;
|
||||
@@ -35,10 +54,15 @@ public abstract class CameraMixin {
|
||||
@Shadow private float xRot;
|
||||
@Shadow private float yRot;
|
||||
|
||||
@Shadow public abstract float getXRot();
|
||||
@Shadow private float eyeHeight;
|
||||
@Shadow private float eyeHeightOld;
|
||||
|
||||
@Shadow public abstract float getYRot();
|
||||
@Shadow protected abstract void setPosition(Vec3 pos);
|
||||
|
||||
@Shadow
|
||||
private BlockGetter level;
|
||||
|
||||
@Shadow private float partialTickTime;
|
||||
@Unique private float returnTimer = 0;
|
||||
@Unique private float rollAngleStart = 0;
|
||||
@Unique Minecraft minecraft = Minecraft.getInstance();
|
||||
@@ -46,52 +70,165 @@ public abstract class CameraMixin {
|
||||
@Unique boolean disableRollableCameraDebug = false;
|
||||
|
||||
@Inject(method = "setRotation", at = @At("HEAD"), cancellable = true)
|
||||
public void open_camera$setRotation(float f, float g, CallbackInfo ci) {
|
||||
if (!(this.entity instanceof Rollable rollable) || disableRollableCameraDebug) return;
|
||||
if (!rollable.shouldRoll() && rollable.getOrientation() != null) {
|
||||
public void cobblemon$setRotation(float f, float g, CallbackInfo ci) {
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || disableRollableCameraDebug) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() && controller.getOrientation() != null) {
|
||||
if(this.returnTimer < 1) {
|
||||
//Rotation is taken from entity since we no longer handle mouse ourselves
|
||||
//Stops a period of time when you can't input anything.
|
||||
rollable.getOrientation().set(
|
||||
controller.getOrientation().set(
|
||||
new Matrix3f()
|
||||
.rotateY((float) Math.toRadians(180 - this.entity.getYRot()))
|
||||
.rotateX((float) Math.toRadians(-this.entity.getXRot()))
|
||||
);
|
||||
if(rollAngleStart == 0){
|
||||
this.returnTimer = 1;
|
||||
rollable.clearRotation();
|
||||
controller.reset();
|
||||
return;
|
||||
}
|
||||
rollable.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
|
||||
applyRotation();
|
||||
controller.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
|
||||
cobblemon$applyRotation();
|
||||
this.returnTimer += .05F;
|
||||
ci.cancel();
|
||||
} else {
|
||||
this.returnTimer = 1;
|
||||
rollable.clearRotation();
|
||||
controller.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (rollable.getOrientation() == null) return;
|
||||
applyRotation();
|
||||
if (controller.getOrientation() == null) return;
|
||||
cobblemon$applyRotation();
|
||||
|
||||
this.returnTimer = 0;
|
||||
this.rollAngleStart = rollable.getRoll();
|
||||
this.rollAngleStart = controller.getRoll();
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
//If you want to move this to a delagate you need an AW for position
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setPosition(DDD)V"))
|
||||
public void cobblemon$positionCamera(Camera instance, double x, double y, double z, Operation<Void> original, @Local(ordinal = 1, argsOnly = true) boolean thirdPersonReverse) {
|
||||
Entity entity = instance.getEntity();
|
||||
Entity vehicle = entity.getVehicle();
|
||||
MountedPokemonAnimationRenderController.INSTANCE.reset();
|
||||
|
||||
if(vehicle instanceof Rideable){
|
||||
//RidingCameraDelagate.INSTANCE.positionCamera(instance, x, y, z, original);
|
||||
if (!(vehicle instanceof PokemonEntity pokemon)) {
|
||||
original.call(instance, x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemon.getDelegate();
|
||||
Vec3 entityPos = new Vec3(
|
||||
Mth.lerp(instance.getPartialTickTime(), pokemon.xOld, pokemon.getX()),
|
||||
Mth.lerp(instance.getPartialTickTime(), pokemon.yOld, pokemon.getY()),
|
||||
Mth.lerp(instance.getPartialTickTime(), pokemon.zOld, pokemon.getZ())
|
||||
);
|
||||
MountedPokemonAnimationRenderController.INSTANCE.setup(pokemon, partialTickTime);
|
||||
int seatIndex = pokemon.getPassengers().indexOf(entity);
|
||||
Seat seat = pokemon.getSeats().get(seatIndex);
|
||||
|
||||
OrientationControllable rollable = (OrientationControllable) entity;
|
||||
OrientationController controller = rollable.getOrientationController();
|
||||
|
||||
if (!instance.isDetached() || Cobblemon.config.getThirdPartyViewBobbing()) {
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
|
||||
|
||||
if (locator == null) {
|
||||
original.call(instance, x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
|
||||
float currEyeHeight = Mth.lerp(instance.getPartialTickTime(), eyeHeightOld, eyeHeight);
|
||||
var rotatedEyeHeight = new Vector3f(0f, currEyeHeight - (entity.getBbHeight() / 2), 0f);
|
||||
if (controller.isActive()) {
|
||||
rotatedEyeHeight = controller.getRenderOrientation(partialTickTime).transform(rotatedEyeHeight);
|
||||
}
|
||||
|
||||
Vec3 position = locatorOffset.add(entityPos).add(new Vec3(rotatedEyeHeight));
|
||||
setPosition(position);
|
||||
} else {
|
||||
Vector3f pos = entityPos.add(new Vec3(0, pokemon.getBbHeight() / 2, 0)).toVector3f();
|
||||
|
||||
PosableModel model = VaryingModelRepository.INSTANCE.getPoser(pokemon.getPokemon().getSpecies().getResourceIdentifier(), new FloatingState());
|
||||
Map<String, Vec3> cameraOffsets = model.getSeatToCameraOffset();
|
||||
|
||||
Vec3 cameraOffset;
|
||||
if (thirdPersonReverse && cameraOffsets.containsKey(seat.getLocator() + "_reverse")) {
|
||||
cameraOffset = cameraOffsets.get(seat.getLocator() + "_reverse");
|
||||
} else if (cameraOffsets.containsKey(seat.getLocator())) {
|
||||
cameraOffset = cameraOffsets.get(seat.getLocator());
|
||||
} else {
|
||||
cameraOffset = new Vec3(0f, 2f, 4f);
|
||||
}
|
||||
|
||||
Vector3f offset = cameraOffset.toVector3f();
|
||||
|
||||
if (thirdPersonReverse) offset.z *= -1;
|
||||
float xRot = (float) (-1 * Math.toRadians(instance.getXRot()));
|
||||
|
||||
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f().rotateY((float) Math.toRadians(180f - instance.getYRot())).rotateX(xRot);
|
||||
Vector3f rotatedOffset = orientation.transform(offset);
|
||||
float offsetDistance = rotatedOffset.length();
|
||||
Vector3f offsetDirection = rotatedOffset.mul(1 / offsetDistance);
|
||||
|
||||
float maxZoom = cobblemon$getMaxZoom(offsetDistance, offsetDirection, pos);
|
||||
|
||||
setPosition(new Vec3(offsetDirection.mul(maxZoom).add(pos)));
|
||||
}
|
||||
} else {
|
||||
original.call(instance, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void applyRotation(){
|
||||
if (!(this.entity instanceof Rollable rollable) || rollable.getOrientation() == null) return;
|
||||
var newRotation = rollable.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
private void cobblemon$applyRotation(){
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || controllable.getOrientationController().getOrientation() == null) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
var newRotation = controller.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
if (this.minecraft.options.getCameraType().isMirrored()) {
|
||||
newRotation.rotateY((float)Math.toRadians(180));
|
||||
}
|
||||
this.rotation.set(newRotation);
|
||||
this.xRot = rollable.getPitch();
|
||||
this.yRot = rollable.getYaw();
|
||||
this.forwards.set(rollable.getForwardVector());
|
||||
this.up.set(rollable.getUpVector());
|
||||
this.left.set(rollable.getLeftVector());
|
||||
this.xRot = controller.getPitch();
|
||||
this.yRot = controller.getYaw();
|
||||
this.forwards.set(controller.getForwardVector());
|
||||
this.up.set(controller.getUpVector());
|
||||
this.left.set(controller.getLeftVector());
|
||||
}
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;move(FFF)V", ordinal = 0))
|
||||
public void stopMoveIfRolling(Camera instance, float zoom, float dy, float dx, Operation<Void> original) {
|
||||
Entity entity = instance.getEntity();
|
||||
Entity vehicle = entity.getVehicle();
|
||||
|
||||
if (!(vehicle instanceof PokemonEntity) || Cobblemon.config.getThirdPartyViewBobbing()) {
|
||||
original.call(instance, zoom, dy, dx);
|
||||
}
|
||||
}
|
||||
|
||||
//Modified vanilla code
|
||||
@Unique
|
||||
private float cobblemon$getMaxZoom(float maxZoom, Vector3f directionVector, Vector3f positionVector) {
|
||||
Vec3 pos = new Vec3(positionVector);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
float g = (float) ((i & 1) * 2 - 1);
|
||||
float h = (float) ((i >> 1 & 1) * 2 - 1);
|
||||
float j = (float) ((i >> 2 & 1) * 2 - 1);
|
||||
Vec3 vec3 = pos.add(g * 0.1F, h * 0.1F, j * 0.1F);
|
||||
Vec3 vec32 = vec3.add(new Vec3(directionVector).scale(maxZoom));
|
||||
HitResult hitResult = this.level.clip(new ClipContext(vec3, vec32, ClipContext.Block.VISUAL, ClipContext.Fluid.NONE, this.entity));
|
||||
if (hitResult.getType() != HitResult.Type.MISS) {
|
||||
float k = (float) hitResult.getLocation().distanceToSqr(pos);
|
||||
if (k < Mth.square(maxZoom)) {
|
||||
maxZoom = Mth.sqrt(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxZoom;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,21 @@ public class HumanoidModelMixin {
|
||||
}
|
||||
|
||||
Entity vehicle = entity.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity && entity instanceof AbstractClientPlayer) {
|
||||
MountedPlayerRenderer.INSTANCE.animate((PokemonEntity) vehicle, (AbstractClientPlayer) entity, relevantPartsByName, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity && entity instanceof AbstractClientPlayer) {
|
||||
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRotatePlayerHead(settings, state, pokemonEntity);
|
||||
});
|
||||
|
||||
if (!shouldRotatePlayerHead) {
|
||||
netHeadYaw = 0f;
|
||||
headPitch = 0f;
|
||||
if (this.head != null) {
|
||||
this.head.yRot = 0f;
|
||||
this.head.xRot = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
MountedPlayerRenderer.INSTANCE.animate(pokemonEntity, (AbstractClientPlayer) entity, relevantPartsByName, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -8,7 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -31,14 +31,14 @@ public class ItemInHandRendererMixin {
|
||||
if (abstractClientPlayer.isUsingItem() && abstractClientPlayer.getUseItem().getItem() instanceof PokedexItem) {
|
||||
ci.cancel();
|
||||
}
|
||||
else if (abstractClientPlayer instanceof Rollable rollable && rollable.shouldRoll()) {
|
||||
else if (abstractClientPlayer instanceof OrientationControllable controllable && controllable.getOrientationController().isActive()) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V", ordinal = 1))
|
||||
private void cobblemon$renderHandswithItems(PoseStack instance, Quaternionf quaternion) {
|
||||
if (!(Minecraft.getInstance().player instanceof Rollable rollable && rollable.shouldRoll())) {
|
||||
if (!(Minecraft.getInstance().player instanceof OrientationControllable controllable && controllable.getOrientationController().isActive())) {
|
||||
instance.mulPose(quaternion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.ModAPI;
|
||||
import com.cobblemon.mod.common.item.PokeBallItem;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.cobblemon.mod.common.item.WearableItem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.ItemModelShaper;
|
||||
@@ -54,17 +55,18 @@ public abstract class ItemRendererMixin {
|
||||
)
|
||||
private void cobblemon$overrideItemModel(ItemStack stack, ItemDisplayContext renderMode, boolean leftHanded, PoseStack matrices, MultiBufferSource multiBufferSource, int light, int overlay, BakedModel model, CallbackInfo ci) {
|
||||
boolean shouldBe2d = renderMode == ItemDisplayContext.GUI || renderMode == ItemDisplayContext.FIXED;
|
||||
ResourceLocation resourceLocation = null;
|
||||
if (shouldBe2d) {
|
||||
ResourceLocation resourceLocation = null;
|
||||
if (stack.getItem() instanceof PokeBallItem pokeBallItem) resourceLocation = pokeBallItem.getPokeBall().getModel2d();
|
||||
else if (stack.getItem() instanceof PokedexItem pokedexItem) resourceLocation = pokedexItem.getType().getItemSpritePath();
|
||||
}
|
||||
if (renderMode != ItemDisplayContext.HEAD && stack.getItem() instanceof WearableItem wearableItem) resourceLocation = wearableItem.getModel2d();
|
||||
|
||||
if (resourceLocation != null) {
|
||||
BakedModel replacementModel = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, "inventory"));
|
||||
if (!cobblemon$isSameModel(model, replacementModel)) {
|
||||
ci.cancel();
|
||||
render(stack, renderMode, leftHanded, matrices, multiBufferSource, light, overlay, replacementModel);
|
||||
}
|
||||
if (resourceLocation != null) {
|
||||
BakedModel replacementModel = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, "inventory"));
|
||||
if (!cobblemon$isSameModel(model, replacementModel)) {
|
||||
ci.cancel();
|
||||
render(stack, renderMode, leftHanded, matrices, multiBufferSource, light, overlay, replacementModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,6 +80,7 @@ public abstract class ItemRendererMixin {
|
||||
boolean canOpenScreen = entity != null && ((entity.getOffhandItem() == stack && !(entity.getMainHandItem().getItem() instanceof PokedexItem)) || entity.getMainHandItem() == stack);
|
||||
resourceLocation = pokedexItem.getType().getItemModelPath(isScanModel ? "scanning" : (canOpenScreen ? null : "off"));
|
||||
}
|
||||
else if (stack.getItem() instanceof WearableItem wearableItem) resourceLocation = wearableItem.getModel3d();
|
||||
|
||||
if (resourceLocation != null) {
|
||||
BakedModel model = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, MODEL_PATH));
|
||||
|
||||
@@ -9,9 +9,14 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.C2SUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.joml.Matrix3f;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
@@ -20,24 +25,55 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(LocalPlayer.class)
|
||||
public class LocalPlayerMixin {
|
||||
public abstract class LocalPlayerMixin extends LivingEntity {
|
||||
|
||||
@Unique Matrix3f cobblemon$lastOrientation;
|
||||
|
||||
@Inject(method = "sendPosition", at = @At("TAIL"))
|
||||
private void cobblemon_updateRotationMatrix(CallbackInfo ci) {
|
||||
if (!(this instanceof Rollable rollable)) return;
|
||||
if (rollable.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = rollable.getOrientation() != null ? new Matrix3f(rollable.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new C2SUpdateOrientationPacket(rollable.getOrientation()));
|
||||
protected LocalPlayerMixin(EntityType<? extends LivingEntity> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
}
|
||||
|
||||
// @Inject(method = "sendPosition", at = @At("TAIL"))
|
||||
// private void cobblemon$updateRotationMatrix(CallbackInfo ci) {
|
||||
// if (!(this instanceof OrientationControllable controllable)) return;
|
||||
// var controller = controllable.getOrientationController();
|
||||
// if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
|
||||
// cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
|
||||
// CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
|
||||
// }
|
||||
|
||||
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
private void cobblemon_updateRotationMatrixPassenger(CallbackInfo ci) {
|
||||
if (!(this instanceof Rollable rollable)) return;
|
||||
if (rollable.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = rollable.getOrientation() != null ? new Matrix3f(rollable.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new C2SUpdateOrientationPacket(rollable.getOrientation()));
|
||||
private void cobblemon$updateRotationMatrixPassenger(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((LocalPlayer)(Object)this);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(LocalPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopRiding() {
|
||||
super.stopRiding();
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
|
||||
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
@@ -29,9 +30,10 @@ import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
@Mixin(MouseHandler.class)
|
||||
public class MouseHandlerMixin {
|
||||
public abstract class MouseHandlerMixin {
|
||||
@Shadow private double accumulatedScrollY;
|
||||
@Shadow @Final private Minecraft minecraft;
|
||||
|
||||
@@ -49,7 +51,13 @@ public class MouseHandlerMixin {
|
||||
|
||||
@Shadow private double accumulatedDY;
|
||||
|
||||
@Shadow private double accumulatedScrollX;
|
||||
@Shadow private double lastHandleMovementTime;
|
||||
|
||||
@Shadow public abstract boolean isMouseGrabbed();
|
||||
|
||||
@Shadow protected abstract void turnPlayer(double movementTime);
|
||||
|
||||
@Unique private double cobblemon$timeDelta;
|
||||
|
||||
@Inject(
|
||||
method = "onScroll",
|
||||
@@ -121,9 +129,9 @@ public class MouseHandlerMixin {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(player instanceof Rollable rollable)) return true;
|
||||
if (!(player instanceof OrientationControllable controllable)) return true;
|
||||
|
||||
if (!rollable.shouldRoll()) {
|
||||
if (!controllable.getOrientationController().isActive()) {
|
||||
xMouseSmoother.reset();
|
||||
yMouseSmoother.reset();
|
||||
pitchSmoother.reset();
|
||||
@@ -132,68 +140,110 @@ public class MouseHandlerMixin {
|
||||
return true;
|
||||
}
|
||||
|
||||
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6000000238418579 + 0.20000000298023224;
|
||||
var ridingSensitivity = Math.pow(defaultSensitivity, 3);
|
||||
|
||||
//Send mouse input to be interpreted into rotation
|
||||
//deltas by the ride controller
|
||||
Vec3 angVecMouse = rollable.rotationOnMouseXY(
|
||||
cursorDeltaY,
|
||||
cursorDeltaX ,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
ridingSensitivity,
|
||||
movementTime
|
||||
);
|
||||
Vec3 angVecMouse = cobblemon$getRideMouseRotation(cursorDeltaX, cursorDeltaY, movementTime);
|
||||
|
||||
//Perform Rotation using mouse influenced rotation deltas.
|
||||
rollable.rotate(
|
||||
controllable.getOrientationController().rotate(
|
||||
(float) angVecMouse.x,
|
||||
(float) angVecMouse.y,
|
||||
(float) angVecMouse.z
|
||||
);
|
||||
|
||||
|
||||
//Gather and apply the current rotation deltas
|
||||
var angRot = rollable.angRollVel(movementTime);
|
||||
var angRot = cobblemon$getAngularVelocity(movementTime);
|
||||
|
||||
//Apply smoothing if requested by the controller.
|
||||
//This Might be best if done by the controller itself?
|
||||
if( rollable.useAngVelSmoothing() )
|
||||
if(cobblemon$shouldUseAngVelSmoothing())
|
||||
{
|
||||
if( angRot != null ) {
|
||||
var yaw = yawSmoother.getNewDeltaValue(angRot.x * 0.5f, d);
|
||||
var pitch = pitchSmoother.getNewDeltaValue(angRot.y * 0.5f, d);
|
||||
var roll = rollSmoother.getNewDeltaValue(angRot.z * 0.5f, d);
|
||||
rollable.rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
var yaw = yawSmoother.getNewDeltaValue(angRot.x * 0.5f, d);
|
||||
var pitch = pitchSmoother.getNewDeltaValue(angRot.y * 0.5f, d);
|
||||
var roll = rollSmoother.getNewDeltaValue(angRot.z * 0.5f, d);
|
||||
controllable.getOrientationController().rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
//Otherwise simply apply the smoothing
|
||||
else
|
||||
{
|
||||
if( angRot != null ) {
|
||||
rollable.rotate((float) (
|
||||
angRot.x * 10 * d),
|
||||
(float) (angRot.y * 10 * d),
|
||||
(float) (angRot.z * 10 * d)
|
||||
);
|
||||
}
|
||||
controllable.getOrientationController().rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
}
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHandler;isMouseGrabbed()Z", ordinal = 0))
|
||||
private void cobblemon$maintainMovementWhenInScreens(CallbackInfo ci, @Local(ordinal = 1) double e) {
|
||||
if (minecraft.player == null) return;
|
||||
if (!(minecraft.player instanceof Rollable rollable)) return;
|
||||
if (!rollable.shouldRoll()) return;
|
||||
if (minecraft.isPaused()) return;
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At("HEAD"))
|
||||
private void cobblemon$maintainMovementWhenInScreens2(CallbackInfo ci) {
|
||||
double time = Blaze3D.getTime();
|
||||
cobblemon$timeDelta = time - this.lastHandleMovementTime;
|
||||
}
|
||||
|
||||
var pitch = pitchSmoother.getNewDeltaValue(0, e);
|
||||
var roll = rollSmoother.getNewDeltaValue(0, e);
|
||||
rollable.rotate(0.0F, (float)pitch, (float)roll);
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At("TAIL"))
|
||||
private void cobblemon$maintainMovementWhenInScreens(CallbackInfo ci) {
|
||||
if (minecraft.player == null) return;
|
||||
if (!(minecraft.player instanceof OrientationControllable controllable)) return;
|
||||
if (!controllable.getOrientationController().isActive()) return;
|
||||
if (minecraft.isPaused()) return;
|
||||
if (isMouseGrabbed()) return;
|
||||
|
||||
this.turnPlayer(cobblemon$timeDelta);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Vec3 cobblemon$getAngularVelocity(double deltaTime) {
|
||||
var player = minecraft.player;
|
||||
if (player == null) return Vec3.ZERO;
|
||||
if (!(player instanceof OrientationControllable)) return Vec3.ZERO;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return Vec3.ZERO;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
return pokemonEntity.ifRidingAvailableSupply(Vec3.ZERO, (behaviour, settings, state) -> {
|
||||
return behaviour.angRollVel(settings, state, pokemonEntity, player, deltaTime);
|
||||
});
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Vec3 cobblemon$getRideMouseRotation(double mouseX, double mouseY, double deltaTime) {
|
||||
var player = minecraft.player;
|
||||
if (player == null) return Vec3.ZERO;
|
||||
var vehicle = player.getVehicle();
|
||||
if (vehicle == null) return Vec3.ZERO;
|
||||
if (!(vehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
|
||||
var sensitivity = cobblemon$getRidingSensitivity();
|
||||
return pokemonEntity.ifRidingAvailableSupply(Vec3.ZERO, (behaviour, settings, state) -> {
|
||||
return behaviour.rotationOnMouseXY(
|
||||
settings,
|
||||
state,
|
||||
pokemonEntity,
|
||||
player,
|
||||
mouseY,
|
||||
mouseX,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Unique
|
||||
private double cobblemon$getRidingSensitivity() {
|
||||
var sensitivity = this.minecraft.options.sensitivity().get() * 0.6000000238418579 + 0.20000000298023224;
|
||||
return Math.pow(sensitivity, 3);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseAngVelSmoothing() {
|
||||
var player = minecraft.player;
|
||||
if (player == null) return true;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return true;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return true;
|
||||
return pokemonEntity.ifRidingAvailableSupply(true, (behaviour, settings, state) -> {
|
||||
return behaviour.useAngVelSmoothing(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.api.riding.RidingManager;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.model.PlayerModel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PlayerModel.class)
|
||||
public class PlayerModelMixin {
|
||||
@Inject(method = "setupAnim(Lnet/minecraft/world/entity/LivingEntity;FFFFF)V", at = @At(value = "HEAD"))
|
||||
private void cobblemon$setHeadRotation(LivingEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, CallbackInfo ci){
|
||||
if (!(entity instanceof Player)) return;
|
||||
Entity vehicle = entity.getVehicle();
|
||||
|
||||
if (!(vehicle instanceof PokemonEntity)) return;
|
||||
RidingManager ridingManager = ((Rideable) vehicle).getRiding();
|
||||
if (ridingManager.shouldRotatePlayerHead((PokemonEntity) vehicle)) return;
|
||||
|
||||
netHeadYaw = 0f;
|
||||
headPitch = 0f;
|
||||
}
|
||||
}
|
||||
+28
-1
@@ -11,9 +11,15 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
import com.cobblemon.mod.common.client.render.ClientPlayerIcon;
|
||||
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.model.EntityModel;
|
||||
import net.minecraft.client.model.PlayerModel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
@@ -23,12 +29,33 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PlayerRenderer.class)
|
||||
public class PlayerRendererMixin {
|
||||
public abstract class PlayerRendererMixin extends LivingEntityRenderer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> {
|
||||
|
||||
public PlayerRendererMixin(EntityRendererProvider.Context context, PlayerModel<AbstractClientPlayer> model, float shadowRadius) {
|
||||
super(context, model, shadowRadius);
|
||||
}
|
||||
|
||||
@Inject(method = "render(Lnet/minecraft/world/entity/LivingEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "TAIL"))
|
||||
public void cobblemon$clientPlayerIcon(LivingEntity entity, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource buffer, int packedLight, CallbackInfo ci) {
|
||||
ClientPlayerIcon.Companion.onRenderPlayer((Player) entity);
|
||||
}
|
||||
|
||||
@WrapOperation(method = "getRenderOffset(Lnet/minecraft/client/player/AbstractClientPlayer;F)Lnet/minecraft/world/phys/Vec3;", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/AbstractClientPlayer;isCrouching()Z"))
|
||||
private boolean cobblemon$disableCrouchOffset(AbstractClientPlayer instance, Operation<Boolean> original) {
|
||||
if (instance.isPassenger() && instance.getVehicle() instanceof PokemonEntity) {
|
||||
return false;
|
||||
}
|
||||
return original.call(instance);
|
||||
}
|
||||
|
||||
@Inject(method = "setModelProperties", at = @At("TAIL"))
|
||||
private void cobblemon$setModelProperties(AbstractClientPlayer player, CallbackInfo ci) {
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
PlayerModel<AbstractClientPlayer> playerModel = this.getModel();
|
||||
playerModel.crouching = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "setupRotations(Lnet/minecraft/client/player/AbstractClientPlayer;Lcom/mojang/blaze3d/vertex/PoseStack;FFFF)V",
|
||||
at = @At("HEAD")
|
||||
|
||||
@@ -86,9 +86,9 @@ import com.cobblemon.mod.common.permission.LaxPermissionValidator
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.aspects.COSMETIC_SLOT_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.FORM_ASPECTS
|
||||
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
|
||||
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.properties.AspectPropertyType
|
||||
@@ -100,6 +100,7 @@ import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.pokemon.transformation.triggers.BlockClickTrigger
|
||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -254,13 +255,8 @@ object Cobblemon {
|
||||
PlatformEvents.RIGHT_CLICK_BLOCK.subscribe { event ->
|
||||
val player = event.player
|
||||
val block = player.level().getBlockState(event.pos).block
|
||||
player.party().forEach { pokemon ->
|
||||
pokemon.lockedEvolutions
|
||||
.filterIsInstance<BlockClickEvolution>()
|
||||
.forEach { evolution ->
|
||||
evolution.attemptEvolution(pokemon, BlockClickEvolution.BlockInteractionContext(block, player.level()))
|
||||
}
|
||||
}
|
||||
val context = BlockClickTrigger.Context(block, player.level())
|
||||
player.party().forEach { pokemon -> pokemon.triggerTransformations(BlockClickTrigger::class.java, context) }
|
||||
}
|
||||
|
||||
PlatformEvents.CHANGE_DIMENSION.subscribe {
|
||||
@@ -301,6 +297,7 @@ object Cobblemon {
|
||||
|
||||
SHINY_ASPECT.register()
|
||||
GENDER_ASPECT.register()
|
||||
FORM_ASPECTS.register()
|
||||
COSMETIC_SLOT_ASPECT.register()
|
||||
|
||||
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
|
||||
@@ -562,6 +559,9 @@ object Cobblemon {
|
||||
this.implementation.registerCommandArgument(cobblemonResource("dex"), DexArgumentType::class, SingletonArgumentInfo.contextFree (DexArgumentType::dex))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("npc_class"), NPCClassArgumentType::class, SingletonArgumentInfo.contextFree(NPCClassArgumentType::npcClass))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("wallpaper"), UnlockablePCBoxWallpaperArgumentType::class, SingletonArgumentInfo.contextFree(UnlockablePCBoxWallpaperArgumentType::wallpaper))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("mark"), MarkArgumentType::class, SingletonArgumentInfo.contextFree(MarkArgumentType::mark))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("transform_type"), TransformTypeArgumentType::class, SingletonArgumentInfo.contextFree(TransformTypeArgumentType::transformType))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("model_part"), ModelPartArgumentType::class, SingletonArgumentInfo.contextFree(ModelPartArgumentType::modelPart))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ object CobblemonCommands {
|
||||
ChangeEyeHeight.register(dispatcher)
|
||||
ChangeScaleAndSize.register(dispatcher)
|
||||
ChangeWalkSpeed.register(dispatcher)
|
||||
ChangeJointScaleCommand.register(dispatcher)
|
||||
TransformModelPartCommand.register(dispatcher)
|
||||
TestCommand.register(dispatcher)
|
||||
ReloadShowdownCommand.register(dispatcher)
|
||||
ClickTextCommand.register(dispatcher)
|
||||
@@ -60,8 +60,13 @@ object CobblemonCommands {
|
||||
RenameBoxCommand.register(dispatcher)
|
||||
ChangeBoxWallpaperCommand.register(dispatcher)
|
||||
RunMolangScriptCommand.register(dispatcher)
|
||||
SpectateBattleCommand.register(dispatcher)
|
||||
CobblemonConfigCommand.register(dispatcher)
|
||||
UnlockPCBoxWallpaperCommand.register(dispatcher)
|
||||
ChangePCBoxesCommand.register(dispatcher)
|
||||
MarkGiveCommand.register(dispatcher)
|
||||
MarkTakeCommand.register(dispatcher)
|
||||
MarkGiveAllCommand.register(dispatcher)
|
||||
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
|
||||
@@ -281,7 +281,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
// Evolution items
|
||||
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
|
||||
@JvmField val DRAGON_SCALE = noSettingsItem("dragon_scale")
|
||||
@JvmField val KINGS_ROCK = noSettingsItem("kings_rock")
|
||||
@JvmField val METAL_COAT = noSettingsItem("metal_coat")
|
||||
@JvmField val UPGRADE = noSettingsItem("upgrade")
|
||||
@JvmField val DUBIOUS_DISC = noSettingsItem("dubious_disc")
|
||||
@@ -294,20 +293,21 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField val REAPER_CLOTH = noSettingsItem("reaper_cloth")
|
||||
@JvmField val PRISM_SCALE = noSettingsItem("prism_scale")
|
||||
@JvmField val SACHET = noSettingsItem("sachet")
|
||||
@JvmField val WHIPPED_DREAM = noSettingsItem("whipped_dream")
|
||||
@JvmField val STRAWBERRY_SWEET = noSettingsItem("strawberry_sweet")
|
||||
@JvmField val LOVE_SWEET = noSettingsItem("love_sweet")
|
||||
@JvmField val BERRY_SWEET = noSettingsItem("berry_sweet")
|
||||
@JvmField val CLOVER_SWEET = noSettingsItem("clover_sweet")
|
||||
@JvmField val FLOWER_SWEET = noSettingsItem("flower_sweet")
|
||||
@JvmField val STAR_SWEET = noSettingsItem("star_sweet")
|
||||
@JvmField val RIBBON_SWEET = noSettingsItem("ribbon_sweet")
|
||||
@JvmField val WHIPPED_DREAM = create("whipped_dream", foodItem(8, 0.3f))
|
||||
@JvmField val STRAWBERRY_SWEET = create("strawberry_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val LOVE_SWEET = create("love_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val BERRY_SWEET = create("berry_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val CLOVER_SWEET = create("clover_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val FLOWER_SWEET = create("flower_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val STAR_SWEET = create("star_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val RIBBON_SWEET = create("ribbon_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
|
||||
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
|
||||
@JvmField val MASTERPIECE_TEACUP = noSettingsItem("masterpiece_teacup")
|
||||
@JvmField val UNREMARKABLE_TEACUP = noSettingsItem("unremarkable_teacup")
|
||||
@JvmField val SWEET_APPLE = noSettingsItem("sweet_apple")
|
||||
@JvmField val TART_APPLE = noSettingsItem("tart_apple")
|
||||
@JvmField val SWEET_APPLE = create("sweet_apple", foodItem(4, 0.3f))
|
||||
@JvmField val TART_APPLE = create("tart_apple", foodItem(4, 0.3f))
|
||||
@JvmField val SYRUPY_APPLE = create("syrupy_apple", foodItem(4, 0.3f))
|
||||
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
|
||||
@JvmField val GALARICA_WREATH = noSettingsItem("galarica_wreath")
|
||||
@JvmField val BLACK_AUGURITE = noSettingsItem("black_augurite")
|
||||
@@ -660,6 +660,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val WATER_STONE = noSettingsItem("water_stone")
|
||||
|
||||
val wearables = mutableListOf<WearableItem>()
|
||||
//Wearable items (these items should have a corresponding 3D model)
|
||||
@JvmField val BLACK_GLASSES = wearableItem("black_glasses")
|
||||
@JvmField val CHOICE_BAND = wearableItem("choice_band")
|
||||
@JvmField val CHOICE_SPECS = wearableItem("choice_specs")
|
||||
@JvmField val EXP_SHARE = wearableItem("exp_share")
|
||||
@JvmField val FOCUS_BAND = wearableItem("focus_band")
|
||||
@JvmField val KINGS_ROCK = wearableItem("kings_rock")
|
||||
@JvmField val MUSCLE_BAND = wearableItem("muscle_band")
|
||||
@JvmField val ROCKY_HELMET = wearableItem("rocky_helmet")
|
||||
@JvmField val SAFETY_GOGGLES = wearableItem("safety_goggles")
|
||||
@JvmField val WISE_GLASSES = wearableItem("wise_glasses")
|
||||
|
||||
// Held Items
|
||||
@JvmField
|
||||
val ABILITY_SHIELD = heldItem("ability_shield")
|
||||
@@ -676,8 +689,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val BLACK_BELT = heldItem("black_belt")
|
||||
@JvmField
|
||||
val BLACK_GLASSES = heldItem("black_glasses")
|
||||
@JvmField
|
||||
val BLACK_SLUDGE = heldItem("black_sludge")
|
||||
@JvmField
|
||||
val BLUNDER_POLICY = heldItem("blunder_policy")
|
||||
@@ -686,12 +697,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val CHARCOAL = heldItem("charcoal_stick", remappedName = "charcoal")
|
||||
@JvmField
|
||||
val CHOICE_BAND = heldItem("choice_band")
|
||||
@JvmField
|
||||
val CHOICE_SCARF = heldItem("choice_scarf")
|
||||
@JvmField
|
||||
val CHOICE_SPECS = heldItem("choice_specs")
|
||||
@JvmField
|
||||
val CLEANSE_TAG = heldItem("cleanse_tag")
|
||||
// @JvmField
|
||||
// val CLEAR_AMULET = heldItem("clear_amulet")
|
||||
@@ -712,8 +719,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val EVIOLITE = heldItem("eviolite")
|
||||
@JvmField
|
||||
val EXP_SHARE = heldItem("exp_share")
|
||||
@JvmField
|
||||
val EXPERT_BELT = heldItem("expert_belt")
|
||||
@JvmField
|
||||
val FAIRY_FEATHER = heldItem("fairy_feather")
|
||||
@@ -722,8 +727,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val FLOAT_STONE = heldItem("float_stone")
|
||||
@JvmField
|
||||
val FOCUS_BAND = heldItem("focus_band")
|
||||
@JvmField
|
||||
val FOCUS_SASH = heldItem("focus_sash")
|
||||
@JvmField
|
||||
val GRASSY_SEED = heldItem("grassy_seed")
|
||||
@@ -758,8 +761,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val MIRACLE_SEED = heldItem("miracle_seed")
|
||||
@JvmField
|
||||
val MUSCLE_BAND = heldItem("muscle_band")
|
||||
@JvmField
|
||||
val MYSTIC_WATER = heldItem("mystic_water")
|
||||
@JvmField
|
||||
val NEVER_MELT_ICE = heldItem("never_melt_ice")
|
||||
@@ -790,12 +791,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val RING_TARGET = heldItem("ring_target")
|
||||
@JvmField
|
||||
val ROCKY_HELMET = heldItem("rocky_helmet")
|
||||
@JvmField
|
||||
val ROOM_SERVICE = heldItem("room_service")
|
||||
@JvmField
|
||||
val SAFETY_GOGGLES = heldItem("safety_goggles")
|
||||
@JvmField
|
||||
val SCOPE_LENS = heldItem("scope_lens")
|
||||
@JvmField
|
||||
val SHARP_BEAK = heldItem("sharp_beak")
|
||||
@@ -832,8 +829,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val WIDE_LENS = heldItem("wide_lens")
|
||||
@JvmField
|
||||
val WISE_GLASSES = heldItem("wise_glasses")
|
||||
@JvmField
|
||||
val ZOOM_LENS = heldItem("zoom_lens")
|
||||
@JvmField
|
||||
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 1F)
|
||||
@@ -1263,6 +1258,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return item
|
||||
}
|
||||
|
||||
private fun wearableItem(name: String, heldItemRemappedName: String? = null): CobblemonItem = create(
|
||||
name,
|
||||
WearableItem(name).also {
|
||||
wearables.add(it)
|
||||
if (heldItemRemappedName != null) {
|
||||
CobblemonHeldItemManager.registerRemap(it, heldItemRemappedName)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
|
||||
name,
|
||||
CobblemonItem(Item.Properties()).also {
|
||||
@@ -1354,4 +1359,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return createdItem
|
||||
}
|
||||
|
||||
private fun foodItem(nutrition: Int, saturationModifier: Float): Item {
|
||||
return Item(Item.Properties().food(FoodProperties.Builder().nutrition(nutrition).saturationModifier(saturationModifier).build()))
|
||||
}
|
||||
}
|
||||
@@ -29,11 +29,13 @@ import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.orientation.S2CUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pokedex.ServerConfirmedRegisterHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundUpdateRidingStateHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
|
||||
import com.cobblemon.mod.common.client.net.settings.OpenCobblemonConfigEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
|
||||
@@ -73,6 +75,7 @@ import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityP
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.CloseNPCEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.OpenNPCEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
|
||||
@@ -142,7 +145,7 @@ import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPoke
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.C2SUpdateOrientationPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPacket
|
||||
@@ -151,6 +154,9 @@ import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.StartScannin
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHiddenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
|
||||
@@ -164,9 +170,6 @@ import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptanceP
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.PerformTradePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
|
||||
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.ChallengeResponseHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
|
||||
@@ -193,6 +196,9 @@ import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.StartScanning
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetItemHiddenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.ServerboundUpdateRidingStateHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.RequestStarterScreenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.SelectStarterPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.BenchMoveHandler
|
||||
@@ -202,6 +208,12 @@ import com.cobblemon.mod.common.net.serverhandling.storage.SwapPCPartyPokemonHan
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.MovePartyPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.ReleasePCPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.SwapPartyPokemonHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.form.AddFormPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.form.ClearFormsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.form.RemoveFormPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.form.AcceptFormPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.form.RevertFormPacket
|
||||
import com.cobblemon.mod.common.net.serverhandling.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
|
||||
@@ -265,6 +277,13 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(DmaxLevelUpdatePacket.ID, DmaxLevelUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(GmaxFactorUpdatePacket.ID, GmaxFactorUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(CosmeticItemUpdatePacket.ID, CosmeticItemUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(ActiveMarkUpdatePacket.ID, ActiveMarkUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkAddUpdatePacket.ID, MarkAddUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkRemoveUpdatePacket.ID, MarkRemoveUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkPotentialAddUpdatePacket.ID, MarkPotentialAddUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarksUpdatePacket.ID, MarksUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarksPotentialUpdatePacket.ID, MarksPotentialUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkingsUpdatePacket.ID, MarkingsUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
|
||||
// Evolution start
|
||||
list.add(PacketRegisterInfo(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler()))
|
||||
@@ -357,6 +376,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(FishingBaitRegistrySyncPacket.ID, FishingBaitRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(FlowRegistrySyncPacket.ID, FlowRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(CosmeticItemAssignmentSyncPacket.ID, CosmeticItemAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
|
||||
// Effects
|
||||
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
|
||||
@@ -387,6 +407,9 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(PokemonPasturedPacket.ID, PokemonPasturedPacket::decode, PokemonPasturedHandler))
|
||||
list.add(PacketRegisterInfo(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler))
|
||||
|
||||
// Orientation
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, S2CUpdateOrientationHandler))
|
||||
|
||||
// Behaviours
|
||||
list.add(PacketRegisterInfo(PlayPosableAnimationPacket.ID, PlayPosableAnimationPacket::decode, PlayPosableAnimationHandler))
|
||||
|
||||
@@ -410,9 +433,17 @@ object CobblemonNetwork {
|
||||
// Pokédex scanning
|
||||
list.add(PacketRegisterInfo(ServerConfirmedRegisterPacket.ID, ServerConfirmedRegisterPacket::decode, ServerConfirmedRegisterHandler))
|
||||
|
||||
// Form packets
|
||||
list.add(PacketRegisterInfo(AddFormPacket.ID, AddFormPacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(ClearFormsPacket.ID, ClearFormsPacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(RemoveFormPacket.ID, RemoveFormPacket::decode, PokemonUpdatePacketHandler()))
|
||||
|
||||
// Debug / cheats
|
||||
list.add(PacketRegisterInfo(CalculateSeatPositionsPacket.ID, CalculateSeatPositionsPacket::decode, CalculateSeatPositionsHandler))
|
||||
|
||||
// Riding
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
@@ -421,6 +452,8 @@ object CobblemonNetwork {
|
||||
// Pokemon Update Packets
|
||||
list.add(PacketRegisterInfo(SetNicknamePacket.ID, SetNicknamePacket::decode, SetNicknameHandler))
|
||||
list.add(PacketRegisterInfo(SetItemHiddenPacket.ID, SetItemHiddenPacket::decode, SetItemHiddenHandler))
|
||||
list.add(PacketRegisterInfo(SetActiveMarkPacket.ID, SetActiveMarkPacket::decode, SetActiveMarkHandler))
|
||||
list.add(PacketRegisterInfo(SetMarkingsPacket.ID, SetMarkingsPacket::decode, SetMarkingsHandler))
|
||||
|
||||
// Evolution Packets
|
||||
list.add(PacketRegisterInfo(AcceptEvolutionPacket.ID, AcceptEvolutionPacket::decode, AcceptEvolutionHandler))
|
||||
@@ -508,8 +541,13 @@ object CobblemonNetwork {
|
||||
// NPC packets
|
||||
list.add(PacketRegisterInfo(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler))
|
||||
|
||||
// Orientation packet(s)
|
||||
list.add(PacketRegisterInfo(C2SUpdateOrientationPacket.ID, C2SUpdateOrientationPacket::decode, OrientationPacketHandler))
|
||||
// Form Packets
|
||||
list.add(PacketRegisterInfo(AcceptFormPacket.ID, AcceptFormPacket::decode, AcceptFormHandler))
|
||||
list.add(PacketRegisterInfo(RevertFormPacket.ID, RevertFormPacket::decode, RevertFormHandler))
|
||||
|
||||
// Riding packet(s)
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, OrientationPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.abilities
|
||||
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.util.codec.CodecUtils
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
@@ -25,7 +26,7 @@ class AbilityTemplate(
|
||||
var builder: (AbilityTemplate, forced: Boolean, priority: Priority) -> Ability = { template, forced, priority -> Ability(template, forced, priority) },
|
||||
val displayName: String = "cobblemon.ability.$name",
|
||||
val description: String = "cobblemon.ability.$name.desc"
|
||||
) {
|
||||
) : ShowdownIdentifiable {
|
||||
/**
|
||||
* Returns the Ability or if applicable the extension connected to this template
|
||||
*/
|
||||
@@ -45,6 +46,8 @@ class AbilityTemplate(
|
||||
*/
|
||||
fun create(json: JsonObject) = create().loadFromJSON(json)
|
||||
|
||||
override fun showdownId(): String = ShowdownIdentifiable.REGEX.replace(this.name.lowercase(), "")
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -48,9 +48,9 @@ import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.requirements.DefeatRequirement
|
||||
import com.cobblemon.mod.common.pokemon.transformation.progress.DefeatTransformationProgress
|
||||
import com.cobblemon.mod.common.pokemon.transformation.progress.LastBattleCriticalHitsTransformationProgress
|
||||
import com.cobblemon.mod.common.pokemon.transformation.requirements.DefeatRequirement
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.cobblemon.mod.common.util.giveOrDropItemStack
|
||||
@@ -77,7 +77,7 @@ open class PokemonBattle(
|
||||
val side2: BattleSide
|
||||
) {
|
||||
/** Whether logging will be silenced for this battle. */
|
||||
var mute = true
|
||||
var mute = false
|
||||
val struct = this.asMoLangValue()
|
||||
val runtime = MoLangRuntime().also { it.environment.query = struct }
|
||||
|
||||
@@ -92,7 +92,7 @@ open class PokemonBattle(
|
||||
actor.battle = this
|
||||
actor.pokemonList.forEach { battlePokemon ->
|
||||
battlePokemon.effectedPokemon.evolutionProxy.current().progress()
|
||||
.filterIsInstance<LastBattleCriticalHitsEvolutionProgress>()
|
||||
.filterIsInstance<LastBattleCriticalHitsTransformationProgress>()
|
||||
.forEach { it.reset() }
|
||||
}
|
||||
}
|
||||
@@ -252,11 +252,12 @@ open class PokemonBattle(
|
||||
val facedFainted = opponentPokemon.facedOpponents.contains(faintedPokemon)
|
||||
val pokemon = opponentPokemon.effectedPokemon
|
||||
if (facedFainted) {
|
||||
// TODO refactor and apply to forms
|
||||
pokemon.lockedEvolutions.forEach { evolution ->
|
||||
evolution.requirements.filterIsInstance<DefeatRequirement>().forEach { defeatRequirement ->
|
||||
if (defeatRequirement.target.matches(faintedPokemon.effectedPokemon)) {
|
||||
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DefeatEvolutionProgress && it.currentProgress().target == defeatRequirement.target }) { DefeatEvolutionProgress() }
|
||||
progress.updateProgress(DefeatEvolutionProgress.Progress(defeatRequirement.target, progress.currentProgress().amount + 1))
|
||||
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DefeatTransformationProgress && it.currentProgress().target == defeatRequirement.target }) { DefeatTransformationProgress() }
|
||||
progress.updateProgress(DefeatTransformationProgress.Progress(defeatRequirement.target, progress.currentProgress().amount + 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.drop
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
class EvolutionItemDropEntry : ItemDropEntry() {
|
||||
val requirements: MutableSet<EvolutionRequirement> = mutableSetOf()
|
||||
val requirements: MutableSet<TransformationRequirement> = mutableSetOf()
|
||||
|
||||
override fun canDrop(pokemon: Pokemon?): Boolean = pokemon != null && requirements.all { it.check(pokemon) }
|
||||
}
|
||||
@@ -20,4 +20,4 @@ interface EntitySideDelegate<T : Entity> {
|
||||
fun tick(entity: T) {}
|
||||
fun onSyncedDataUpdated(data: EntityDataAccessor<*>) {}
|
||||
fun addToStruct(struct: QueryStruct) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,4 +21,6 @@ interface PokemonSideDelegate : EntitySideDelegate<PokemonEntity> {
|
||||
fun updatePostDeath() {}
|
||||
fun handleStatus(status: Byte) {}
|
||||
fun spawnShinyParticle(player: Player) {}
|
||||
}
|
||||
fun positionRider(passenger: Entity, positionUpdater: MoveFunction)
|
||||
fun updateAge(age: Int) {}
|
||||
}
|
||||
|
||||
+13
-1
@@ -8,10 +8,16 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.fishing
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.itemRegistry
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
/**
|
||||
@@ -55,5 +61,11 @@ interface BobberSpawnPokemonEvent {
|
||||
val chosenBucket: SpawnBucket,
|
||||
val bait: ItemStack,
|
||||
val pokemon: PokemonEntity
|
||||
) : BobberSpawnPokemonEvent
|
||||
) : BobberSpawnPokemonEvent {
|
||||
val context = mutableMapOf<String, MoValue>(
|
||||
"chosen_bucket" to ObjectValue(chosenBucket, { it.name }),
|
||||
"bait" to pokemon.level().itemRegistry.wrapAsHolder(bait.item).asMoLangValue(Registries.ITEM),
|
||||
"pokemon_entity" to pokemon.asMoLangValue()
|
||||
)
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -8,10 +8,18 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
data class FossilRevivedEvent (
|
||||
val pokemon: Pokemon,
|
||||
val player: ServerPlayer?
|
||||
)
|
||||
) {
|
||||
val context = mutableMapOf<String, MoValue>(
|
||||
"pokemon" to pokemon.struct,
|
||||
"player" to (player?.asMoLangValue() ?: DoubleValue.ZERO)
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -12,8 +12,8 @@ import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
|
||||
|
||||
/**
|
||||
* Fired when an evolution is accepted.
|
||||
|
||||
+1
-1
@@ -10,8 +10,8 @@ package com.cobblemon.mod.common.api.events.pokemon.evolution
|
||||
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
|
||||
|
||||
/**
|
||||
* Fired after an evolution finishes.
|
||||
|
||||
+2
-2
@@ -8,9 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon.evolution
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.EvolutionDisplay
|
||||
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.transformation.evolution.EvolutionDisplay
|
||||
|
||||
/**
|
||||
* Fired before an evolution is sent to clients.
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon.evolution
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -12,8 +12,8 @@ import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
|
||||
import com.cobblemon.mod.common.util.getBoolean
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,7 @@ import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.FossilRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
|
||||
import com.cobblemon.mod.common.pokemon.transformation.adapters.LegacyItemConditionWrapperAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
|
||||
|
||||
@@ -215,6 +215,7 @@ fun drawPosablePortrait(
|
||||
ageInTicks: Float = 0F,
|
||||
headYaw: Float = 0F,
|
||||
headPitch: Float = 0F,
|
||||
doQuirks: Boolean = true,
|
||||
r: Float = 1F,
|
||||
g: Float = 1F,
|
||||
b: Float = 1F,
|
||||
@@ -240,6 +241,7 @@ fun drawPosablePortrait(
|
||||
context.put(RenderContext.SPECIES, identifier)
|
||||
context.put(RenderContext.ASPECTS, state.currentAspects)
|
||||
context.put(RenderContext.POSABLE_STATE, state)
|
||||
context.put(RenderContext.DO_QUIRKS, doQuirks)
|
||||
|
||||
val renderType = RenderType.entityCutout(texture)
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ abstract class RequestManager<T : ServerPlayerActionRequest> {
|
||||
?: this.getInboundRequest(receiver.uuid, requestID)
|
||||
|
||||
/** Determines whether [player] can receive a [T]. */
|
||||
open fun isBusy(player: ServerPlayer): Boolean = player.isInBattle() || player.isTrading() || player.party().find { it.entity?.isBusy == true } != null
|
||||
open fun isBusy(player: ServerPlayer): Boolean = player.isBusy() || player.isPartyBusy()
|
||||
|
||||
/** Determines if the [target] is a valid interaction request target. */
|
||||
abstract fun isValidInteraction(player: ServerPlayer, target: ServerPlayer): Boolean
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.mark
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.StringRepresentable
|
||||
|
||||
class Mark(
|
||||
identifier: ResourceLocation,
|
||||
val name: String,
|
||||
val description: String,
|
||||
val title: String?,
|
||||
@SerializedName(value = "titleColor", alternate = ["titleColour"])
|
||||
val titleColour: String?,
|
||||
val texture: ResourceLocation,
|
||||
val replace: List<ResourceLocation>?,
|
||||
val group: String?,
|
||||
val chance: Float = 0F,
|
||||
val indexNumber: Int?
|
||||
): StringRepresentable {
|
||||
|
||||
companion object {
|
||||
internal fun decode(buffer: RegistryFriendlyByteBuf): Mark {
|
||||
return Mark(
|
||||
buffer.readIdentifier(),
|
||||
buffer.readString(),
|
||||
buffer.readString(),
|
||||
buffer.readNullable { buffer.readString() },
|
||||
buffer.readNullable { buffer.readString() },
|
||||
buffer.readResourceLocation(),
|
||||
buffer.readNullable { buffer.readList { buffer.readResourceLocation() } },
|
||||
buffer.readNullable { buffer.readString() },
|
||||
buffer.readFloat(),
|
||||
buffer.readNullable { buffer.readInt() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Transient
|
||||
var identifier: ResourceLocation = identifier
|
||||
internal set
|
||||
|
||||
override fun getSerializedName(): String = identifier.toString()
|
||||
|
||||
fun getName(): MutableComponent = name.asTranslated()
|
||||
|
||||
fun getDescription(): MutableComponent = description.asTranslated()
|
||||
|
||||
fun getTitle(name: MutableComponent): MutableComponent {
|
||||
title?.let {
|
||||
try {
|
||||
return if (titleColour != null) it.asTranslated(name.withColor(-1)).withColor(titleColour.toInt(16))
|
||||
else it.asTranslated(name)
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Error parsing titleColor hexadecimal color code for {}", identifier, e)
|
||||
return it.asTranslated(name)
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
fun getChanceGroup(): Pair<String, Float> = Pair(group ?: chance.toString(), chance)
|
||||
|
||||
internal fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeIdentifier(identifier)
|
||||
buffer.writeString(name)
|
||||
buffer.writeString(description)
|
||||
buffer.writeNullable(title) { _, v -> buffer.writeString(v) }
|
||||
buffer.writeNullable(titleColour) { _, v -> buffer.writeString(v) }
|
||||
buffer.writeResourceLocation(texture)
|
||||
buffer.writeNullable(replace) { _, v -> buffer.writeCollection(v) { _, resource -> buffer.writeResourceLocation(resource) } }
|
||||
buffer.writeNullable(group) { _, v -> buffer.writeString(v) }
|
||||
buffer.writeFloat(chance)
|
||||
buffer.writeNullable(indexNumber) { _, v -> buffer.writeInt(v) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.mark
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MarkRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
|
||||
object Marks: JsonDataRegistry<Mark> {
|
||||
|
||||
override val id: ResourceLocation = cobblemonResource("marks")
|
||||
override val type: PackType = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<Marks>()
|
||||
override val typeToken: TypeToken<Mark> = TypeToken.get(Mark::class.java)
|
||||
override val resourcePath: String = "marks"
|
||||
|
||||
override val gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.create()
|
||||
|
||||
private val marks = hashMapOf<ResourceLocation, Mark>()
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, Mark>) {
|
||||
this.marks.clear()
|
||||
data.forEach { (identifier, mark) ->
|
||||
try {
|
||||
mark.identifier = identifier
|
||||
this.marks[identifier] = mark
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Skipped loading the {} mark", identifier, e)
|
||||
}
|
||||
}
|
||||
Cobblemon.LOGGER.info("Loaded {} marks", this.marks.size)
|
||||
this.observable.emit(this)
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
MarkRegistrySyncPacket(this.all()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all loaded [Mark]s.
|
||||
*/
|
||||
fun all() = this.marks.values.toList()
|
||||
fun identifiers(): Collection<String> = marks.keys.toSet().map { it.toString() }
|
||||
|
||||
/**
|
||||
* Gets a [Mark] by its [ResourceLocation].
|
||||
* @param identifier The identifier of the mark.
|
||||
* @return The [Mark] if loaded, otherwise null.
|
||||
*/
|
||||
fun getByIdentifier(identifier: ResourceLocation): Mark? = this.marks[identifier]
|
||||
}
|
||||
@@ -17,31 +17,19 @@ import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonUnlockableWallpapers
|
||||
import com.cobblemon.mod.common.*
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.dialogue.PlayerDialogueFaceProvider
|
||||
import com.cobblemon.mod.common.api.dialogue.ReferenceDialogueFaceProvider
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.NPCProvider
|
||||
import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
|
||||
import com.cobblemon.mod.common.api.pokedex.CaughtCount
|
||||
import com.cobblemon.mod.common.api.pokedex.CaughtPercent
|
||||
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
|
||||
import com.cobblemon.mod.common.api.pokedex.PokedexManager
|
||||
import com.cobblemon.mod.common.api.pokedex.SeenCount
|
||||
import com.cobblemon.mod.common.api.pokedex.SeenPercent
|
||||
import com.cobblemon.mod.common.api.pokedex.*
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.storage.PokemonStore
|
||||
@@ -49,11 +37,11 @@ import com.cobblemon.mod.common.api.storage.party.PartyStore
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCPosition
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCStore
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
|
||||
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunctions
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.entity.npc.NPCBattleActor
|
||||
@@ -68,14 +56,12 @@ import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticl
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
|
||||
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
|
||||
import com.cobblemon.mod.common.pokemon.transformation.triggers.ItemInteractionTrigger
|
||||
import com.cobblemon.mod.common.pokemon.transformation.triggers.LevelUpTrigger
|
||||
import com.cobblemon.mod.common.pokemon.transformation.triggers.TradeTrigger
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.mojang.datafixers.util.Either
|
||||
import java.util.UUID
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.client.multiplayer.ClientLevel
|
||||
import net.minecraft.commands.arguments.EntityAnchorArgument
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Holder
|
||||
@@ -83,11 +69,7 @@ import net.minecraft.core.Registry
|
||||
import net.minecraft.core.RegistryAccess
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.DoubleTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.StringTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.nbt.*
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.MinecraftServer
|
||||
@@ -96,11 +78,7 @@ import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
import net.minecraft.world.damagesource.DamageTypes
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.EntityType
|
||||
import net.minecraft.world.entity.LightningBolt
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.*
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
@@ -112,8 +90,12 @@ import net.minecraft.world.level.Level.ExplosionInteraction
|
||||
import net.minecraft.world.level.biome.Biome
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.dimension.DimensionType
|
||||
import net.minecraft.world.level.levelgen.Heightmap
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.*
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Holds a bunch of useful MoLang trickery that can be used or extended in API
|
||||
@@ -234,6 +216,22 @@ object MoLangFunctions {
|
||||
val z = params.getInt(2)
|
||||
return@put DoubleValue(world.isRainingAt(BlockPos(x, y, z)))
|
||||
}
|
||||
map.put("is_snowing_at") { params ->
|
||||
val x = params.getInt(0)
|
||||
val y = params.getInt(1)
|
||||
val z = params.getInt(2)
|
||||
val blockPos = BlockPos(x, y, z)
|
||||
if (!world.isRaining()) {
|
||||
return@put DoubleValue.ZERO
|
||||
} else if (!world.canSeeSky(blockPos)) {
|
||||
return@put DoubleValue.ZERO
|
||||
} else if (world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, blockPos).getY() > blockPos.getY()) {
|
||||
return@put DoubleValue.ZERO
|
||||
} else {
|
||||
val biome = world.getBiome(blockPos).value() as Biome
|
||||
return@put DoubleValue(biome.getPrecipitationAt(blockPos) == Biome.Precipitation.SNOW)
|
||||
}
|
||||
}
|
||||
map.put("is_chunk_loaded_at") { params ->
|
||||
val x = params.getInt(0)
|
||||
val y = params.getInt(1)
|
||||
@@ -289,16 +287,32 @@ object MoLangFunctions {
|
||||
} as? ServerPlayer
|
||||
val pos = Vec3(x, y, z)
|
||||
|
||||
if (world !is ClientLevel) {
|
||||
val packet = SpawnSnowstormParticlePacket(particle, pos)
|
||||
if (player != null) {
|
||||
packet.sendToPlayer(player)
|
||||
} else {
|
||||
packet.sendToPlayersAround(x, y, z, 64.0, world.dimension())
|
||||
}
|
||||
val packet = SpawnSnowstormParticlePacket(particle, pos)
|
||||
if (player != null) {
|
||||
packet.sendToPlayer(player)
|
||||
} else {
|
||||
val effect = BedrockParticleOptionsRepository.getEffect(particle) ?: return@put DoubleValue.ZERO
|
||||
ParticleStorm.createAtPosition(world, effect, pos).spawn()
|
||||
packet.sendToPlayersAround(x, y, z, 64.0, world.dimension())
|
||||
}
|
||||
}
|
||||
map.put("spawn_pokemon") { params ->
|
||||
val x = params.getInt(0)
|
||||
val y = params.getInt(1)
|
||||
val z = params.getInt(2)
|
||||
val props = params.getString(3).toProperties()
|
||||
|
||||
val pos = BlockPos(x, y, z)
|
||||
|
||||
if (!Level.isInSpawnableBounds(pos)) {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
|
||||
val pokemon = props.createEntity(world)
|
||||
pokemon.moveTo(pos, pokemon.yRot, pokemon.xRot)
|
||||
|
||||
if (world.addFreshEntity(pokemon)) {
|
||||
return@put pokemon.struct
|
||||
} else {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("get_entities_around") { params ->
|
||||
@@ -467,6 +481,7 @@ object MoLangFunctions {
|
||||
map.put("is_sneaking") { _ -> DoubleValue(entity.isShiftKeyDown) }
|
||||
map.put("is_sprinting") { _ -> DoubleValue(entity.isSprinting) }
|
||||
map.put("is_in_water") { _ -> DoubleValue(entity.isUnderWater) }
|
||||
map.put("is_in_rain") { _ -> DoubleValue(entity.isInWaterOrRain && !entity.isInWater) }
|
||||
map.put("is_touching_water_or_rain") { _ -> DoubleValue(entity.isInWaterRainOrBubble) }
|
||||
map.put("is_touching_water") { _ -> DoubleValue(entity.isInWater) }
|
||||
map.put("is_underwater") { DoubleValue(entity.getIsSubmerged()) }
|
||||
@@ -738,6 +753,8 @@ object MoLangFunctions {
|
||||
map.put("npc") { battleActor.entity.struct }
|
||||
} else if (battleActor is PlayerBattleActor) {
|
||||
map.put("player") { battleActor.entity?.asMoLangValue() ?: DoubleValue.ZERO }
|
||||
} else if (battleActor is PokemonBattleActor) {
|
||||
map.put("pokemon") { battleActor.entity?.asMoLangValue() ?: DoubleValue.ZERO }
|
||||
}
|
||||
return@mutableListOf map
|
||||
}
|
||||
@@ -776,6 +793,34 @@ object MoLangFunctions {
|
||||
DoubleValue.ONE
|
||||
}
|
||||
map.put("owner") { pokemon.getOwnerPlayer()?.asMoLangValue() ?: DoubleValue.ZERO }
|
||||
map.put("add_marks") { params ->
|
||||
for (param in params.params) {
|
||||
val identifier = param.asString().asIdentifierDefaultingNamespace()
|
||||
val mark = Marks.getByIdentifier(identifier)
|
||||
if (mark != null) pokemon.exchangeMark(mark, true)
|
||||
}
|
||||
}
|
||||
map.put("add_marks_with_chance") { params ->
|
||||
for (param in params.params) {
|
||||
val identifier = param.asString().asIdentifierDefaultingNamespace()
|
||||
val mark = Marks.getByIdentifier(identifier)
|
||||
mark?.let {
|
||||
val probability = it.chance.coerceIn(0F, 1F) * 100
|
||||
val randomValue = Random.nextDouble(0.0, 100.0)
|
||||
if (randomValue < probability) pokemon.exchangeMark(it, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
map.put("add_potential_marks") { params ->
|
||||
for (param in params.params) {
|
||||
val identifier = param.asString().asIdentifierDefaultingNamespace()
|
||||
val mark = Marks.getByIdentifier(identifier)
|
||||
if (mark != null) pokemon.addPotentialMark(mark)
|
||||
}
|
||||
}
|
||||
map.put("apply_potential_marks") {
|
||||
return@put DoubleValue(pokemon.applyPotentialMarks())
|
||||
}
|
||||
map
|
||||
}
|
||||
)
|
||||
@@ -786,9 +831,15 @@ object MoLangFunctions {
|
||||
map.put("in_battle") { DoubleValue(pokemonEntity.isBattling) }
|
||||
map.put("is_moving") { DoubleValue((pokemonEntity.moveControl as? PokemonMoveControl)?.hasWanted() == true) }
|
||||
map.put("is_flying") { DoubleValue(pokemonEntity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) }
|
||||
map.put("is_gliding") { DoubleValue(pokemonEntity.useRidingAltPose()) }
|
||||
map.put("is_ridden") { DoubleValue(pokemonEntity.hasControllingPassenger()) }
|
||||
map.put("has_aspect") { DoubleValue(it.getString(0) in pokemonEntity.aspects) }
|
||||
map.put("is_pokemon") { DoubleValue.ONE }
|
||||
map.put("is_holding_item") { DoubleValue(!pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).isEmpty) }
|
||||
map.put("is_holding_item") { DoubleValue(!pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).let {
|
||||
it.isEmpty || it.`is`(CobblemonItemTags.WEARABLE_HAT_ITEMS) || it.`is`(CobblemonItemTags.WEARABLE_FACE_ITEMS)
|
||||
}) }
|
||||
map.put("is_wearing_hat") { DoubleValue(pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).`is`(CobblemonItemTags.WEARABLE_HAT_ITEMS)) }
|
||||
map.put("is_wearing_face") { DoubleValue(pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).`is`(CobblemonItemTags.WEARABLE_FACE_ITEMS)) }
|
||||
map
|
||||
}
|
||||
)
|
||||
@@ -1129,16 +1180,15 @@ object MoLangFunctions {
|
||||
|
||||
map.put("result") { evolution.result.asMoLangValue() }
|
||||
|
||||
if (evolution is LevelUpEvolution) {
|
||||
if (evolution.trigger is LevelUpTrigger) {
|
||||
map.put("is_level_up") { DoubleValue.ONE }
|
||||
} else if (evolution is TradeEvolution) {
|
||||
} else if (evolution.trigger is TradeTrigger) {
|
||||
map.put("is_trade") { DoubleValue.ONE }
|
||||
} else if (evolution is ItemInteractionEvolution) {
|
||||
} else if (evolution.trigger is ItemInteractionTrigger) {
|
||||
map.put("is_item") { DoubleValue.ONE }
|
||||
}
|
||||
|
||||
map.put("is_optional") { DoubleValue(evolution.optional) }
|
||||
map.put("consumes_held_item") { DoubleValue(evolution.consumeHeldItem) }
|
||||
|
||||
map
|
||||
}
|
||||
@@ -1435,4 +1485,4 @@ object MoLangFunctions {
|
||||
}
|
||||
}
|
||||
|
||||
fun Either<ResourceLocation, ExpressionLike>.runScript(runtime: MoLangRuntime) = map({ CobblemonScripts.run(it, runtime) }, { it.resolve(runtime) })
|
||||
fun Either<ResourceLocation, ExpressionLike>.runScript(runtime: MoLangRuntime) = map({ CobblemonScripts.run(it, runtime) }, { it.resolve(runtime) })
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
@@ -56,7 +57,7 @@ open class MoveTemplate(
|
||||
val critRatio: Double,
|
||||
val effectChances: Array<Double>,
|
||||
val actionEffect: ActionEffectTimeline?
|
||||
) {
|
||||
) : ShowdownIdentifiable {
|
||||
val struct: MoStruct by lazy {
|
||||
QueryStruct(hashMapOf())
|
||||
.addFunction("name") { StringValue(name) }
|
||||
@@ -192,4 +193,6 @@ open class MoveTemplate(
|
||||
}
|
||||
return this.elementalType
|
||||
}
|
||||
|
||||
override fun showdownId() = ShowdownIdentifiable.REGEX.replace(this.name.lowercase(), "")
|
||||
}
|
||||
|
||||
@@ -19,4 +19,4 @@ interface Decodable {
|
||||
*/
|
||||
fun decode(buffer: RegistryFriendlyByteBuf)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,4 @@ interface Encodable {
|
||||
*/
|
||||
fun encode(buffer: RegistryFriendlyByteBuf)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -6,10 +6,10 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.riding.states
|
||||
package com.cobblemon.mod.common.api.net.serializers
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
object RidingStateSerializer {
|
||||
|
||||
class RunUpToFlightCompositeState(pokemonEntity: PokemonEntity) : CompositeState(pokemonEntity) {
|
||||
var currSpeed: Double = 0.0
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.orientation
|
||||
|
||||
import com.cobblemon.mod.common.util.math.geometry.toDegrees
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.asin
|
||||
|
||||
open class OrientationController(val entity: LivingEntity) {
|
||||
|
||||
companion object {
|
||||
val FORWARDS: Vector3f = Vector3f(0.0f, 0.0f, -1.0f)
|
||||
val UP: Vector3f = Vector3f(0.0f, 1.0f, 0.0f)
|
||||
val LEFT: Vector3f = Vector3f(-1.0f, 0.0f, 0.0f)
|
||||
}
|
||||
|
||||
open var active: Boolean = false
|
||||
|
||||
var orientation: Matrix3f? = null
|
||||
private set
|
||||
|
||||
private var renderOrientationO: Matrix3f? = null
|
||||
private var renderOrientation: Matrix3f? = null
|
||||
|
||||
/** Adding this simply because it irritates me seeing `getActive` when most of this is Java. */
|
||||
fun isActive() = active
|
||||
|
||||
fun updateOrientation(fn: (Matrix3f) -> Matrix3f?) {
|
||||
if (!active) return
|
||||
if (orientation == null) {
|
||||
orientation = Matrix3f()
|
||||
rotate(entity.yRot - 180, entity.xRot, 0f)
|
||||
}
|
||||
orientation = fn(orientation!!)
|
||||
entity.yRot = yaw
|
||||
entity.xRot = pitch
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
orientation = null
|
||||
renderOrientationO = null
|
||||
renderOrientation = null
|
||||
active = false
|
||||
}
|
||||
|
||||
fun rotate(yaw: Float, pitch: Float, roll: Float) {
|
||||
rotateYaw(yaw)
|
||||
rotatePitch(pitch)
|
||||
rotateRoll(roll)
|
||||
}
|
||||
|
||||
fun getRenderOrientation(delta: Float): Quaternionf {
|
||||
val old = renderOrientationO ?: renderOrientation ?: orientation
|
||||
val new = renderOrientation ?: old
|
||||
val oldQuat = Quaternionf().setFromUnnormalized(old)
|
||||
val newQuat = Quaternionf().setFromUnnormalized(new)
|
||||
oldQuat.slerp(newQuat, delta)
|
||||
return oldQuat
|
||||
}
|
||||
|
||||
fun tick() {
|
||||
if (!active || orientation == null) return
|
||||
renderOrientationO = renderOrientation
|
||||
val current = orientation
|
||||
val renderMatrix = this.renderOrientation ?: current
|
||||
val renderQuat = Quaternionf().setFromUnnormalized(renderMatrix)
|
||||
val targetQuat = Quaternionf().setFromUnnormalized(current)
|
||||
val dampingFactor = 0.66f // We can change this factor for faster transitions
|
||||
renderQuat.slerp(targetQuat, dampingFactor)
|
||||
|
||||
val newRenderOrientation = Matrix3f()
|
||||
renderQuat.get(newRenderOrientation)
|
||||
renderOrientation = newRenderOrientation
|
||||
}
|
||||
|
||||
val forwardVector: Vector3f
|
||||
get() = orientation?.transform(FORWARDS, Vector3f()) ?: Vector3f(FORWARDS)
|
||||
|
||||
val leftVector: Vector3f
|
||||
get() = orientation?.transform(LEFT, Vector3f()) ?: Vector3f(LEFT)
|
||||
|
||||
val upVector : Vector3f
|
||||
get() = orientation?.transform(UP, Vector3f()) ?: Vector3f(UP)
|
||||
|
||||
fun rotateYaw(yaw: Float) = updateOrientation { it.rotateY(-yaw.toRadians()) }
|
||||
fun rotatePitch(pitch: Float) = updateOrientation { it.rotateX(-pitch.toRadians()) }
|
||||
fun rotateRoll(roll: Float) = updateOrientation { it.rotateZ(-roll.toRadians()) }
|
||||
|
||||
val yaw: Float
|
||||
get() = Mth.wrapDegrees(-FORWARDS.angleSigned(forwardVector, UP).toDegrees() + 180)
|
||||
|
||||
val pitch: Float
|
||||
get() = Mth.wrapDegrees(-asin(forwardVector.y).toDegrees())
|
||||
|
||||
val roll: Float
|
||||
get() = Mth.wrapDegrees(-upVector.angleSigned(UP, forwardVector).toDegrees())
|
||||
|
||||
fun applyGlobalYaw(deltaYawDegrees: Float) = updateOrientation { original ->
|
||||
val euler = Vector3f()
|
||||
original.getEulerAnglesXYZ(euler)
|
||||
val pitch0 = euler.x
|
||||
val roll0 = euler.z
|
||||
|
||||
val unroll = Matrix3f().rotateZ(-roll0)
|
||||
val unpitch = Matrix3f().rotateX(-pitch0)
|
||||
val flattened = Matrix3f(original).mul(unroll).mul(unpitch)
|
||||
|
||||
//Flip to reflect current acceptance of what direction is pos for yaw
|
||||
val globalYaw = Matrix3f().rotationY(-1.0f * deltaYawDegrees.toRadians())
|
||||
val rePitch = Matrix3f().rotateX(pitch0)
|
||||
val reRoll = Matrix3f().rotateZ(roll0)
|
||||
|
||||
return@updateOrientation Matrix3f(globalYaw).mul(flattened).mul(rePitch).mul(reRoll)
|
||||
}
|
||||
|
||||
}
|
||||
+9
-2
@@ -20,7 +20,7 @@ object CobblemonPermissions {
|
||||
@JvmStatic
|
||||
val CHANGE_WALK_SPEED = this.create("${COMMAND_PREFIX}changewalkspeed", PermissionLevel.ALL_COMMANDS)
|
||||
@JvmStatic
|
||||
val CHANGE_JOINT_SCALE = this.create("${COMMAND_PREFIX}changejointscale", PermissionLevel.ALL_COMMANDS)
|
||||
val TRANSFORM_MODEL_PART = this.create("${COMMAND_PREFIX}transformmodelpart", PermissionLevel.ALL_COMMANDS)
|
||||
@JvmStatic
|
||||
val CHECKSPAWNS = this.create("${COMMAND_PREFIX}checkspawns", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
@@ -90,6 +90,9 @@ object CobblemonPermissions {
|
||||
@JvmStatic
|
||||
val HELD_ITEM = this.create("${COMMAND_PREFIX}helditem", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
@JvmStatic
|
||||
val CHANGE_MARK = this.create("${COMMAND_PREFIX}changemark", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
@JvmStatic
|
||||
val PC = this.create("${COMMAND_PREFIX}pc", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
@@ -128,8 +131,12 @@ object CobblemonPermissions {
|
||||
val RUN_MOLANG_SCRIPT = this.create("${COMMAND_PREFIX}runmolangscript", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
val COBBLEMON_CONFIG_RELOAD = this.create("${COMMAND_PREFIX}cobblemonconfig.reload", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
@JvmStatic
|
||||
val CALCULATE_SEAT_POSITIONS = this.create("${COMMAND_PREFIX}calculateseatpositions", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
val CHANGE_BOX_COUNT = this.create("${COMMAND_PREFIX}boxcount", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
val SPECTATE_BATTLE = this.create("${COMMAND_PREFIX}spectatebattle", PermissionLevel.ALL_COMMANDS)
|
||||
|
||||
fun all(): Iterable<Permission> = this.permissions
|
||||
|
||||
|
||||
+6
-6
@@ -77,18 +77,18 @@ object CatchRateModifiers {
|
||||
|
||||
/**
|
||||
* Used by [PokeBalls.MOON_BALL].
|
||||
* Boosts the catch rate 1.5× during Moon Phases 3 and 7 between the times of 12000 – 24000.
|
||||
* 2.5× during Moon Phases 2 and 8 between the times of 12000 – 24000.
|
||||
* 4× during Moon Phase 1 between the times of 12000 – 24000.
|
||||
* Boosts the catch rate 1.5× during Moon Phases 2 and 6 between the times of 12000 – 24000.
|
||||
* 2.5× during Moon Phases 1 and 7 between the times of 12000 – 24000.
|
||||
* 4× during Moon Phase 0 between the times of 12000 – 24000.
|
||||
* 1× otherwise.
|
||||
*/
|
||||
val MOON_PHASES: CatchRateModifier = WorldStateModifier { _, entity ->
|
||||
if (entity.level().gameTime in 12000..24000)
|
||||
return@WorldStateModifier 1F
|
||||
when (entity.level().moonPhase) {
|
||||
3, 7 -> 1.5F
|
||||
2, 8 -> 2.5F
|
||||
1 -> 4F
|
||||
2, 6 -> 1.5F
|
||||
1, 7 -> 2.5F
|
||||
0 -> 4F
|
||||
else -> 1F
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,29 +466,18 @@ open class PokemonProperties {
|
||||
}
|
||||
|
||||
fun matches(properties: PokemonProperties): Boolean {
|
||||
return properties.asString() == this.asString()
|
||||
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
|
||||
return this.commonMatches(properties) && this.customProperties.containsAll(properties.customProperties)
|
||||
}
|
||||
|
||||
// Undefined properties will match whatever they're compared with
|
||||
private fun commonMatches(pokemon: Pokemon): Boolean {
|
||||
level?.takeIf { it != pokemon.level }?.let { return false }
|
||||
shiny?.takeIf { it != pokemon.shiny }?.let { return false }
|
||||
gender?.takeIf { it != pokemon.gender }?.let { return false }
|
||||
species?.run {
|
||||
try {
|
||||
val species = if (this == "random") {
|
||||
PokemonSpecies.species.random()
|
||||
} else {
|
||||
PokemonSpecies.getByIdentifier(this.asIdentifierDefaultingNamespace()) ?: return@run
|
||||
}
|
||||
if (pokemon.species != species) {
|
||||
return false
|
||||
}
|
||||
} catch (e: ResourceLocationException) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
species?.takeIf { it.asSpecies() != pokemon.species }?.let { return false }
|
||||
nickname?.takeIf { it.string != pokemon.nickname?.string }?.let { return false }
|
||||
form?.takeIf { !it.equals(pokemon.form.name, true) }?.let { return false }
|
||||
form?.takeIf { !it.equals(pokemon.form.formOnlyShowdownId(), true) }?.let { return false }
|
||||
friendship?.takeIf { it != pokemon.friendship }?.let { return false }
|
||||
pokeball?.takeIf { it != pokemon.caughtBall.name.toString() }?.let { return false }
|
||||
nature?.takeIf { it != pokemon.nature.name.toString() }?.let { return false }
|
||||
@@ -527,6 +516,36 @@ open class PokemonProperties {
|
||||
return true
|
||||
}
|
||||
|
||||
// Undefined properties will match whatever they're compared with
|
||||
private fun commonMatches(properties: PokemonProperties): Boolean {
|
||||
level?.takeIf { it != properties.level }?.let { return false }
|
||||
shiny?.takeIf { it != properties.shiny }?.let { return false }
|
||||
gender?.takeIf { it != properties.gender }?.let { return false }
|
||||
species?.takeIf { it.asSpecies() != properties.species?.asSpecies() }?.let { return false }
|
||||
nickname?.takeIf { it.string != properties.nickname?.string }?.let { return false }
|
||||
form?.takeIf { it != properties.form }?.let { return false }
|
||||
friendship?.takeIf { it != properties.friendship }?.let { return false }
|
||||
pokeball?.takeIf { it != properties.pokeball }?.let { return false }
|
||||
nature?.takeIf { it != properties.nature }?.let { return false }
|
||||
ability?.takeIf { it != properties.ability }?.let { return false }
|
||||
status?.takeIf { it != properties.status }?.let { return false }
|
||||
ivs?.forEach{ stat ->
|
||||
if (stat.value != properties.ivs?.get(stat.key)) { return false }
|
||||
}
|
||||
evs?.forEach{ stat ->
|
||||
if (stat.value != properties.evs?.get(stat.key)) { return false }
|
||||
}
|
||||
type?.takeIf { it != properties.type }?.let { return false }
|
||||
teraType?.takeIf { it != properties.teraType }?.let { return false }
|
||||
dmaxLevel?.takeIf { it != properties.dmaxLevel }?.let { return false }
|
||||
gmaxFactor?.takeIf { it != properties.gmaxFactor }?.let { return false }
|
||||
tradeable?.takeIf { it != properties.tradeable }?.let { return false }
|
||||
originalTrainer?.takeIf { it != properties.originalTrainer }?.let{ return false }
|
||||
originalTrainerType?.takeIf { it != properties.originalTrainerType }?.let{ return false }
|
||||
moves?.takeIf { it.any { move -> properties.moves?.none { it == move } == true } }?.let { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO Review the need for this, usage for us is in commands that deviate from the behavior established by multiple Pokémon query equivalent
|
||||
fun isSubSetOf(properties: PokemonProperties): Boolean {
|
||||
level?.takeIf { it != properties.level }?.let { return false }
|
||||
@@ -798,4 +817,15 @@ open class PokemonProperties {
|
||||
return potentialAbility.template.create(false, potentialAbility.priority)
|
||||
}
|
||||
|
||||
private fun String.asSpecies() =
|
||||
try {
|
||||
if (this == "random") {
|
||||
PokemonSpecies.species.random()
|
||||
} else {
|
||||
PokemonSpecies.getByIdentifier(this.asIdentifierDefaultingNamespace())
|
||||
}
|
||||
}
|
||||
catch (e: ResourceLocationException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,8 @@ import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.abilities.AbilityPool
|
||||
import com.cobblemon.mod.common.api.abilities.AbilityTemplate
|
||||
import com.cobblemon.mod.common.api.abilities.CommonAbility
|
||||
import com.cobblemon.mod.common.api.abilities.PotentialAbility
|
||||
import com.cobblemon.mod.common.api.ai.SleepDepth
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
@@ -24,16 +26,17 @@ import com.cobblemon.mod.common.api.moves.adapters.MoveTemplateAdapter
|
||||
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffect
|
||||
import com.cobblemon.mod.common.api.pokemon.effect.adapter.ShoulderEffectAdapter
|
||||
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.PreEvolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.evolution.PreEvolution
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroupAdapter
|
||||
import com.cobblemon.mod.common.api.pokemon.moves.Learnset
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.trigger.TransformationTrigger
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStatDefinition
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
@@ -42,14 +45,20 @@ import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPack
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.SpeciesAdditions
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonEvolutionAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonPreEvolutionAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonRequirementAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
|
||||
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
|
||||
import com.cobblemon.mod.common.pokemon.abilities.SpecialAbility
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.transformation.adapters.*
|
||||
import com.cobblemon.mod.common.pokemon.transformation.form.GigantamaxForm
|
||||
import com.cobblemon.mod.common.pokemon.transformation.form.PermanentForm
|
||||
import com.cobblemon.mod.common.pokemon.transformation.form.StandardForm
|
||||
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
|
||||
import com.cobblemon.mod.common.pokemon.transformation.requirements.HeldItemRequirement
|
||||
import com.cobblemon.mod.common.pokemon.transformation.requirements.MoveSetRequirement
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.adapters.RideControllerAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.RidingBehaviourSettingsAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.ifClient
|
||||
import com.google.common.collect.HashBasedTable
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
@@ -68,6 +77,7 @@ import net.minecraft.world.level.biome.Biome
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.levelgen.structure.Structure
|
||||
import net.minecraft.world.phys.AABB
|
||||
import java.util.NoSuchElementException
|
||||
|
||||
object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
|
||||
@@ -83,10 +93,8 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
.registerTypeAdapter(ExperienceGroup::class.java, ExperienceGroupAdapter)
|
||||
.registerTypeAdapter(EntityDimensions::class.java, EntityDimensionsAdapter)
|
||||
.registerTypeAdapter(Learnset::class.java, LearnsetAdapter)
|
||||
.registerTypeAdapter(Evolution::class.java, CobblemonEvolutionAdapter)
|
||||
.registerTypeAdapter(AABB::class.java, BoxAdapter)
|
||||
.registerTypeAdapter(AbilityPool::class.java, AbilityPoolAdapter)
|
||||
.registerTypeAdapter(EvolutionRequirement::class.java, CobblemonRequirementAdapter)
|
||||
.registerTypeAdapter(PreEvolution::class.java, CobblemonPreEvolutionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(Set::class.java, Evolution::class.java).type, LazySetAdapter(Evolution::class))
|
||||
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
|
||||
@@ -105,8 +113,11 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Structure::class.java).type, StructureLikeConditionAdapter)
|
||||
.registerTypeAdapter(EggGroup::class.java, EggGroupAdapter)
|
||||
.registerTypeAdapter(MobEffect::class.java, RegistryElementAdapter<MobEffect>(BuiltInRegistries::MOB_EFFECT))
|
||||
.registerTypeAdapter(TransformationTrigger::class.java, CobblemonTriggerAdapter)
|
||||
.registerTypeAdapter(TransformationRequirement::class.java, CobblemonRequirementAdapter)
|
||||
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
|
||||
.registerTypeAdapter(RideController::class.java, RideControllerAdapter)
|
||||
.registerTypeAdapter(FormData::class.java, FormAdapter)
|
||||
.registerTypeAdapter(RidingBehaviourSettings::class.java, RidingBehaviourSettingsAdapter)
|
||||
.registerTypeAdapter(RidingStatDefinition::class.java, RidingStatDefinitionAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.disableHtmlEscaping()
|
||||
@@ -125,6 +136,9 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
get() = this.speciesByIdentifier.values
|
||||
val implemented = mutableListOf<Species>()
|
||||
|
||||
val forms: Collection<FormData>
|
||||
get() = this.species.flatMap { it.allForms }
|
||||
|
||||
init {
|
||||
SpeciesAdditions.observable.subscribe {
|
||||
this.species.forEach(Species::initialize)
|
||||
@@ -211,6 +225,11 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
this.speciesByDex.remove(old.resourceIdentifier.namespace, old.nationalPokedexNumber)
|
||||
}
|
||||
this.speciesByDex.put(species.resourceIdentifier.namespace, species.nationalPokedexNumber, species)
|
||||
ifClient {
|
||||
if (species.implemented) {
|
||||
this.implemented.add(species)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,34 +238,18 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
}
|
||||
|
||||
/**
|
||||
* The representation of a [Species] and/or [FormData] in the context of showdown.
|
||||
* The representation of [FormData] in the context of Showdown.
|
||||
* This is intended as a sort of DTO that can be easily converted between JSON and Java/JS objects.
|
||||
*
|
||||
* @param species The [Species] being converted or the base species if the form is not null.
|
||||
* @param form The [FormData] being converted int o species (Showdown considers them species) will be null when dealing with the base form.
|
||||
* @param form The [FormData] being converted into a species (Showdown considers them species).
|
||||
*/
|
||||
@Suppress("unused")
|
||||
internal class ShowdownSpecies(species: Species, form: FormData?) {
|
||||
val num = species.nationalPokedexNumber
|
||||
val name = if (form != null) "${createShowdownName(species)}-${form.name}" else createShowdownName(species)
|
||||
val baseSpecies = if (form != null) createShowdownName(species) else this.name
|
||||
val forme = form?.name
|
||||
// ToDo baseForme
|
||||
val otherFormes = if (form == null && species.forms.isNotEmpty()) species.forms.map { "${this.name}-${it.name}" } else emptyList()
|
||||
val formeOrder = if (form == null && this.otherFormes.isNotEmpty()) arrayListOf(this.name, *this.otherFormes.toTypedArray()) else emptyList()
|
||||
val abilities: Map<String, String> = mapOf(
|
||||
"0" to "No Ability",
|
||||
"1" to "No Ability",
|
||||
"H" to "No Ability",
|
||||
"S" to "No Ability"
|
||||
)
|
||||
val types = (form?.types ?: species.types).map { it.name.replaceFirstChar(Char::uppercase) }
|
||||
val preevo: String? = (form?.preEvolution ?: species.preEvolution)?.let { if (it.form == it.species.standardForm) createShowdownName(it.species) else "${createShowdownName(it.species)}-${it.form.name}" }
|
||||
// For the context of battles the content here doesn't matter whatsoever and due to how PokemonProperties work we can't guarantee an actual specific species is defined.
|
||||
val evos = if ((form?.evolutions ?: species.evolutions).isEmpty()) emptyList() else arrayListOf("")
|
||||
val nfe = this.evos.isNotEmpty()
|
||||
val eggGroups = (form?.eggGroups ?: species.eggGroups).map { it.showdownID }
|
||||
val gender: String? = when (form?.maleRatio ?: species.maleRatio) {
|
||||
internal open class ShowdownSpecies(form: FormData) {
|
||||
val num = form.species.nationalPokedexNumber
|
||||
val name = form.showdownName()
|
||||
val types = form.types.map { it.name.replaceFirstChar(Char::uppercase) }
|
||||
val eggGroups = form.eggGroups.map { it.showdownID }
|
||||
val gender: String? = when (form.maleRatio) {
|
||||
0F -> "F"
|
||||
1F -> "M"
|
||||
-1F, 1.125F -> "N"
|
||||
@@ -254,35 +257,132 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
}
|
||||
val genderRatio = if (this.gender == null)
|
||||
mapOf(
|
||||
"maleRatio" to (form?.maleRatio ?: species.maleRatio),
|
||||
"femaleRation" to (1F - (form?.maleRatio ?: species.maleRatio))
|
||||
"M" to (form.maleRatio),
|
||||
"F" to (1F - (form.maleRatio))
|
||||
) else null
|
||||
val baseStats = mapOf(
|
||||
"hp" to (form?.baseStats?.get(Stats.HP) ?: species.baseStats[Stats.HP] ?: 1),
|
||||
"atk" to (form?.baseStats?.get(Stats.ATTACK) ?: species.baseStats[Stats.ATTACK] ?: 1),
|
||||
"def" to (form?.baseStats?.get(Stats.DEFENCE) ?: species.baseStats[Stats.DEFENCE] ?: 1),
|
||||
"spa" to (form?.baseStats?.get(Stats.SPECIAL_ATTACK) ?: species.baseStats[Stats.SPECIAL_ATTACK] ?: 1),
|
||||
"spd" to (form?.baseStats?.get(Stats.SPECIAL_DEFENCE) ?: species.baseStats[Stats.SPECIAL_DEFENCE] ?: 1),
|
||||
"spe" to (form?.baseStats?.get(Stats.SPEED) ?: species.baseStats[Stats.SPEED] ?: 1)
|
||||
)
|
||||
val heightm = (form?.height ?: species.height) / 10
|
||||
val weightkg = (form?.weight ?: species.weight) / 10
|
||||
val baseStats = Stats.PERMANENT.associateBy({ it.showdownId }, { form.baseStats[it] ?: 1 })
|
||||
val heightm = form.height / 10
|
||||
val weightkg = form.weight / 10
|
||||
// This is ugly, but we already have it hardcoded in the mod anyway
|
||||
val maxHP = if (species.showdownId() == "shedinja") 1 else null
|
||||
val canGigantamax: String? = if (form?.gigantamaxMove != null) form.gigantamaxMove.name else null
|
||||
val cannotDynamax = form?.dynamaxBlocked ?: species.dynamaxBlocked
|
||||
// ToDo battleOnly
|
||||
// ToDo changesFrom
|
||||
val requiredMove = form?.requiredMove
|
||||
val requiredItem = form?.requiredItem
|
||||
val requiredItems = form?.requiredItems
|
||||
val maxHP = if (this.num == 292) 1 else null
|
||||
val cannotDynamax = form.dynamaxBlocked
|
||||
val abilities = form.showdownAbilityMapping()
|
||||
// Common fields exempt from standard forms
|
||||
val baseSpecies = if (form !is StandardForm) form.species.standardForm.showdownName() else null
|
||||
val forme = if (form !is StandardForm) form.name else null
|
||||
|
||||
/**
|
||||
* The following fields are optional and currently omitted
|
||||
*
|
||||
* cosmeticFormes (not needed, we have species features)
|
||||
* addedType (tertiary type [by name or showdownid] added by moves or abilities)
|
||||
* tier (smogon tryhard bs)
|
||||
* doublesTier (smogon tryhard bs)
|
||||
* natDexTier (smogon tryhard bs)
|
||||
* evoType (the evolution method used to evolve from 'prevo'; trade', 'useItem', 'levelMove', 'levelExtra', 'levelFriendship', 'levelHold', 'other')
|
||||
* evoMove (the move [by name or showdownid] used to evolve from 'prevo')
|
||||
* evoLevel (the minimum level required to evolve from 'prevo')
|
||||
* canHatch (flag for baby pokemon)
|
||||
* color (color, value is arbitrary)
|
||||
* tags (flags for filtering pokemon; 'Mega', 'Mythical', 'Sub-Legendary', 'Restricted Legendary', 'Paradox')
|
||||
* unreleasedHidden (whether this pokemon has an unreleased hidden ability)
|
||||
* maleOnlyHidden (whether it is only possible to get the hidden ability on a male pokemon)
|
||||
* gmaxUnreleased (whether this pokemon has an unreleased gmax form)
|
||||
* pokemonGoData (no one cares)
|
||||
*/
|
||||
}
|
||||
|
||||
private fun createShowdownName(species: Species): String {
|
||||
if (species.resourceIdentifier.namespace == Cobblemon.MODID) {
|
||||
return species.name
|
||||
/**
|
||||
* The representation of a [PermanentForm] in the context of Showdown.
|
||||
*
|
||||
* @param form The [PermanentForm] being converted into a species.
|
||||
*/
|
||||
internal open class ShowdownPermanentForm(form: PermanentForm) : ShowdownSpecies(form) {
|
||||
// species this form evolves from
|
||||
val prevo = form.preEvolution?.form?.showdownName()
|
||||
// For the context of battles the content here doesn't matter whatsoever and due to how PokemonProperties work we can't guarantee an actual specific species is defined.
|
||||
val evos = form.evolutions.map { "" }
|
||||
// not fully evolved
|
||||
val nfe = this.evos.isNotEmpty()
|
||||
// whether there is a gmax form to change to
|
||||
val canGigantamax: String? = form.changeableForms.filterIsInstance<GigantamaxForm>().firstOrNull()?.name // TODO id better
|
||||
}
|
||||
|
||||
/**
|
||||
* The representation of a [StandardForm] in the context of Showdown.
|
||||
*
|
||||
* @param form The [StandardForm] being converted into a species.
|
||||
*/
|
||||
internal class ShowdownStandardForm(form: StandardForm) : ShowdownPermanentForm(form) {
|
||||
// list of all forms descending from this base species
|
||||
val otherFormes = form.flattenForms().map { it.showdownName() }
|
||||
// list of forms [by name or showdownid] in the order they appear in game [union of baseSpecies, otherFormes, and cosmeticFormes] with the exception of ending with 'Gmax' forms
|
||||
val formeOrder = if (this.otherFormes.isNotEmpty()) arrayListOf(this.name, *this.otherFormes.toTypedArray()) else null
|
||||
|
||||
// TODO we don't enforce any form order with our Species registration - right now this looks like only a problem with Mega Rayquaza, but investigate changes needed on Showdown's end to enable these lists to be more dynamic
|
||||
}
|
||||
|
||||
/**
|
||||
* The representation of a [TemporaryForm] in the context of Showdown.
|
||||
*
|
||||
* @param form The [TemporaryForm] being converted into a species.
|
||||
*/
|
||||
internal class ShowdownTemporaryForm(form: TemporaryForm) : ShowdownSpecies(form) {
|
||||
// form change can occur during a battle
|
||||
val battleOnly = if (form.battleOnly) form.parentForm.showdownName() else null
|
||||
// form change can occur outside of battle (mutually exclusive with battleOnly)
|
||||
val changesFrom = if (!form.battleOnly) form.parentForm.showdownName() else null
|
||||
// pokemon must know this move to be in this form
|
||||
val requiredMove = form.requirements.filterIsInstance<MoveSetRequirement>().firstOrNull()?.move?.showdownId() // TODO update showdown to support 'requiredMoves'
|
||||
// pokemon must hold one of these item(s) to be in this form
|
||||
val requiredItems = form.requirements.filterIsInstance<HeldItemRequirement>().firstOrNull()?.let { requirement ->
|
||||
try {
|
||||
requirement.itemCondition.items.get().map { BuiltInRegistries.ITEM.getKey(it.value()).path } // TODO held items on showdown are ignorant of namespace
|
||||
}
|
||||
catch (e: NoSuchElementException)
|
||||
{
|
||||
Cobblemon.LOGGER.error("Failed to resolve required held item for ${form.showdownId()}}") // TODO this needs to be done after tags are loaded...
|
||||
null
|
||||
}
|
||||
}
|
||||
return "${species.resourceIdentifier.namespace}:${species.name}"
|
||||
}
|
||||
|
||||
}
|
||||
/** Accommodate for Showdown bullshit. */
|
||||
/*
|
||||
private fun TemporaryForm.showdownParentForm(): Any {
|
||||
if (this.parentOverrides.isNotEmpty())
|
||||
return this.species.standardForm.flattenForms().filter {
|
||||
parentOverrides.contains(it.showdownId())
|
||||
}.map {
|
||||
it.showdownName()
|
||||
}
|
||||
else
|
||||
return parentForm.showdownName()
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructs a mapping of the [PotentialAbility]s belonging to a [FormData] in Showdown identifiable format.
|
||||
*
|
||||
* @return A map of type (numeric for [CommonAbility]s, H for [HiddenAbility], S for [SpecialAbility]) to showdownid.
|
||||
*/
|
||||
private fun FormData.showdownAbilityMapping(): Map<String, String>? {
|
||||
// potential abilities
|
||||
val commonAbilities = this.abilities.filterIsInstance<CommonAbility>()
|
||||
val hiddenAbility = this.abilities.find { it is HiddenAbility }
|
||||
val specialAbility = this.abilities.find { it is SpecialAbility }
|
||||
|
||||
// can have multiple common abilities
|
||||
val abilities = mutableMapOf<String, String>()
|
||||
val mapping: (String, PotentialAbility) -> Unit = { key, ability ->
|
||||
abilities.put(key, ability.template.showdownId())
|
||||
}
|
||||
|
||||
// can only have one hidden and one special ability
|
||||
commonAbilities.forEachIndexed { index, ability -> mapping(index.toString(), ability) }
|
||||
hiddenAbility?.let { ability -> mapping("H", ability) }
|
||||
specialAbility?.let { ability -> mapping("S", ability) }
|
||||
return if (abilities.isEmpty()) null else abilities
|
||||
}
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.aspect
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeature
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
/**
|
||||
* A provider of aspects for a [SpeciesFeature].
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since Feb 12th, 2024
|
||||
*/
|
||||
interface FeatureAspectProvider: AspectProvider {
|
||||
var default: String?
|
||||
var isAspect: Boolean
|
||||
|
||||
/** Returns true if this [aspect] is provided by this provider. */
|
||||
fun matches(aspect: String): Boolean
|
||||
|
||||
/** Creates a [SpeciesFeature] that provides the respective [aspect]. */
|
||||
fun from(aspect: String): SpeciesFeature<*>?
|
||||
|
||||
/** Sets the [aspect] that's provided. */
|
||||
fun set(pokemon: Pokemon, aspect: String)
|
||||
}
|
||||
+2
-2
@@ -24,11 +24,11 @@ interface SingleConditionalAspectProvider : AspectProvider {
|
||||
fun getForFeature(name: String): SingleConditionalAspectProvider {
|
||||
return object : SingleConditionalAspectProvider {
|
||||
override val aspect: String = name
|
||||
override fun meetsCondition(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.enabled == true
|
||||
override fun meetsCondition(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.value == true
|
||||
override fun meetsCondition(pokemonProperties: PokemonProperties) = pokemonProperties
|
||||
.customProperties
|
||||
.filterIsInstance<FlagSpeciesFeature>()
|
||||
.any { it.name == name && it.enabled }
|
||||
.any { it.name == name && it.value }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
|
||||
|
||||
/**
|
||||
* Represents an evolution of a [Pokemon] that can only occur during specific actions and with added context.
|
||||
* For the default implementations see [ItemInteractionEvolution] & [TradeEvolution].
|
||||
*
|
||||
* @param RC The context given at runtime when querying the [Evolution].
|
||||
* @param TC The context that is serialized from JSON during species loading, this is what the [RC] is expected to match against.
|
||||
* @author Licious
|
||||
* @since March 19th, 2022
|
||||
*/
|
||||
interface ContextEvolution<RC, TC> : Evolution {
|
||||
|
||||
/**
|
||||
* The target context for this [Evolution] to even be tested.
|
||||
*/
|
||||
val requiredContext: TC
|
||||
|
||||
/**
|
||||
* Attempts to evolve the given [Pokemon] under the given context of type [RC].
|
||||
*
|
||||
* @param pokemon The [Pokemon] attempting to evolve.
|
||||
* @param context The context of this query.
|
||||
* @return If the evolution was successful.
|
||||
*/
|
||||
fun attemptEvolution(pokemon: Pokemon, context: RC): Boolean {
|
||||
if (this.testContext(pokemon, context) && super.test(pokemon)) {
|
||||
return super.evolve(pokemon)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given context is valid for the [requiredContext].
|
||||
*
|
||||
* @param pokemon The [Pokemon] attempting to evolve.
|
||||
* @param context The context of this query.
|
||||
* @return If the context matched the [requiredContext].
|
||||
*/
|
||||
fun testContext(pokemon: Pokemon, context: RC): Boolean
|
||||
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.progress.EvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.evolution.controller.ClientEvolutionController
|
||||
import com.cobblemon.mod.common.pokemon.evolution.controller.ServerEvolutionController
|
||||
|
||||
/**
|
||||
* Responsible for holding all available [EvolutionLike]s in the [Pokemon].
|
||||
* Also handles all the networking behind them.
|
||||
* For the Cobblemon default implementations see [ClientEvolutionController] & [ServerEvolutionController].
|
||||
*
|
||||
* @author Licious
|
||||
* @since April 28th, 2022
|
||||
*/
|
||||
interface EvolutionController<T : EvolutionLike, out I : PreProcessor> : MutableSet<T> {
|
||||
|
||||
/**
|
||||
* Resolves the [Pokemon] attached to this controller.
|
||||
*
|
||||
* @return The [Pokemon] this controller is attached to.
|
||||
*/
|
||||
fun pokemon(): Pokemon
|
||||
|
||||
/**
|
||||
* Starts the given evolution on this controller.
|
||||
* All the necessary networking will be handled.
|
||||
*
|
||||
* @param evolution The [EvolutionLike] starting.
|
||||
*/
|
||||
fun start(evolution: T)
|
||||
|
||||
/**
|
||||
* Returns an immutable collection of [EvolutionProgress]es attached to this controller.
|
||||
*
|
||||
* @return The currently tracked [EvolutionProgress]es.
|
||||
*/
|
||||
fun progress(): Collection<EvolutionProgress<*>>
|
||||
|
||||
/**
|
||||
* Attaches a [EvolutionProgress] to this controller.
|
||||
*
|
||||
* @param P The type of [EvolutionProgress].
|
||||
* @param progress The [EvolutionProgress] being attached for tracking.
|
||||
* @return The instance being tracked.
|
||||
*/
|
||||
fun <P : EvolutionProgress<*>> trackProgress(progress: P): P
|
||||
|
||||
/**
|
||||
* Attempts to find an [EvolutionProgress] in [progress] or creates and tracks using [trackProgress].
|
||||
*
|
||||
* @param P The type of [EvolutionProgress].
|
||||
* @param predicate The lambda attempting to find specific progress. This needs to ensure the [EvolutionProgress] is of type [P] or the cast will fail.
|
||||
* @param progressFactory The lambda creating a new instance of type [P] if [predicate] can't find an element.
|
||||
* @return The found match in [progress] or the created and now tracked with [trackProgress].
|
||||
*/
|
||||
fun <P : EvolutionProgress<*>> progressFirstOrCreate(predicate: (progress: EvolutionProgress<*>) -> Boolean, progressFactory: () -> P): P
|
||||
|
||||
fun asIntermediate(): I
|
||||
|
||||
}
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.evolution.CobblemonEvolutionDisplay
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
|
||||
/**
|
||||
* Represents an evolution of a [Pokemon], this is the client side counterpart of [Evolution].
|
||||
* This has no attachments to any data regarding the evolution itself and only serves for display purposes and basic communication.
|
||||
*
|
||||
* @author Licious
|
||||
* @since April 28th, 2022
|
||||
*/
|
||||
interface EvolutionDisplay : EvolutionLike {
|
||||
|
||||
/**
|
||||
* The [Species] of the evolution result.
|
||||
*/
|
||||
val species: Species
|
||||
|
||||
/**
|
||||
* The aspects of the evolution result.
|
||||
* These are used by the client to resolve the entity it needs to display.
|
||||
*/
|
||||
val aspects: Set<String>
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
val CODEC: Codec<EvolutionDisplay> = RecordCodecBuilder.create { instance ->
|
||||
instance.group(
|
||||
Codec.STRING.fieldOf("id").forGetter(EvolutionDisplay::id),
|
||||
Species.BY_IDENTIFIER_CODEC.fieldOf("species").forGetter(EvolutionDisplay::species),
|
||||
Codec.list(Codec.STRING).fieldOf("aspects").forGetter { it.aspects.toList() }
|
||||
).apply(instance) { id, species, aspects -> CobblemonEvolutionDisplay(id, species, aspects.toSet()) }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution
|
||||
|
||||
/**
|
||||
* Responsible for holding the different [EvolutionController] implementations based on the logical side.
|
||||
* If you haven't already checked your side previously you can use [isClient].
|
||||
*
|
||||
* @param C The type of [EvolutionLike] on the client side.
|
||||
* @param S The type of [EvolutionLike] on the server side.
|
||||
* @param CI The type of [PreProcessor] on the client side.
|
||||
* @param SI The type of [PreProcessor] on the server side.
|
||||
*
|
||||
* @author Licious
|
||||
* @since June 18th, 2022
|
||||
*/
|
||||
interface EvolutionProxy<C : EvolutionLike, S : EvolutionLike, CI : PreProcessor, SI : PreProcessor> {
|
||||
|
||||
/**
|
||||
* Checks if the current logical side is the client.
|
||||
*
|
||||
* @return True if the current logical side is the client.
|
||||
*/
|
||||
fun isClient(): Boolean
|
||||
|
||||
/**
|
||||
* Returns the current [EvolutionController].
|
||||
* Keep in mind this will have type erasure and as such most operations will not be possible.
|
||||
* It's recommended to work with [client] or [server] when possible.
|
||||
*
|
||||
* @return The current [EvolutionController].
|
||||
*/
|
||||
fun current(): EvolutionController<out EvolutionLike, *>
|
||||
|
||||
/**
|
||||
* The client side implementation of the [EvolutionController].
|
||||
*
|
||||
* @throws [ClassCastException] if called from the server side.
|
||||
*
|
||||
* @return The client side implementation of the [EvolutionController] if possible.
|
||||
*/
|
||||
fun client(): EvolutionController<C, CI>
|
||||
|
||||
/**
|
||||
* The server side implementation of the [EvolutionController].
|
||||
*
|
||||
* @throws [ClassCastException] if called from the client side.
|
||||
*
|
||||
* @return The server side implementation of the [EvolutionController] if possible.
|
||||
*/
|
||||
fun server(): EvolutionController<S, SI>
|
||||
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
|
||||
|
||||
/**
|
||||
* Represents an evolution of a [Pokemon] that can occur without any additional context or actions.
|
||||
* For the default implementation see [LevelUpEvolution].
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 19th, 2022
|
||||
*/
|
||||
interface PassiveEvolution : Evolution {
|
||||
|
||||
/**
|
||||
* Checks if the given [Pokemon] satisfies the requirements.
|
||||
* If yes the evolution will attempt to start.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being tested.
|
||||
* @return If the [Pokemon] will evolve.
|
||||
*/
|
||||
fun attemptEvolution(pokemon: Pokemon): Boolean {
|
||||
if (super.test(pokemon)) {
|
||||
return super.evolve(pokemon)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* If the evolution will disappear once the conditions are no longer met.
|
||||
*/
|
||||
val permanent: Boolean
|
||||
|
||||
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonEvolutionAdapter
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonSerializer
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Saves and loads [Evolution]s with JSON.
|
||||
* For the default implementation see [CobblemonEvolutionAdapter].
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 20th, 2022
|
||||
*/
|
||||
interface EvolutionAdapter : JsonDeserializer<Evolution>, JsonSerializer<Evolution> {
|
||||
|
||||
/**
|
||||
* Registers the given type of [Evolution] to it's associated ID for deserialization.
|
||||
*
|
||||
* @param T The type of [Evolution].
|
||||
* @param id The id of the evolution event.
|
||||
* @param type The [KClass] of the type.
|
||||
*/
|
||||
fun <T : Evolution> registerType(id: String, type: KClass<T>)
|
||||
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonRequirementAdapter
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonSerializer
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Saves and loads [EvolutionRequirement]s with JSON.
|
||||
* For the default implementation see [CobblemonRequirementAdapter].
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 21st, 2022
|
||||
*/
|
||||
interface RequirementAdapter : JsonDeserializer<EvolutionRequirement>, JsonSerializer<EvolutionRequirement> {
|
||||
|
||||
/**
|
||||
* Registers the given type of [EvolutionRequirement] to it's associated ID for deserialization.
|
||||
*
|
||||
* @param T The type of [EvolutionRequirement].
|
||||
* @param id The id of the evolution event.
|
||||
* @param type The [KClass] of the type.
|
||||
*/
|
||||
fun <T : EvolutionRequirement> registerType(id: String, type: KClass<T>)
|
||||
|
||||
}
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution.progress
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.evolution.controller.ServerEvolutionController
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.Lifecycle
|
||||
import net.minecraft.core.MappedRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import kotlin.jvm.Throws
|
||||
|
||||
object EvolutionProgressTypes {
|
||||
|
||||
private val REGISTRY: Registry<EvolutionProgressType<*>> = MappedRegistry(
|
||||
ResourceKey.createRegistryKey(cobblemonResource("evolution_progress")), Lifecycle.stable()
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
val DAMAGE_TAKEN = this.registerType(DamageTakenEvolutionProgress.ID, EvolutionProgressType(DamageTakenEvolutionProgress.CODEC))
|
||||
@JvmStatic
|
||||
val DEFEAT = this.registerType(DefeatEvolutionProgress.ID, EvolutionProgressType(DefeatEvolutionProgress.CODEC))
|
||||
@JvmStatic
|
||||
val LAST_BATTLE_CRITICAL_HITS = this.registerType(LastBattleCriticalHitsEvolutionProgress.ID, EvolutionProgressType(LastBattleCriticalHitsEvolutionProgress.CODEC))
|
||||
@JvmStatic
|
||||
val RECOIL = this.registerType(RecoilEvolutionProgress.ID, EvolutionProgressType(RecoilEvolutionProgress.CODEC))
|
||||
@JvmStatic
|
||||
val USE_MOVE = this.registerType(UseMoveEvolutionProgress.ID, EvolutionProgressType(UseMoveEvolutionProgress.CODEC))
|
||||
|
||||
/**
|
||||
* Registers an evolution progress.
|
||||
*
|
||||
* @param T The type of the [EvolutionProgress].
|
||||
* @param id The [Identifier].
|
||||
* @param type The [EvolutionProgressType] record.
|
||||
* @return The registered [EvolutionProgressType] of type [T].
|
||||
*
|
||||
* @throws [IllegalStateException] if [Registry.register] fails.
|
||||
*/
|
||||
@Throws(IllegalStateException::class)
|
||||
@JvmStatic
|
||||
fun <T : EvolutionProgress<*>> registerType(id: ResourceLocation, type: EvolutionProgressType<T>): EvolutionProgressType<T> {
|
||||
return Registry.register(REGISTRY, id, type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a codec instance of this registry.
|
||||
*
|
||||
* @return The generated [Codec] of [EvolutionProgress].
|
||||
*/
|
||||
fun codec(): Codec<EvolutionProgress<*>> = REGISTRY.byNameCodec().dispatch(
|
||||
ServerEvolutionController.ID_KEY,
|
||||
{ it.type() },
|
||||
{ it.codec }
|
||||
)
|
||||
|
||||
}
|
||||
+1
-1
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.pokemon.OriginalTrainerType
|
||||
import com.cobblemon.mod.common.pokemon.evolution.requirements.LevelRequirement
|
||||
import com.cobblemon.mod.common.pokemon.transformation.requirements.LevelRequirement
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
+29
-5
@@ -9,7 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.feature
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.FeatureAspectProvider
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
|
||||
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
@@ -29,11 +29,11 @@ import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
*/
|
||||
open class ChoiceSpeciesFeatureProvider(
|
||||
override var keys: List<String>,
|
||||
var default: String? = null,
|
||||
override var default: String? = null,
|
||||
var choices: List<String> = listOf(),
|
||||
var isAspect: Boolean = true,
|
||||
override var isAspect: Boolean = true,
|
||||
var aspectFormat: String = "{{choice}}"
|
||||
) : SynchronizedSpeciesFeatureProvider<StringSpeciesFeature>, CustomPokemonPropertyType<StringSpeciesFeature>, AspectProvider {
|
||||
) : SynchronizedSpeciesFeatureProvider<StringSpeciesFeature>, CustomPokemonPropertyType<StringSpeciesFeature>, FeatureAspectProvider {
|
||||
override var needsKey = true
|
||||
override var visible = false
|
||||
fun getAspect(feature: StringSpeciesFeature) = aspectFormat.substitute("choice", feature.value)
|
||||
@@ -76,6 +76,28 @@ open class ChoiceSpeciesFeatureProvider(
|
||||
return aspects
|
||||
}
|
||||
|
||||
fun parseValue(aspect: String): String? {
|
||||
if (!matches(aspect)) return null
|
||||
val head = aspectFormat.substringBefore("{{choice}}")
|
||||
val tail = aspectFormat.substringAfter("{{choice}}").takeIf { it.isNotBlank() }
|
||||
|
||||
var value = aspect.substringAfter(head)
|
||||
tail?.let { value = value.substringBefore(it) }
|
||||
return value
|
||||
}
|
||||
|
||||
override fun matches(aspect: String): Boolean = this.isAspect && this.getAllAspects().contains(aspect)
|
||||
|
||||
override fun from(aspect: String): SpeciesFeature<*>? {
|
||||
val value = parseValue(aspect)
|
||||
return if (value != null && choices.contains(value)) this.fromString(value) else null
|
||||
}
|
||||
|
||||
override fun set(pokemon: Pokemon, aspect: String) {
|
||||
val value = parseValue(aspect)
|
||||
if (value != null && choices.contains(value)) this.get(pokemon)?.value = value
|
||||
}
|
||||
|
||||
override fun examples() = choices
|
||||
|
||||
internal constructor(): this(emptyList())
|
||||
@@ -123,7 +145,9 @@ open class ChoiceSpeciesFeatureProvider(
|
||||
|
||||
override fun provide(pokemon: Pokemon): Set<String> {
|
||||
return if (isAspect) {
|
||||
get(pokemon)?.let { setOf(getAspect(it)) } ?: emptySet()
|
||||
get(pokemon)?.let {
|
||||
setOf(getAspect(it))
|
||||
} ?: emptySet()
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
|
||||
+30
-21
@@ -9,7 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.feature
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.FeatureAspectProvider
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
|
||||
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
|
||||
@@ -30,65 +30,74 @@ import kotlin.random.Random
|
||||
* @author Hiroku
|
||||
* @since May 13th, 2022
|
||||
*/
|
||||
open class FlagSpeciesFeature(override val name: String) : SynchronizedSpeciesFeature, CustomPokemonProperty {
|
||||
open class FlagSpeciesFeature(override val name: String) : SynchronizedSpeciesFeature<Boolean>, CustomPokemonProperty {
|
||||
constructor(name: String, enabled: Boolean): this(name) {
|
||||
this.enabled = enabled
|
||||
this.value = enabled
|
||||
}
|
||||
|
||||
var enabled = false
|
||||
override var value: Boolean = false
|
||||
override fun saveToNBT(pokemonNBT: CompoundTag): CompoundTag {
|
||||
pokemonNBT.putBoolean(name, enabled)
|
||||
pokemonNBT.putBoolean(name, value)
|
||||
return pokemonNBT
|
||||
}
|
||||
|
||||
override fun loadFromNBT(pokemonNBT: CompoundTag): SpeciesFeature {
|
||||
enabled = if (pokemonNBT.contains(name)) pokemonNBT.getBoolean(name) else enabled
|
||||
override fun loadFromNBT(pokemonNBT: CompoundTag): SpeciesFeature<Boolean> {
|
||||
value = if (pokemonNBT.contains(name)) pokemonNBT.getBoolean(name) else value
|
||||
return this
|
||||
}
|
||||
|
||||
override fun saveToJSON(pokemonJSON: JsonObject): JsonObject {
|
||||
pokemonJSON.addProperty(name, enabled)
|
||||
pokemonJSON.addProperty(name, value)
|
||||
return pokemonJSON
|
||||
}
|
||||
|
||||
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature {
|
||||
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature<Boolean> {
|
||||
val isEnabled = pokemonJSON.get(name)?.asBoolean
|
||||
enabled = isEnabled ?: this.enabled
|
||||
value = isEnabled ?: this.value
|
||||
return this
|
||||
}
|
||||
|
||||
override fun saveToBuffer(buffer: RegistryFriendlyByteBuf, toClient: Boolean) {
|
||||
buffer.writeBoolean(enabled)
|
||||
buffer.writeBoolean(value)
|
||||
}
|
||||
|
||||
override fun loadFromBuffer(buffer: RegistryFriendlyByteBuf) {
|
||||
enabled = buffer.readBoolean()
|
||||
value = buffer.readBoolean()
|
||||
}
|
||||
|
||||
override fun asString() = "$name=$enabled"
|
||||
override fun asString() = "$name=$value"
|
||||
|
||||
override fun apply(pokemon: Pokemon) {
|
||||
val featureProvider = SpeciesFeatures.getFeature(name) ?: return
|
||||
if (featureProvider in SpeciesFeatures.getFeaturesFor(pokemon.species)) {
|
||||
val existingFeature = pokemon.getFeature<FlagSpeciesFeature>(name)
|
||||
if (existingFeature != null) {
|
||||
existingFeature.enabled = enabled
|
||||
existingFeature.value = value
|
||||
} else {
|
||||
pokemon.features.add(FlagSpeciesFeature(name, enabled))
|
||||
pokemon.features.add(FlagSpeciesFeature(name, value))
|
||||
}
|
||||
pokemon.updateAspects()
|
||||
}
|
||||
}
|
||||
|
||||
override fun matches(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.enabled == enabled
|
||||
override fun matches(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.value == value
|
||||
}
|
||||
|
||||
class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpeciesFeature>, CustomPokemonPropertyType<FlagSpeciesFeature>, AspectProvider {
|
||||
class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpeciesFeature>, CustomPokemonPropertyType<FlagSpeciesFeature>, FeatureAspectProvider {
|
||||
override var keys: List<String> = emptyList()
|
||||
// Uses get() = true because that way there's no backing field. It MUST be true, this way no JSON trickery will overwrite it
|
||||
override val needsKey get() = true
|
||||
var default: String? = null
|
||||
var isAspect = true
|
||||
override var default: String? = null
|
||||
override var isAspect = true
|
||||
|
||||
override fun matches(aspect: String): Boolean = this.isAspect && this.keys.first() == aspect
|
||||
|
||||
override fun from(aspect: String): SpeciesFeature<*>? = if (matches(aspect)) fromString(null) else null
|
||||
|
||||
override fun set(pokemon: Pokemon, aspect: String) {
|
||||
this.get(pokemon)?.value = true
|
||||
}
|
||||
|
||||
override var visible: Boolean = false
|
||||
|
||||
override fun invoke(buffer: RegistryFriendlyByteBuf, name: String): FlagSpeciesFeature? {
|
||||
@@ -170,7 +179,7 @@ class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpecie
|
||||
}
|
||||
|
||||
override fun provide(pokemon: Pokemon): Set<String> {
|
||||
return if (isAspect && pokemon.getFeature<FlagSpeciesFeature>(keys.first())?.enabled == true) {
|
||||
return if (isAspect && pokemon.getFeature<FlagSpeciesFeature>(keys.first())?.value == true) {
|
||||
setOf(keys.first())
|
||||
} else {
|
||||
emptySet()
|
||||
@@ -178,7 +187,7 @@ class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpecie
|
||||
}
|
||||
|
||||
override fun provide(properties: PokemonProperties): Set<String> {
|
||||
return if (isAspect && properties.customProperties.filterIsInstance<FlagSpeciesFeature>().find { it.name == keys.first() }?.enabled == true) {
|
||||
return if (isAspect && properties.customProperties.filterIsInstance<FlagSpeciesFeature>().find { it.name == keys.first() }?.value == true) {
|
||||
setOf(keys.first())
|
||||
} else {
|
||||
emptySet()
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
|
||||
}
|
||||
|
||||
fun register(name: String, provider: SpeciesFeatureProvider<*>) = register(name, provider, isCoded = true)
|
||||
fun <T : SpeciesFeature> register(name: String, providerLambda: () -> T) {
|
||||
fun <T : SpeciesFeature<*>> register(name: String, providerLambda: () -> T) {
|
||||
register(name, object : SpeciesFeatureProvider<T> {
|
||||
override fun invoke(pokemon: Pokemon) = providerLambda()
|
||||
override fun invoke(nbt: CompoundTag) = providerLambda().apply { loadFromNBT(nbt) }
|
||||
|
||||
+4
-4
@@ -26,8 +26,8 @@ import net.minecraft.world.phys.Vec3
|
||||
* A species feature value that's just an integer. Complex stuff.
|
||||
* @author Hiroku
|
||||
*/
|
||||
class IntSpeciesFeature(override var name: String) : SynchronizedSpeciesFeature, CustomPokemonProperty {
|
||||
var value = 0
|
||||
class IntSpeciesFeature(override var name: String) : SynchronizedSpeciesFeature<Int>, CustomPokemonProperty {
|
||||
override var value = 0
|
||||
|
||||
constructor() : this("")
|
||||
constructor(name: String, value: Int) : this(name) {
|
||||
@@ -39,7 +39,7 @@ class IntSpeciesFeature(override var name: String) : SynchronizedSpeciesFeature,
|
||||
return pokemonNBT
|
||||
}
|
||||
|
||||
override fun loadFromNBT(pokemonNBT: CompoundTag): SynchronizedSpeciesFeature {
|
||||
override fun loadFromNBT(pokemonNBT: CompoundTag): SynchronizedSpeciesFeature<Int> {
|
||||
value = pokemonNBT.getInt(name)
|
||||
return this
|
||||
}
|
||||
@@ -49,7 +49,7 @@ class IntSpeciesFeature(override var name: String) : SynchronizedSpeciesFeature,
|
||||
return pokemonJSON
|
||||
}
|
||||
|
||||
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature {
|
||||
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature<Int> {
|
||||
value = pokemonJSON.get(name).asInt
|
||||
return this
|
||||
}
|
||||
|
||||
+4
-3
@@ -24,10 +24,11 @@ import net.minecraft.nbt.CompoundTag
|
||||
* @author Hiroku
|
||||
* @since May 13th, 2022
|
||||
*/
|
||||
interface SpeciesFeature {
|
||||
interface SpeciesFeature<T> {
|
||||
val name: String
|
||||
var value: T
|
||||
fun saveToNBT(pokemonNBT: CompoundTag): CompoundTag
|
||||
fun loadFromNBT(pokemonNBT: CompoundTag): SpeciesFeature
|
||||
fun loadFromNBT(pokemonNBT: CompoundTag): SpeciesFeature<T>
|
||||
fun saveToJSON(pokemonJSON: JsonObject): JsonObject
|
||||
fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature
|
||||
fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature<T>
|
||||
}
|
||||
+1
-1
@@ -21,7 +21,7 @@ import net.minecraft.nbt.CompoundTag
|
||||
* @author Hiroku
|
||||
* @since November 29th, 2022
|
||||
*/
|
||||
interface SpeciesFeatureProvider<T : SpeciesFeature> {
|
||||
interface SpeciesFeatureProvider<T : SpeciesFeature<*>> {
|
||||
/**
|
||||
* Attempts to create a species feature for the given [Pokemon]. It is appropriate to check for an existing feature
|
||||
* that is compatible with this type and transfer / retain that feature instead of constructing a new one. For example
|
||||
|
||||
+4
-4
@@ -24,14 +24,14 @@ import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
*/
|
||||
class StringSpeciesFeature(
|
||||
override val name: String,
|
||||
var value: String
|
||||
) : SynchronizedSpeciesFeature, CustomPokemonProperty {
|
||||
override var value: String
|
||||
) : SynchronizedSpeciesFeature<String>, CustomPokemonProperty {
|
||||
override fun saveToNBT(pokemonNBT: CompoundTag): CompoundTag {
|
||||
pokemonNBT.putString(name, value)
|
||||
return pokemonNBT
|
||||
}
|
||||
|
||||
override fun loadFromNBT(pokemonNBT: CompoundTag): SpeciesFeature {
|
||||
override fun loadFromNBT(pokemonNBT: CompoundTag): SpeciesFeature<String> {
|
||||
value = pokemonNBT.getString(name)?.takeIf { it.isNotBlank() }?.lowercase() ?: return this
|
||||
return this
|
||||
}
|
||||
@@ -41,7 +41,7 @@ class StringSpeciesFeature(
|
||||
return pokemonJSON
|
||||
}
|
||||
|
||||
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature {
|
||||
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature<String> {
|
||||
value = pokemonJSON.get(name)?.asString?.lowercase() ?: return this
|
||||
return this
|
||||
}
|
||||
|
||||
+1
-1
@@ -16,4 +16,4 @@ import com.cobblemon.mod.common.api.serialization.BufferSerializer
|
||||
* @author Hiroku
|
||||
* @since November 13th, 2023
|
||||
*/
|
||||
interface SynchronizedSpeciesFeature : SpeciesFeature, BufferSerializer
|
||||
interface SynchronizedSpeciesFeature<T> : SpeciesFeature<T>, BufferSerializer
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
* @author Hiroku
|
||||
* @since November 13th, 2023
|
||||
*/
|
||||
interface SynchronizedSpeciesFeatureProvider<T : SynchronizedSpeciesFeature> : SpeciesFeatureProvider<T>, BufferSerializer {
|
||||
interface SynchronizedSpeciesFeatureProvider<T : SynchronizedSpeciesFeature<*>> : SpeciesFeatureProvider<T>, BufferSerializer {
|
||||
var visible: Boolean
|
||||
operator fun invoke(buffer: RegistryFriendlyByteBuf, name: String): T?
|
||||
/** Gets the feature from this Pokémon, if it has been created yet. */
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.controller.TransformationController
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.trigger.ContextTrigger
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.trigger.TransformationTrigger
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
/**
|
||||
* Represents a transformation of a [Pokemon]. This is the server side counterpart of [TransformationDisplay] and serves as
|
||||
* the driver of the transformation. These are triggered by a player-driven or world-driven event.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since Sept 8th, 2023
|
||||
*/
|
||||
interface Transformation : TransformationLike {
|
||||
|
||||
/** The [TransformationTrigger] to attempt this transformation. */
|
||||
val trigger: TransformationTrigger
|
||||
|
||||
/** The [TransformationRequirement]s that need to be satisfied for this transformation. */
|
||||
val requirements: Set<TransformationRequirement>
|
||||
|
||||
/** If this transformation can be deferred by the user and started whenever. */
|
||||
val optional: Boolean
|
||||
|
||||
/** If this transformation needs its requirements reevaluated to remain valid in a [TransformationController]. */
|
||||
val reevaluate: Boolean
|
||||
|
||||
/** Checks if all [TransformationRequirement]s are met. */
|
||||
fun checkRequirements(pokemon: Pokemon) = this.requirements.all { requirement -> requirement.check(pokemon) }
|
||||
|
||||
/**
|
||||
* Tests if the given [Pokemon] passes all the conditions and is ready to transform.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
* @param context The optional [ContextTrigger.Context] needed to transform.
|
||||
* @return Whether the [Transformation] can start.
|
||||
*/
|
||||
fun test(pokemon: Pokemon, context: ContextTrigger.Context?) = this.trigger.testTrigger(context) && this.checkRequirements(pokemon)
|
||||
|
||||
/**
|
||||
* Starts this transformation if conditions are met.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being transformed.
|
||||
* @param context The optional [ContextTrigger.Context] needed to transform.
|
||||
* @return Whether the [Transformation] was successful.
|
||||
*/
|
||||
fun start(pokemon: Pokemon, context: ContextTrigger.Context?): Boolean {
|
||||
if (test(pokemon, context)) {
|
||||
forceStart(pokemon)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts this transformation without evaluating the requirements.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being transformed.
|
||||
*/
|
||||
fun forceStart(pokemon: Pokemon) { this.requirements.forEach { it.fulfill(pokemon) } }
|
||||
|
||||
/**
|
||||
* Converts this transformation to its client side representation.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being transformed.
|
||||
* @return The [TransformationDisplay] representing this transformation on the client.
|
||||
*/
|
||||
fun convertToDisplay(pokemon: Pokemon): TransformationDisplay
|
||||
|
||||
/**
|
||||
* Validates whether a transformation still meets the [TransformationRequirement]s.
|
||||
* If [Transformation.reevaluate] is false, this check will be bypassed.
|
||||
*
|
||||
* @param pokemon the [Pokemon] to test against.
|
||||
* @return Whether this transformation is still valid and can be made for [pokemon].
|
||||
*/
|
||||
fun reevaluate(pokemon: Pokemon) = !this.reevaluate || this.checkRequirements(pokemon)
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
|
||||
/**
|
||||
* Represents a transformation of a [Pokemon], this is the client side counterpart of [Transformation].
|
||||
* This has no attachments to any data regarding the transformation itself and only serves for display purposes and basic communication.
|
||||
*
|
||||
* @author Licious
|
||||
* @since April 28th, 2022
|
||||
*/
|
||||
interface TransformationDisplay : TransformationLike {
|
||||
|
||||
/**
|
||||
* The [Species] of the transformation result.
|
||||
*/
|
||||
val species: Species
|
||||
|
||||
/**
|
||||
* The aspects of the transformation result.
|
||||
* These are used by the client to resolve the entity it needs to display.
|
||||
*/
|
||||
val aspects: Set<String>
|
||||
}
|
||||
+6
-6
@@ -6,20 +6,20 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation
|
||||
|
||||
/**
|
||||
* Represents the base of an evolution.
|
||||
* It can either be the full data container present on the server side [Evolution].
|
||||
* Or the client side representation for display [EvolutionDisplay].
|
||||
* Represents the base of a transformation.
|
||||
* It can either be the full data container present on the server side [Transformation].
|
||||
* Or the client side representation for display [TransformationDisplay].
|
||||
*
|
||||
* @author Licious
|
||||
* @since April 28th, 2022
|
||||
*/
|
||||
interface EvolutionLike {
|
||||
interface TransformationLike {
|
||||
|
||||
/**
|
||||
* The unique id of the evolution.
|
||||
* The unique id of the transformation.
|
||||
* It should be human-readable, I.E pikachu_level
|
||||
*/
|
||||
val id: String
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
|
||||
import com.cobblemon.mod.common.pokemon.transformation.adapters.CobblemonRequirementAdapter
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonSerializer
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Saves and loads [TransformationRequirement]s with JSON.
|
||||
* For the default implementation see [CobblemonRequirementAdapter].
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 21st, 2022
|
||||
*/
|
||||
interface RequirementAdapter : JsonDeserializer<TransformationRequirement>, JsonSerializer<TransformationRequirement> {
|
||||
|
||||
/**
|
||||
* Registers the given type of [TransformationRequirement] to it's associated ID for deserialization.
|
||||
*
|
||||
* @param T The type of [TransformationRequirement].
|
||||
* @param id The id of the evolution event.
|
||||
* @param type The [KClass] of the type.
|
||||
*/
|
||||
fun <T : TransformationRequirement> registerType(id: String, type: KClass<T>)
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.trigger.TransformationTrigger
|
||||
import com.cobblemon.mod.common.pokemon.transformation.adapters.CobblemonTriggerAdapter
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonSerializer
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Saves and loads [TransformationTrigger]s with JSON.
|
||||
* For the default implementation see [CobblemonTriggerAdapter].
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 20th, 2022
|
||||
*/
|
||||
interface TriggerAdapter : JsonDeserializer<TransformationTrigger>, JsonSerializer<TransformationTrigger> {
|
||||
|
||||
/**
|
||||
* Registers the given type of [TransformationTrigger] to it's associated ID for deserialization.
|
||||
*
|
||||
* @param T The type of [TransformationTrigger].
|
||||
* @param id The id of the evolution event.
|
||||
* @param type The [KClass] of the type.
|
||||
*/
|
||||
fun <T : TransformationTrigger> registerType(id: String, type: KClass<T>)
|
||||
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.controller
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.TransformationLike
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.proxy.PreProcessor
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.progress.TransformationProgress
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.transformation.controller.CobblemonClientTransformationController
|
||||
import com.cobblemon.mod.common.pokemon.transformation.controller.CobblemonServerTransformationController
|
||||
|
||||
/**
|
||||
* Responsible for holding all available [TransformationLike]s in the [Pokemon].
|
||||
* Also handles all the networking behind them.
|
||||
* For the Cobblemon default implementations see [CobblemonClientTransformationController] & [CobblemonServerTransformationController].
|
||||
*
|
||||
* @author Licious
|
||||
* @since April 28th, 2022
|
||||
*/
|
||||
interface TransformationController<T : TransformationLike, out I : PreProcessor> : MutableSet<T> {
|
||||
|
||||
/**
|
||||
* Resolves the [Pokemon] attached to this controller.
|
||||
*
|
||||
* @return The [Pokemon] this controller is attached to.
|
||||
*/
|
||||
fun pokemon(): Pokemon
|
||||
|
||||
/**
|
||||
* Starts the given transformation on this controller.
|
||||
* All the necessary networking will be handled.
|
||||
*
|
||||
* @param transformation The [TransformationLike] starting.
|
||||
*/
|
||||
fun start(transformation: T)
|
||||
|
||||
/** Reverts the active [TransformationLike] for this controller's [pokemon]. */
|
||||
fun revert() // TODO dunno if i like this
|
||||
|
||||
/**
|
||||
* Returns an immutable collection of [TransformationProgress]es attached to this controller.
|
||||
*
|
||||
* @return The currently tracked [TransformationProgress]es.
|
||||
*/
|
||||
fun progress(): Collection<TransformationProgress<*>>
|
||||
|
||||
/**
|
||||
* Attaches a [TransformationProgress] to this controller.
|
||||
*
|
||||
* @param P The type of [TransformationProgress].
|
||||
* @param progress The [TransformationProgress] being attached for tracking.
|
||||
* @return The instance being tracked.
|
||||
*/
|
||||
fun <P : TransformationProgress<*>> trackProgress(progress: P): P
|
||||
|
||||
/**
|
||||
* Attempts to find an [TransformationProgress] in [progress] or creates and tracks using [trackProgress].
|
||||
*
|
||||
* @param P The type of [TransformationProgress].
|
||||
* @param predicate The lambda attempting to find specific progress. This needs to ensure the [TransformationProgress] is of type [P] or the cast will fail.
|
||||
* @param progressFactory The lambda creating a new instance of type [P] if [predicate] can't find an element.
|
||||
* @return The found match in [progress] or the created and now tracked with [trackProgress].
|
||||
*/
|
||||
fun <P : TransformationProgress<*>> progressFirstOrCreate(predicate: (progress: TransformationProgress<*>) -> Boolean, progressFactory: () -> P): P
|
||||
|
||||
fun asIntermediate(): I
|
||||
|
||||
/**
|
||||
* Guard for [start] to prevent a transformation from executing while the [pokemon] is busy or if the transformation
|
||||
* is not in the controller.
|
||||
*
|
||||
* @param transformation the [TransformationLike] to validate.
|
||||
* @return whether this controller is capable of starting the transformation.
|
||||
*/
|
||||
fun canStart(transformation: T): Boolean
|
||||
|
||||
/**
|
||||
* Whether this controller is capable of executing [start] for a transformation. This checks if the [pokemon] is busy
|
||||
* or if there is a transformation ready in the controller.
|
||||
*
|
||||
* @return whether this controller is capable of starting a transformation.
|
||||
*/
|
||||
fun canStart(): Boolean
|
||||
|
||||
/**
|
||||
* Validates the [TransformationLike] currently active for this controller's [pokemon] and determines whether it can be
|
||||
* reverted and if the pokemon is capable of reverting right now.
|
||||
*
|
||||
* @return whether the transformation can be reverted.
|
||||
*/
|
||||
fun canRevert(): Boolean
|
||||
|
||||
/**
|
||||
* Retrieves the [TransformationLike] in this controller that matches the provided id.
|
||||
*
|
||||
* @param id the identifier of the transformation.
|
||||
* @return the transformation matching this id.
|
||||
*/
|
||||
fun getById(id: String) = this.firstOrNull { transformation -> transformation.id.equals(id, true) }
|
||||
}
|
||||
+2
-2
@@ -6,11 +6,11 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.evolution
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.evolution.StandardPreEvolution
|
||||
import com.cobblemon.mod.common.pokemon.transformation.evolution.StandardPreEvolution
|
||||
|
||||
/**
|
||||
* Represents the previous stage in the evolutionary line of a given Pokémon.
|
||||
+24
-13
@@ -6,25 +6,36 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution.progress
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.progress
|
||||
|
||||
import com.cobblemon.mod.common.api.data.Identifiable
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.EvolutionController
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.controller.TransformationController
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.trigger.TransformationTrigger
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
* Represents a container of progression towards the completion of an evolution requirement.
|
||||
* To register an evolution progress use [EvolutionProgressTypes.registerType].
|
||||
* Represents a container of progression towards the completion of a [TransformationRequirement].
|
||||
* To register a transformation progress use [TransformationProgressTypes.registerType].
|
||||
*
|
||||
* @param T The type of the progression.
|
||||
*
|
||||
* @author Licious
|
||||
* @since January 27th, 2023
|
||||
*/
|
||||
interface EvolutionProgress<T> : Identifiable {
|
||||
interface TransformationProgress<T : TransformationProgress.Progress> : Identifiable {
|
||||
|
||||
/**
|
||||
* Represents progression towards a [TransformationRequirement].
|
||||
*
|
||||
* @property amount The value required to be complete.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since April 18th, 2025
|
||||
*/
|
||||
interface Progress {
|
||||
val amount: Int
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current progress of type [T].
|
||||
@@ -47,7 +58,7 @@ interface EvolutionProgress<T> : Identifiable {
|
||||
fun reset()
|
||||
|
||||
/**
|
||||
* Used to decide if the given progress should be kept in the [pokemon]s [EvolutionController].
|
||||
* Used to decide if the given progress should be kept in the [pokemon]s [TransformationController].
|
||||
*
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
* @return True if the progress is still required otherwise false.
|
||||
@@ -55,16 +66,16 @@ interface EvolutionProgress<T> : Identifiable {
|
||||
fun shouldKeep(pokemon: Pokemon): Boolean
|
||||
|
||||
/**
|
||||
* The [EvolutionProgressType] of this.
|
||||
* The [TransformationProgressType] of this.
|
||||
*
|
||||
* @return The [EvolutionProgressType] of this.
|
||||
* @return The [TransformationProgressType] of this.
|
||||
*/
|
||||
fun type(): EvolutionProgressType<*>
|
||||
fun type(): TransformationProgressType<*>
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun codec() = EvolutionProgressTypes.codec()
|
||||
fun codec() = TransformationProgressTypes.codec()
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -6,10 +6,10 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution.progress
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.progress
|
||||
|
||||
import com.mojang.serialization.MapCodec
|
||||
|
||||
data class EvolutionProgressType<T : EvolutionProgress<*>>(
|
||||
data class TransformationProgressType<T : TransformationProgress<*>>(
|
||||
val codec: MapCodec<T>
|
||||
)
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.progress
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.transformation.progress.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.Lifecycle
|
||||
import net.minecraft.core.MappedRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import kotlin.jvm.Throws
|
||||
|
||||
/**
|
||||
* Registry of [TransformationProgressType]s.
|
||||
*
|
||||
* @author Licious
|
||||
* @since July 6th, 2024
|
||||
*/
|
||||
object TransformationProgressTypes {
|
||||
|
||||
private const val ID_KEY = "id"
|
||||
|
||||
private val REGISTRY: Registry<TransformationProgressType<*>> = MappedRegistry(
|
||||
ResourceKey.createRegistryKey(cobblemonResource("transformation_progress")), Lifecycle.stable()
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
val DAMAGE_TAKEN = this.registerType(DamageTakenTransformationProgress.ID, TransformationProgressType(DamageTakenTransformationProgress.CODEC))
|
||||
@JvmStatic
|
||||
val DEFEAT = this.registerType(DefeatTransformationProgress.ID, TransformationProgressType(DefeatTransformationProgress.CODEC))
|
||||
@JvmStatic
|
||||
val LAST_BATTLE_CRITICAL_HITS = this.registerType(LastBattleCriticalHitsTransformationProgress.ID, TransformationProgressType(LastBattleCriticalHitsTransformationProgress.CODEC))
|
||||
@JvmStatic
|
||||
val RECOIL = this.registerType(RecoilTransformationProgress.ID, TransformationProgressType(RecoilTransformationProgress.CODEC))
|
||||
@JvmStatic
|
||||
val USE_MOVE = this.registerType(UseMoveTransformationProgress.ID, TransformationProgressType(UseMoveTransformationProgress.CODEC))
|
||||
|
||||
/**
|
||||
* Registers a transformation progress.
|
||||
*
|
||||
* @param T The type of the [TransformationProgress].
|
||||
* @param id The [ResourceLocation].
|
||||
* @param type The [TransformationProgressType] record.
|
||||
* @return The registered [TransformationProgressType] of type [T].
|
||||
*
|
||||
* @throws [IllegalStateException] if [Registry.register] fails.
|
||||
*/
|
||||
@Throws(IllegalStateException::class)
|
||||
@JvmStatic
|
||||
fun <T : TransformationProgress<*>> registerType(id: ResourceLocation, type: TransformationProgressType<T>): TransformationProgressType<T> {
|
||||
return Registry.register(REGISTRY, id, type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a codec instance of this registry.
|
||||
*
|
||||
* @return The generated [Codec] of [TransformationProgress].
|
||||
*/
|
||||
fun codec(): Codec<TransformationProgress<*>> = REGISTRY.byNameCodec().dispatch(
|
||||
ID_KEY,
|
||||
{ it.type() },
|
||||
{ it.codec }
|
||||
)
|
||||
}
|
||||
+3
-2
@@ -6,13 +6,14 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.proxy
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.controller.TransformationController
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
fun interface PreProcessor {
|
||||
fun create(pokemon: Pokemon): EvolutionController<*, *>
|
||||
fun create(pokemon: Pokemon): TransformationController<*, *>
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.proxy
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.Transformation
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.TransformationDisplay
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.TransformationLike
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.controller.TransformationController
|
||||
|
||||
/**
|
||||
* Responsible for holding the different [TransformationController] implementations based on the logical side.
|
||||
* If you haven't already checked your side previously you can use [isClient].
|
||||
*
|
||||
* @param C The type of [TransformationDisplay] on the client side.
|
||||
* @param S The type of [Transformation] on the server side.
|
||||
* @param CI The type of [PreProcessor] on the client side.
|
||||
* @param SI The type of [PreProcessor] on the server side.
|
||||
*
|
||||
* @author Licious, Segfault Guy
|
||||
* @since January 19th, 2025
|
||||
*/
|
||||
interface TransformationProxy<C : TransformationDisplay, S : Transformation, CI : PreProcessor, SI : PreProcessor> {
|
||||
|
||||
/**
|
||||
* Checks if the current logical side is the client.
|
||||
*
|
||||
* @return True if the current logical side is the client.
|
||||
*/
|
||||
fun isClient(): Boolean
|
||||
|
||||
/**
|
||||
* Returns the current [TransformationController].
|
||||
* Keep in mind this will have type erasure and as such most operations will not be possible.
|
||||
* It's recommended to work with [client] or [server] when possible.
|
||||
*
|
||||
* @return The current [TransformationController].
|
||||
*/
|
||||
fun current(): TransformationController<out TransformationLike, *>
|
||||
|
||||
/**
|
||||
* The client side implementation of the [TransformationController].
|
||||
*
|
||||
* @throws [ClassCastException] if called from the server side.
|
||||
*
|
||||
* @return The client side implementation of the [TransformationController] if possible.
|
||||
*/
|
||||
fun client(): TransformationController<C, CI>
|
||||
|
||||
/**
|
||||
* The server side implementation of the [TransformationController].
|
||||
*
|
||||
* @throws [ClassCastException] if called from the client side.
|
||||
*
|
||||
* @return The server side implementation of the [TransformationController] if possible.
|
||||
*/
|
||||
fun server(): TransformationController<S, SI>
|
||||
|
||||
}
|
||||
+5
-6
@@ -6,23 +6,22 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.evolution.requirements.template
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.requirement
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* An [EvolutionRequirement] that expects a [LivingEntity] to be attached to the [Pokemon].
|
||||
* A [TransformationRequirement] that expects a [LivingEntity] to be attached to the [Pokemon].
|
||||
* It can be the [PokemonEntity] if present or the [LivingEntity] that owns it.
|
||||
*
|
||||
* Whenever an entity can't be resolved [EvolutionRequirement.check] will never succeed.
|
||||
* Whenever an entity can't be resolved [TransformationRequirement.check] will never succeed.
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 21st, 2022
|
||||
*/
|
||||
interface EntityQueryRequirement : EvolutionRequirement {
|
||||
interface EntityQueryRequirement : TransformationRequirement {
|
||||
override fun check(pokemon: Pokemon): Boolean {
|
||||
val queriedEntity = pokemon.entity ?: pokemon.getOwnerPlayer() ?: return false
|
||||
return this.check(pokemon, queriedEntity)
|
||||
@@ -32,7 +31,7 @@ interface EntityQueryRequirement : EvolutionRequirement {
|
||||
* Checks if the given [Pokemon] & [LivingEntity] satisfies the requirement.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
* @param queriedEntity The [LivingEntity] that can be compared in context of a [Level].
|
||||
* @param queriedEntity The [LivingEntity] that can be compared in context of a [net.minecraft.world.level.Level].
|
||||
* @return If the requirement was satisfied.
|
||||
*/
|
||||
fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.requirement
|
||||
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
/**
|
||||
* A [TransformationRequirement] that expects the [Pokemon] to have an owner.
|
||||
* It can be the [ServerPlayer] or the [NPCEntity] that owns it.
|
||||
*
|
||||
* Whenever an owner can't be resolved [TransformationRequirement.check] will never succeed.
|
||||
*
|
||||
* @author Polymeta
|
||||
* @since May 6th, 2025
|
||||
*/
|
||||
interface OwnerQueryRequirement : TransformationRequirement {
|
||||
override fun check(pokemon: Pokemon): Boolean {
|
||||
val owner = pokemon.getOwnerEntity() ?: return false
|
||||
return when (owner) {
|
||||
is ServerPlayer -> {
|
||||
this.checkPlayer(pokemon, owner)
|
||||
}
|
||||
is NPCEntity -> {
|
||||
this.checkNPC(pokemon, owner)
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given [Pokemon] & [ServerPlayer] satisfies the requirement.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
* @param owner The [ServerPlayer] that owns this [Pokemon].
|
||||
* @return If the requirement was satisfied.
|
||||
*/
|
||||
fun checkPlayer(pokemon: Pokemon, owner: ServerPlayer): Boolean
|
||||
|
||||
/**
|
||||
* Checks if the given [Pokemon] & [NPCEntity] satisfies the requirement.
|
||||
* This method mainly exists as NPCs are different to players in a lot of ways (e.g., lack of advancements),
|
||||
* so they need to be handled differently, either by checking an NPC config or always returning true/false
|
||||
*
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
* @param owner The [NPCEntity] that owns this [Pokemon].
|
||||
* @return If the requirement was satisfied.
|
||||
*/
|
||||
fun checkNPC(pokemon: Pokemon, owner: NPCEntity): Boolean
|
||||
}
|
||||
+12
-7
@@ -6,23 +6,22 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.evolution.requirement
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.requirement
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.ContextEvolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.Transformation
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.trigger.ContextTrigger
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
/**
|
||||
* Represents a requirement for an evolution.
|
||||
* Represents a requirement for a transformation.
|
||||
* Requirements are constant and will never change regardless of the backing action.
|
||||
* For dynamic requirements see [ContextEvolution].
|
||||
*
|
||||
* See [Evolution.requirements] & [Evolution.test] for usage.
|
||||
* See [Transformation.requirements] & [Transformation.test] for usage.
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 19th, 2022
|
||||
*/
|
||||
fun interface EvolutionRequirement {
|
||||
fun interface TransformationRequirement {
|
||||
|
||||
/**
|
||||
* Checks if the given [Pokemon] satisfies the requirement.
|
||||
@@ -32,4 +31,10 @@ fun interface EvolutionRequirement {
|
||||
*/
|
||||
fun check(pokemon: Pokemon): Boolean
|
||||
|
||||
/**
|
||||
* Callback after the [Transformation] has been performed.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
*/
|
||||
fun fulfill(pokemon: Pokemon) {}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.trigger
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.Transformation
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.transformation.triggers.ItemInteractionTrigger
|
||||
import com.cobblemon.mod.common.pokemon.transformation.triggers.TradeTrigger
|
||||
|
||||
/**
|
||||
* Represents a [TransformationTrigger] of a [Pokemon] that can only occur during specific actions and with added context.
|
||||
* For the default implementations see [ItemInteractionTrigger] & [TradeTrigger].
|
||||
*
|
||||
* @param TC The context that is serialized from JSON during species loading. This is what the [Context] provided
|
||||
* to [testTrigger] is expected to match against.
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 19th, 2022
|
||||
*/
|
||||
interface ContextTrigger<TC>: TransformationTrigger {
|
||||
|
||||
/**
|
||||
* Represents context provided for [TransformationTrigger] evaluation.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since October 15th, 2023
|
||||
*/
|
||||
interface Context
|
||||
|
||||
/** The target context required for this [Transformation] to be successfully triggered. */
|
||||
val requiredContext: TC
|
||||
|
||||
/**
|
||||
* Checks if the given context is valid for the [requiredContext].
|
||||
*
|
||||
* @param context The [Context] given at runtime when querying the [Transformation].
|
||||
* @return If the context matched the [requiredContext].
|
||||
*/
|
||||
fun testContext(context: Context): Boolean = false
|
||||
|
||||
/**
|
||||
* Evaluates the triggering condition of a [Transformation].
|
||||
*
|
||||
* @param context The [Context] of the [Transformation].
|
||||
* @return Whether the triggering condition is satisfied. If [context] is null, bypasses the condition check.
|
||||
*/
|
||||
override fun testTrigger(context: Context?) = context?.let { testContext(it) } ?: true
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.trigger
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.transformation.triggers.LevelUpTrigger
|
||||
|
||||
/**
|
||||
* Represents a [TransformationTrigger] of a [Pokemon] that is attempted periodically without any additional context or actions.
|
||||
* For the default implementation see [LevelUpTrigger].
|
||||
*
|
||||
* Triggers that implement this marker will be tested every second.
|
||||
*
|
||||
* @author Licious
|
||||
* @since March 19th, 2022
|
||||
*/
|
||||
interface PassiveTrigger : TransformationTrigger
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.transformation.trigger
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.transformation.Transformation
|
||||
|
||||
/**
|
||||
* Represents a condition that starts a [Transformation].
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since Sept 8th, 2023
|
||||
*/
|
||||
interface TransformationTrigger {
|
||||
|
||||
/**
|
||||
* Evaluates the triggering condition of a [Transformation].
|
||||
*
|
||||
* @param context The optional [ContextTrigger.Context] for [ContextTrigger] evaluation.
|
||||
* @return Whether the triggering condition is satisfied.
|
||||
*/
|
||||
fun testTrigger(context: ContextTrigger.Context?): Boolean = true
|
||||
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import net.minecraft.world.entity.PlayerRideableJumping
|
||||
|
||||
/**
|
||||
@@ -20,6 +23,6 @@ interface Rideable : PlayerRideableJumping {
|
||||
/**
|
||||
* Denotes the manager responsible for handling any instance of riding taking place on an entity
|
||||
*/
|
||||
val riding: RidingManager
|
||||
val riding: RidingBehaviour<RidingBehaviourSettings, RidingBehaviourState>?
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.controller
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
@@ -29,4 +29,4 @@ class RidingAnimation(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.toProperties
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.sin
|
||||
|
||||
data class RidingManager(val entity: PokemonEntity) {
|
||||
var lastSpeed = 0F
|
||||
var states: MutableMap<ResourceLocation, RidingState> = mutableMapOf()
|
||||
var deltaRotation = Vec2.ZERO
|
||||
|
||||
val runtime: MoLangRuntime by lazy {
|
||||
MoLangRuntime()
|
||||
.setup()
|
||||
.withQueryValue("entity", entity.struct)
|
||||
.also {
|
||||
it.environment.query.addFunction("passenger_count") { DoubleValue(entity.passengers.size.toDouble()) }
|
||||
it.environment.query.addFunction("get_ride_stats") { params ->
|
||||
val rideStat = RidingStat.valueOf(params.getString(0).uppercase())
|
||||
val rideStyle = RidingStyle.valueOf(params.getString(1).uppercase())
|
||||
val maxVal = params.getDouble(2)
|
||||
val minVal = params.getDouble(3)
|
||||
//TODO: Use the mons actual boost once implemented
|
||||
val normalizedStat = entity.rideProp.calculate(rideStat, rideStyle, 0) / 100.0f
|
||||
val trueStatVal = (normalizedStat * (maxVal - minVal)) + minVal
|
||||
|
||||
DoubleValue(trueStatVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : RidingState> getState(id: ResourceLocation, constructor: (PokemonEntity) -> T): T {
|
||||
val storedState = states[id]
|
||||
if (storedState == null) {
|
||||
val newState = constructor(entity)
|
||||
states[id] = newState
|
||||
return newState
|
||||
}
|
||||
|
||||
return storedState as T
|
||||
}
|
||||
|
||||
fun getController(entity: PokemonEntity): RideController? {
|
||||
return entity.pokemon.riding.controller?.takeIf { it.condition.invoke(entity) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for handling riding conditions and transitions amongst controllers. This will tick
|
||||
* whenever the entity receives a tickControlled interaction.
|
||||
*/
|
||||
fun tick(entity: PokemonEntity, driver: Player, input: Vec3) {
|
||||
val controller = getController(entity) ?: return
|
||||
|
||||
val pose = controller.pose(entity)
|
||||
entity.entityData.set(PokemonEntity.POSE_TYPE, pose)
|
||||
//val speedPlayer = driver.deltaMovement.horizontalDistance()
|
||||
//driver.displayClientMessage(Component.literal("Speed player: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("$speedPlayer b/t")), true)
|
||||
//val speedEntity = entity.deltaMovement.length() //* 20 * 60 * 60) / ( 1000 )
|
||||
//println(speedEntity)
|
||||
//driver.displayClientMessage(Component.literal("Speed: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("${String.format("%.2f", speedEntity)} km/h")), true)
|
||||
|
||||
}
|
||||
|
||||
fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
val controller = getController(entity) ?: return 0.05F
|
||||
this.lastSpeed = controller.speed(entity, driver)
|
||||
return this.lastSpeed
|
||||
}
|
||||
|
||||
fun controlledRotation(entity: PokemonEntity, driver: Player): Vec2 {
|
||||
val controller = getController(entity) ?: return entity.rotationVector
|
||||
val previousRotation = entity.rotationVector
|
||||
val rotation = controller.rotation(entity, driver)
|
||||
this.deltaRotation = Vec2(rotation.x - previousRotation.x, rotation.y - previousRotation.y)
|
||||
return rotation
|
||||
}
|
||||
|
||||
fun clampPassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
|
||||
val controller = getController(entity) ?: return
|
||||
return controller.clampPassengerRotation(entity, driver)
|
||||
}
|
||||
|
||||
fun updatePassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
|
||||
val controller = getController(entity) ?: return
|
||||
return controller.updatePassengerRotation(entity, driver)
|
||||
}
|
||||
|
||||
fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
|
||||
val controller = getController(entity) ?: return Vec3.ZERO
|
||||
return controller.velocity(entity, driver, input)
|
||||
}
|
||||
|
||||
fun setRideBar(entity: PokemonEntity, driver: Player): Float {
|
||||
val controller = getController(entity) ?: return 0.0f
|
||||
return controller.setRideBar(entity, driver)
|
||||
}
|
||||
|
||||
fun rideFovMult(entity: PokemonEntity, driver: Player): Float {
|
||||
val controller = getController(entity) ?: return 1.0f
|
||||
return controller.rideFovMult(entity, driver)
|
||||
}
|
||||
|
||||
fun canJump(entity: PokemonEntity, driver: Player): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.canJump(entity, driver)
|
||||
}
|
||||
|
||||
fun jumpVelocity(entity: PokemonEntity, driver: Player, jumpStrength: Int): Vec3 {
|
||||
val controller = getController(entity) ?: return Vec3.ZERO
|
||||
return controller.jumpForce(entity, driver, jumpStrength)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to supply the delta for the lerp() between velocity
|
||||
* vectors. Called inertia for now as the way it feels when
|
||||
* affecting the ride is somewhat akin to inertia.
|
||||
*/
|
||||
fun inertia(entity: PokemonEntity): Double {
|
||||
val controller = getController(entity) ?: return 0.5
|
||||
return controller.inertia(entity)
|
||||
}
|
||||
|
||||
fun gravity(entity: PokemonEntity, regularGravity: Double): Double? {
|
||||
val controller = getController(entity) ?: return null
|
||||
return controller.gravity(entity, regularGravity)
|
||||
}
|
||||
|
||||
//Maybe should be changed to be a function that conveys:
|
||||
// "turn on use our camera system function"
|
||||
fun shouldRoll(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.shouldRoll(entity)
|
||||
}
|
||||
|
||||
fun shouldRotatePlayerHead(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.shouldRotatePlayerHead()
|
||||
}
|
||||
|
||||
fun shouldRotatePokemonHead(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.shouldRotatePokemonHead()
|
||||
}
|
||||
|
||||
fun rotationOnMouseXY(
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
yMouse: Double,
|
||||
xMouse: Double,
|
||||
yMouseSmoother: SmoothDouble,
|
||||
xMouseSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
val controller = getController(entity) ?: return Vec3.ZERO
|
||||
return controller.rotationOnMouseXY(
|
||||
entity,
|
||||
driver,
|
||||
yMouse,
|
||||
xMouse,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
) }
|
||||
|
||||
/**
|
||||
* Determines whether mouse input will affect the rotation of
|
||||
* the rollable object. Need to remove this as it's not used anymore
|
||||
*/
|
||||
//I think this might better serve as a "use smoothing on angular velocity"
|
||||
fun useAngVelSmoothing(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return true
|
||||
return controller.useAngVelSmoothing(entity)
|
||||
}
|
||||
|
||||
fun turnOffOnGround(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.turnOffOnGround(entity)
|
||||
}
|
||||
|
||||
fun angRollVel(entity: PokemonEntity, driver: Player, deltaTime: Double): Vec3 {
|
||||
val controller = getController(entity) ?: return Vec3(0.0, 0.0, 0.0)
|
||||
return controller.angRollVel(entity, driver, deltaTime)
|
||||
}
|
||||
|
||||
fun dismountOnShift(): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.dismountOnShift(entity)
|
||||
}
|
||||
}
|
||||
@@ -9,45 +9,38 @@
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStatDefinition
|
||||
import com.cobblemon.mod.common.util.adapters.RideControllerAdapter
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.getString
|
||||
import com.cobblemon.mod.common.util.readIdentifier
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.adapters.RidingBehaviourSettingsAdapter
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class RidingProperties(
|
||||
val stats: Map<RidingStat, RidingStatDefinition> = mapOf(),
|
||||
val seats: List<Seat> = listOf(),
|
||||
val conditions: List<Expression> = listOf(),
|
||||
val controller: RideController? = null
|
||||
val behaviour: RidingBehaviourSettings? = null
|
||||
) {
|
||||
companion object {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): RidingProperties {
|
||||
val stats: Map<RidingStat, RidingStatDefinition> = buffer.readMap(
|
||||
{ buffer.readEnum<RidingStat>(RidingStat::class.java) },
|
||||
{ buffer.readEnum(RidingStat::class.java) },
|
||||
{ RidingStatDefinition.decode(buffer) }
|
||||
)
|
||||
val seats: List<Seat> = buffer.readList { _ -> Seat.decode(buffer) }
|
||||
val conditions = buffer.readList { buffer.readString().asExpression() }
|
||||
val controller = buffer.readNullable { _ ->
|
||||
val key = buffer.readIdentifier()
|
||||
val controller = RideControllerAdapter.types[key]?.getConstructor()?.newInstance() ?: error("Unknown controller key: $key")
|
||||
controller.decode(buffer)
|
||||
return@readNullable controller
|
||||
val behaviour = buffer.readNullable { _ ->
|
||||
val key = buffer.readResourceLocation()
|
||||
val settings = RidingBehaviourSettingsAdapter.types[key]?.getConstructor()?.newInstance() ?: error("Unknown controller key: $key")
|
||||
settings.decode(buffer)
|
||||
return@readNullable settings
|
||||
}
|
||||
|
||||
return RidingProperties(stats = stats, seats = seats, conditions = conditions, controller = controller)
|
||||
return RidingProperties(stats = stats, seats = seats, conditions = conditions, behaviour = behaviour)
|
||||
}
|
||||
}
|
||||
|
||||
val canRide: Boolean
|
||||
get() = seats.isNotEmpty() && controller != null
|
||||
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeMap(
|
||||
stats,
|
||||
@@ -56,7 +49,9 @@ class RidingProperties(
|
||||
)
|
||||
buffer.writeCollection(seats) { _, seat -> seat.encode(buffer) }
|
||||
buffer.writeCollection(conditions) { _, condition -> buffer.writeString(condition.getString()) }
|
||||
buffer.writeNullable(controller) { _, controller -> controller.encode(buffer) }
|
||||
buffer.writeNullable(behaviour) { _, behaviour ->
|
||||
behaviour.encode(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
fun calculate(stat: RidingStat, style: RidingStyle, boosts: Int): Float {
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
/**
|
||||
* Honestly having a base interface is probably unnecessary I'm just considering whether there's going to be some
|
||||
* kind of shared state later.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 6th, 2024
|
||||
*/
|
||||
interface RidingState
|
||||
@@ -19,4 +19,4 @@ enum class RidingStyle {
|
||||
LAND,
|
||||
LIQUID,
|
||||
AIR
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.api.riding.controller.RidingAnimation
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
/**
|
||||
* Represents the behaviour of a Pokemon when being ridden.
|
||||
* This is intended to contain the logic for how a Pokemon should behave when being ridden.
|
||||
*
|
||||
* This class should remain stateless as it is intended to be shared between multiple instances of Pokemon.
|
||||
*
|
||||
* @author landonjw
|
||||
*/
|
||||
interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBehaviourState> {
|
||||
val key: ResourceLocation
|
||||
|
||||
fun getRidingStyle(settings: Settings, state: State): RidingStyle
|
||||
|
||||
fun isActive(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun tick(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player, input: Vec3) {}
|
||||
|
||||
fun pose(settings: Settings, state: State, vehicle: PokemonEntity): PoseType
|
||||
|
||||
fun speed(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Float
|
||||
|
||||
fun clampPassengerRotation(settings: Settings, state: State, entity: PokemonEntity, driver: LivingEntity) {}
|
||||
|
||||
fun updatePassengerRotation(settings: Settings, state: State, entity: PokemonEntity, driver: LivingEntity) {}
|
||||
|
||||
fun rotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity): Vec2
|
||||
|
||||
fun velocity(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player, input: Vec3): Vec3
|
||||
|
||||
fun angRollVel(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player, deltaTime: Double): Vec3
|
||||
|
||||
fun rotationOnMouseXY(
|
||||
settings: Settings,
|
||||
state: State,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3
|
||||
|
||||
fun canJump(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Boolean
|
||||
|
||||
fun setRideBar(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Float
|
||||
|
||||
fun jumpForce(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player, jumpStrength: Int): Vec3
|
||||
|
||||
fun gravity(settings: Settings, state: State, vehicle: PokemonEntity, regularGravity: Double): Double
|
||||
|
||||
fun rideFovMultiplier(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Float
|
||||
|
||||
fun useAngVelSmoothing(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun useRidingAltPose(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Boolean
|
||||
|
||||
fun inertia(settings: Settings, state: State, vehicle: PokemonEntity): Double
|
||||
|
||||
fun shouldRoll(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun turnOffOnGround(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun dismountOnShift(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun shouldRotatePokemonHead(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun shouldRotatePlayerHead(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun createDefaultState(settings: Settings): State
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
/**
|
||||
* Represents static settings of a riding behaviour.
|
||||
* Values in this class are intended to be constant and not change during the riding process.
|
||||
* Typically this will be initialized for each pokemon form during deserialization
|
||||
* to determine how they should ride.
|
||||
*
|
||||
* @author landonjw
|
||||
*/
|
||||
interface RidingBehaviourSettings: Encodable, Decodable {
|
||||
val key: ResourceLocation
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.util.ifClient
|
||||
import com.cobblemon.mod.common.util.ifServer
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
/**
|
||||
* Represents the state of a Pokemon when being ridden.
|
||||
* This is intended to contain mutable state that is passed between the client and server
|
||||
* or temporary state that is used during the riding process.
|
||||
*
|
||||
* This will be destroyed when the a user dismounts the Pokemon.
|
||||
*
|
||||
* @author landonjw
|
||||
*/
|
||||
open class RidingBehaviourState {
|
||||
open val rideVelocity: SidedRidingState<Vec3> = ridingState(Vec3.ZERO, Side.BOTH)
|
||||
open val stamina: SidedRidingState<Float> = ridingState(1.0F, Side.BOTH)
|
||||
|
||||
open fun reset() {
|
||||
rideVelocity.set(Vec3.ZERO, true)
|
||||
stamina.set(1.0F, true)
|
||||
}
|
||||
|
||||
open fun copy(): RidingBehaviourState {
|
||||
val copy = RidingBehaviourState()
|
||||
copy.rideVelocity.set(rideVelocity.get(), true)
|
||||
copy.stamina.set(stamina.get(), true)
|
||||
return copy
|
||||
}
|
||||
|
||||
open fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous.rideVelocity.get() != rideVelocity.get()) return true
|
||||
if (previous.stamina.get() != stamina.get()) return true
|
||||
return false
|
||||
}
|
||||
|
||||
open fun encode(buffer: FriendlyByteBuf) {
|
||||
buffer.writeVec3(rideVelocity.get())
|
||||
buffer.writeFloat(stamina.get())
|
||||
}
|
||||
|
||||
open fun decode(buffer: FriendlyByteBuf) {
|
||||
rideVelocity.set(buffer.readVec3(), true)
|
||||
stamina.set(buffer.readFloat(), true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun <T> ridingState(value: T, side: Side) = SidedRidingState(value, side)
|
||||
|
||||
class SidedRidingState<T>(private var value: T, val side: Side) {
|
||||
fun get() = value
|
||||
|
||||
fun set(value: T, forced: Boolean = false) {
|
||||
if (forced) {
|
||||
this.value = value
|
||||
}
|
||||
else {
|
||||
when (side) {
|
||||
Side.BOTH -> { this.value = value }
|
||||
Side.CLIENT -> { ifClient { this.value = value } }
|
||||
Side.SERVER -> { ifServer { this.value = value } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other is SidedRidingState<*>) {
|
||||
return value == other.value
|
||||
}
|
||||
return super.equals(other)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return value.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
enum class Side {
|
||||
SERVER, CLIENT, BOTH
|
||||
}
|
||||
|
||||
enum class DriverSide {
|
||||
LOCAL, REMOTE, BOTH
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeBehaviour
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
object RidingBehaviours {
|
||||
val behaviours = mutableMapOf<ResourceLocation, RidingBehaviour<RidingBehaviourSettings, RidingBehaviourState>>()
|
||||
|
||||
init {
|
||||
register(BirdAirBehaviour.KEY, BirdAirBehaviour())
|
||||
register(DolphinBehaviour.KEY, DolphinBehaviour())
|
||||
register(GenericLandBehaviour.KEY, GenericLandBehaviour())
|
||||
register(GenericSwimBehaviour.KEY, GenericSwimBehaviour())
|
||||
register(GliderAirBehaviour.KEY, GliderAirBehaviour())
|
||||
register(HelicopterBehaviour.KEY, HelicopterBehaviour())
|
||||
register(JetAirBehaviour.KEY, JetAirBehaviour())
|
||||
register(SwimDashBehaviour.KEY, SwimDashBehaviour())
|
||||
register(VehicleLandBehaviour.KEY, VehicleLandBehaviour())
|
||||
register(HoverBehaviour.KEY, HoverBehaviour())
|
||||
register(CompositeBehaviour.KEY, CompositeBehaviour())
|
||||
}
|
||||
|
||||
fun register(key: ResourceLocation, behaviour: RidingBehaviour<out RidingBehaviourSettings, out RidingBehaviourState>) {
|
||||
if (behaviours.contains(key)) error("Behaviour already registered to key $key")
|
||||
behaviours[key] = RidingController(behaviour) as RidingBehaviour<RidingBehaviourSettings, RidingBehaviourState>
|
||||
}
|
||||
|
||||
fun get(key: ResourceLocation): RidingBehaviour<RidingBehaviourSettings, RidingBehaviourState> {
|
||||
if (!behaviours.contains(key)) error("Behaviour not registered to key $key")
|
||||
return behaviours[key]!!
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user