Compare commits

...
Author SHA1 Message Date
JPAKx4 ba3207d176 Work on a framework to make UI stuff not suck 2025-12-20 12:23:48 -06:00
JPAKx4 762f9ce5f1 Merge branch 'main' into controllify-compat 2025-12-17 22:24:43 -06:00
JPAKx4 6c12198344 Improve InteractWheelProcessor.kt and use controlify sensitivity 2025-12-17 22:24:29 -06:00
Polymeta 06ebf51078 Merge branch 'Wii-Break-It-Wii-Fix-It' into 'main'
Boat Tags and Mint Leaves

Closes #1855

See merge request cable-mc/cobblemon!2082
2025-12-13 22:14:32 +00:00
Polymeta 39c5bcd73c Merge branch 'even-more-seasonings' into 'main'
Adding Missing Effects for Seasonings

See merge request cable-mc/cobblemon!1991
2025-12-13 22:13:24 +00:00
CeejayandPolymeta 8f5f158b60 Adding Missing Effects for Seasonings 2025-12-13 22:13:24 +00:00
dhi_holo 3bc1e35125 Update CHANGELOG.md 2025-12-13 18:42:50 +10:00
dhi_holo 460bedddae Boat Tags
Resolves #1855
2025-12-13 18:12:24 +10:00
dhi_holo 8b64c315f3 Merge branch 'main' into Wii-Break-It-Wii-Fix-It 2025-12-13 17:51:15 +10:00
dhi_holo 7c824a2b72 OVERSIGHTS 2025-12-13 17:50:57 +10:00
Paul f197ac5077 Removed a bunch of duplicates from is_held_item because it looks whack. 2025-12-12 16:24:30 +10:00
Hiroku e0be669482 Merge branch 'patch-1' into 'main'
Fix Soothe Bell not tagged as `cobblemon:held/is_held_item`

See merge request cable-mc/cobblemon!2081
2025-12-12 06:17:17 +00:00
Micky 08ea21fff4 Fix Soothe Bell not tagged as cobblemon:held/is_held_item 2025-12-10 13:27:23 +00:00
JPAKx4 99a0ec7f0d Merge remote-tracking branch 'origin/controllify-compat' into controllify-compat
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/client/CobblemonClient.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/integration/controlify/CobblemonControlifyEntrypoint.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/integration/controlify/gui/InteractWheelProcessor.kt
2025-12-08 22:38:47 -06:00
JPAKx4 aacebc9726 Add changelog, handle horse sprinting, add all UIs to virtual mouse. 2025-12-08 22:37:43 -06:00
JPAKx4 378c85b7dd More work on keybinds for Controlify compat 2025-12-08 22:20:26 -06:00
JPAKx4 c4614ff418 Add radial menu support for controlify 2025-12-08 22:20:26 -06:00
JPAK 8cbbd2de27 Move compat to common for neoforge and fabric support. 2025-12-08 22:20:26 -06:00
JPAKx4 067c59a636 Continue work on controlify compat 2025-12-08 22:20:26 -06:00
JPAKx4 98a02438da Begin ControlifyCompat 2025-12-08 22:20:25 -06:00
Polymeta 28c0f8ab7d Merge branch 'item-interactions-sync' into 'main'
Item interactions sync

See merge request cable-mc/cobblemon!2068
2025-12-08 16:08:48 +00:00
lionandPolymeta fcbe0db568 Item interactions sync 2025-12-08 16:08:48 +00:00
Polymeta 83cefe476e Merge branch 'partner-mark' into 'main'
Add Partner Mark

See merge request cable-mc/cobblemon!2034
2025-12-08 15:57:21 +00:00
Guilherme Pereira 690ccbd260 refactor check riding statistics method for server player mixin 2025-12-08 12:06:20 -03:00
Polymeta 63846d53fb Merge branch 'main' into 'main'
Fixed shiny Pokémon not respecting the silent flag on spawn.

See merge request cable-mc/cobblemon!2064
2025-12-08 13:07:25 +00:00
Polymeta 86cb865742 fixed mochi items being consumed twice
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-12-08 13:01:14 +00:00
Polymeta 1a0c9b6a82 Merge branch 'malformed-jsons-no-more' into 'main'
Fixes a crash caused by malformed riding prespectives json file when trying to ride a pokemon

See merge request cable-mc/cobblemon!2077
2025-12-08 12:59:22 +00:00
Polymeta 985eb103fe Merge branch 'sterr/ride-sound-changes' into 'main'
New ride sound stuff

See merge request cable-mc/cobblemon!2065
2025-12-08 11:44:22 +00:00
Polymeta aec76a78da Merge branch 'restore_adorn_texturing' into 'main'
Restore adorn texturing

Closes #1833

See merge request cable-mc/cobblemon!2078
2025-12-08 11:36:41 +00:00
Jacob Hartmann 17f3edf2be Changelog 2025-12-07 20:35:11 -07:00
Jacob Hartmann 9c5bfda20f Updating texture paths 2025-12-07 20:34:09 -07:00
JPAKx4 26b25c8c39 More work on keybinds for Controlify compat 2025-12-07 17:01:04 -06:00
Gertimoshka 6d545fc1ca Fixes a crash caused by malformed riding prespectives json file when trying to ride a pokemon 2025-12-07 11:47:04 +02:00
Polymeta 9a8ad27122 Merge branch 'fix-spectator-crash' into 'main'
fix spectator crash

Closes #1847

See merge request cable-mc/cobblemon!2076
2025-12-07 08:39:18 +00:00
500-internal-server-error 9f1dbc9ff0 add notes to changelog 2025-12-07 07:58:55 +07:00
Polymeta 99942748b0 Merge branch 'entropydragon--spawn-bait-regional-forms' into 'main'
fix: use regional form data for spawn bait influence

See merge request cable-mc/cobblemon!2074
2025-12-07 00:49:48 +00:00
jasoncramer 64c34230bf chore: add to changelog 2025-12-06 19:28:41 -05:00
JPAKx4 bfd78c1a85 Merge remote-tracking branch 'origin/controllify-compat' into controllify-compat 2025-12-06 17:10:33 -06:00
JPAKx4 239485ccb5 Add radial menu support for controlify 2025-12-06 17:10:20 -06:00
JPAKx4 ff959daaef Add radial menu support for controlify 2025-12-06 16:57:09 -06:00
500-internal-server-error 36881b70be fix spectator crash 2025-12-06 20:51:48 +07:00
JPAK 32bb340260 Move compat to common for neoforge and fabric support. 2025-12-05 21:36:59 -06:00
jasoncramer 9b052478f6 fix: use regional form data for spawn bait influence 2025-12-05 14:23:05 -05:00
Hiroku 339f8339f0 Merge branch 'RestorePokemonItemPickup' into 'main'
Restore Pokemon item pickup

See merge request cable-mc/cobblemon!2073
2025-12-05 08:19:41 +00:00
Hiroku db9a802c3f Merge branch 'fix-spawner-crash' into 'main'
Prevents outside spawn influences from crashing the logical server.

See merge request cable-mc/cobblemon!2072
2025-12-05 07:45:29 +00:00
JazzMcNade e5666e7a82 Restore Pokemon item pickup. Remove unnecessary check in shouldBeSaved() 2025-12-05 01:30:20 -06:00
Neovitalism a588213323 Update CHANGELOG.md 2025-12-04 03:05:03 -06:00
Neovitalism 56b2ba08ad Prevents outside influences from crashing the logical server.
Before when it was completed exceptionally w/ the pokesnack spawner, it would crash the server.
2025-12-04 03:03:57 -06:00
Khvrram 7e6ca7be5e Merge branch cobblemon:main into main 2025-12-04 01:59:17 +00:00
JPAKx4 b7bfc6d0a1 Continue work on controlify compat 2025-12-03 07:01:01 -06:00
Polymeta c43b3bbb4d Merge branch 'fix-can-drop-held-item' into 'main'
Fix can drop held item function

See merge request cable-mc/cobblemon!2069
2025-12-03 08:17:38 +00:00
lionandPolymeta d826aeeb07 Fix can drop held item function 2025-12-03 08:17:35 +00:00
Polymeta f90c6967ce Merge branch 'FixHoneyedLeavesInteraction' into 'main'
FixHoneyedLeavesInteraction

Closes #1832

See merge request cable-mc/cobblemon!2067
2025-12-03 08:15:26 +00:00
JazzMcNade b9cf18adbd Changelog 2025-12-02 20:16:56 -06:00
JazzMcNade 30650e1f9f Code simplication 2025-12-02 20:12:37 -06:00
JazzMcNade eaa558a7c8 Check for creative on using empty bottle 2025-12-02 00:36:53 -06:00
JazzMcNade 0dc725e513 Can only receive honey at max age. Adds result to hand if possible. Checks for creative and server/client 2025-12-02 00:28:23 -06:00
Sterrezo a575c6bc3d Update CHANGELOG.md 2025-12-01 15:47:34 +01:00
Sterrezo 9c102a7850 Merge branch 'main' into sterr/ride-sound-changes 2025-12-01 15:45:40 +01:00
Sterrezo 22a1eaab19 Volume balancing 2025-12-01 15:35:22 +01:00
Sterrezo 0118ace5fc Implemented stereo flight loops 2025-12-01 15:09:37 +01:00
Sterrezo d4a93abbf7 Added support for submerged ride sounds 2025-12-01 14:27:55 +01:00
Sterrezo d0ee3f3e9d Added an option for ride sounds to not play for the passengers 2025-12-01 13:56:56 +01:00
Khvrram 46ae53f565 Merge branch cobblemon:main into main 2025-12-01 04:25:52 +00:00
Hiroku 7d4e5892ba Merge branch 'main' into 'main'
Orientation after crash fix

See merge request cable-mc/cobblemon!2061
2025-12-01 00:23:40 +00:00
KhvrramandHiroku f9de415020 Orientation after crash fix 2025-12-01 00:23:39 +00:00
Khurram Valiyev 4d123b6e4b Fixed shiny Pokémon not respecting the silent flag on spawn. 2025-11-29 22:50:52 -05:00
JPAKx4 d86879095f Begin ControlifyCompat 2025-11-29 17:02:35 -06:00
Polymeta 54dc2e7f6f tidy up changelog [skip-ci] 2025-11-29 12:57:24 +00:00
Polymeta 1d60ba093f Merge branch 'convention-tags-not-being-consistent-grrrrrrrr' into 'main'
Why

See merge request cable-mc/cobblemon!2060
2025-11-29 11:53:50 +00:00
Hiroku 0fef74dce7 Edit OneToOneFileStoreAdapter.kt 2025-11-29 09:46:27 +00:00
Hiroku b08647bb32 Revert "Merge branch 'main' into 'main'"
This reverts merge request !2062
2025-11-29 04:26:57 +00:00
Hiroku de9e89f040 Merge branch 'main' into 'main'
Editar en_us.json

See merge request cable-mc/cobblemon!2062
2025-11-29 04:25:10 +00:00
Ezequiel Neri Ferreira 84a29ebc2a Editar en_us.json 2025-11-29 04:22:49 +00:00
Paul 37b13ae959 Unsnaps your shot 2025-11-29 12:44:40 +10:00
dhi_holo 1cacbe8306 Why
It's called Shears, that's the item name, why does NeoForge use a Shear tag instead
Atleast Fabric has that tag as well so it's not a hard fix
2025-11-29 12:30:45 +10:00
Paul 12d224d15a Reinforce switchForm for crashes 2025-11-29 11:25:58 +10:00
Paul a57eee3afc Changelog updates [skip-ci] 2025-11-29 10:46:19 +10:00
Hiroku 57595c999c Merge branch 'remove-snapshot' into 'main'
Remove snapshot for release

See merge request cable-mc/cobblemon!2059
2025-11-28 23:24:59 +00:00
Landon Wills 83615b7eb3 Prepare release 2025-11-28 17:54:24 -05:00
Polymeta c53c544a8b Merge branch 'implement_pokemon' into 'main'
Last minute changes

See merge request cable-mc/cobblemon!2058
2025-11-28 22:23:03 +00:00
Kenji_64 c7c272c79c Had to fix Dragapult (again) 2025-11-28 21:04:50 +01:00
Kenji_64 c759161367 Added cries to Eelektrik and Eelektross 2025-11-28 21:01:27 +01:00
Landon 19b7b4804f Merge branch 'add-defend-owner-task' into 'main'
Make Pokémon only attack mobs targeting the player

See merge request cable-mc/cobblemon!2051
2025-11-28 18:30:05 +00:00
Landon 3a005cc813 Merge branch '1.7.1-spawns' into 'main'
Updated Dratini line spawns.

See merge request cable-mc/cobblemon!2055
2025-11-28 18:28:24 +00:00
Landon a8e16efa48 Merge branch 'jet-handling' into 'main'
Increase pitch rotation of Jet

See merge request cable-mc/cobblemon!2054
2025-11-28 18:08:20 +00:00
Veraxiel c3ddfce0a7 Updated Dratini spawn. 2025-11-28 12:38:53 -05:00
Landon Wills 9500f7a1f3 adjust wording 2025-11-28 12:21:44 -05:00
Landon Wills 83a8d92e3f Add changelog 2025-11-28 12:21:08 -05:00
Landon Wills e105c5d4d7 Remove multipliers, adjust expression 2025-11-28 12:17:42 -05:00
Landon Wills 3d816f57e2 Increase pitch rotation of Jet 2025-11-28 12:13:55 -05:00
Landon 1e6dcfba9b Merge branch 'change-freelook-default' into 'main'
Change free look binding default to Left Alt

See merge request cable-mc/cobblemon!2053
2025-11-28 16:30:35 +00:00
Polymeta e59d755d32 Merge branch 'implement_pokemon' into 'main'
Various implementation fixes

See merge request cable-mc/cobblemon!2050
2025-11-28 15:38:40 +00:00
Guilherme Pereira c155b5575d change free look binding default to left alt 2025-11-28 09:35:13 -03:00
Jerzykv 9c6b8b231a oops 2 2025-11-28 13:30:16 +01:00
Jerzykv 92b404dac4 oops 2025-11-28 13:27:19 +01:00
Jerzykv 8a1c536d68 Fixed Furfrou's pink and magenta trims being swapped 2025-11-28 12:56:07 +01:00
Jerzykv 04719d22a5 Fixed a tiny issue with Ceruledge's poser 2025-11-28 12:55:54 +01:00
Jerzykv dacc312756 Implemented Tinkatink line remodels 2025-11-28 12:55:26 +01:00
Polymeta ee4a3d46ba Merge branch '1.7.1-spawns' into 'main'
Updated some spawns.

See merge request cable-mc/cobblemon!2052
2025-11-28 09:31:16 +00:00
violet 80b11f1c3d Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-28 01:20:00 -05:00
Carmendar ddcf4eea7b Heracross and Mudsdale jump fix. 2025-11-28 00:16:50 -06:00
violet 6a0681e4c6 fixed cyclizar's textures 2025-11-27 23:37:39 -05:00
Veraxiel 8ebb378da7 Updated some spawns. 2025-11-27 23:31:32 -05:00
violet e92a878074 fixed boltund's model 2025-11-27 23:30:22 -05:00
Paul 0b97b41c08 Merge remote-tracking branch 'origin/main' 2025-11-28 12:27:10 +10:00
Paul 20fe732cfc Potentially minor perf improvement on following walk targets that are unreachable 2025-11-28 12:26:26 +10:00
Carmendar 0575aa29d9 Doubled high end land mount stamina. 2025-11-27 18:43:20 -06:00
Guilherme Pereira 29b560d244 Merge branch 'main' of gitlab.com:cable-mc/cobblemon into partner-mark 2025-11-27 18:21:19 -03:00
Guilherme Pereira dcc98b4a54 rename mob to living entity 2025-11-27 18:19:49 -03:00
Guilherme Pereira d3ce455391 prevents defend owner task from targeting players 2025-11-27 18:10:59 -03:00
Kenji_64 85c6b633d8 Fixed Dragapult's eyes clippings 2025-11-27 22:03:48 +01:00
Guilherme Pereira 956b599060 update CHANGELOG.md 2025-11-27 17:51:11 -03:00
Jerzykv f88552f99b Gholdengo no longer dances in air. what a shame (fixed flying battle pose issue) 2025-11-27 21:46:35 +01:00
Carmendar e2b559f3eb Merge branch 'main' into implement_pokemon 2025-11-27 14:42:31 -06:00
Carmendar 39816d33b6 Rufflet eepy cry and battle pose fix 2025-11-27 14:38:39 -06:00
Landon 0cf2a23fd4 Merge branch 'cobble-land-fixes' into 'main'
Land adjustments for a smoother riding experience. And bug fixes to land rides

See merge request cable-mc/cobblemon!2039
2025-11-27 19:31:24 +00:00
Guilherme Pereira c4d8eae47e add defend owner task once again 2025-11-27 12:16:54 -03:00
Polymeta 2a5a292386 fix saccharine hanging signs sometimes dropping oak wood signs
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-27 11:27:58 +00:00
Polymeta e8a09f5c48 Merge branch 'json-fixing' into 'main'
JSON Fixes

Closes #1819

See merge request cable-mc/cobblemon!2048
2025-11-27 10:42:07 +00:00
dhi_holo e82193cdfd Update interact_with_pokemon.json
Removed accidental flag
2025-11-27 19:56:33 +10:00
dhi_holo 87e7cdebf6 Fabric Tags that aren't true c tags are the bane of my existence
Fixed the concrete tags to behave properly, changelog
2025-11-27 15:25:53 +10:00
dhi_holo 9ca84d852f Update interact_with_pokemon.json
Should close #1819
2025-11-27 14:22:06 +10:00
Carmendar 8194f93d13 Merge branch 'main' into implement_pokemon 2025-11-26 20:54:41 -06:00
Carmendar c158ec33fa Braviary sleep cry fix 2025-11-26 20:53:46 -06:00
Carmendar 1e27c7494e Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-26 20:52:27 -06:00
Carmendar 54a1f8d932 Braviary battle pose fix 2025-11-26 20:51:45 -06:00
Polymeta 635f29e1ac fix glass bottle not being returned when using honey on saccharine leaves
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-26 22:08:12 +00:00
Polymeta db2001b60a Merge branch 'attempted-jvm-fix' into 'main'
Fixed JVM crash from campfire pot

Closes #1795

See merge request cable-mc/cobblemon!2040
2025-11-26 21:40:30 +00:00
HirokuandPolymeta b5098a2ad0 Fixed JVM crash from campfire pot 2025-11-26 21:40:29 +00:00
Kenji_64 d2af0c9332 Fixed Swampert line's missing recoils crashing the game 2025-11-26 15:40:40 +01:00
Polymeta 8c939ee276 Merge branch 'lets-wind-down' into 'main'
Fixes wind charges recalling pastured pokémon

Closes #1805

See merge request cable-mc/cobblemon!2042
2025-11-26 13:27:12 +00:00
NeovitalismandPolymeta 645b8993c8 Fixes wind charges recalling pastured pokémon 2025-11-26 13:27:12 +00:00
Polymeta d96799cac7 Merge branch 'feature/neoforge-recipe-book' into 'main'
split recipebooktype and category across fabric and neoforge so we can leverage neoforge APIs

Closes #1789 and #1787

See merge request cable-mc/cobblemon!2044
2025-11-26 12:44:06 +00:00
Polymeta b822b626c4 split recipebooktype and category across fabric and neoforge so we can leverage neoforge APIs 2025-11-26 12:44:05 +00:00
Polymeta 4d9b182fb3 fix hearty grains crashing if a block is in the way
Closes #1818

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-26 11:59:25 +00:00
Polymeta 88d155eaf4 [skip-ci] more changelog
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-26 11:33:57 +00:00
Paul af96469b7a changelog [skip-ci] 2025-11-26 21:17:15 +10:00
Paul 65f1e7a3be Merge remote-tracking branch 'weblate/lang-updates' 2025-11-26 21:14:31 +10:00
Kenji_64 379a566d71 Fixed Ditto being silent 2025-11-26 11:52:43 +01:00
Kenji_64 f30ff739ed Fixed Metagross' ground_idle not looping properly (again) >:( 2025-11-26 11:36:23 +01:00
阿鱼andWeblate 16cd2de02f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.4% (8973 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-26 10:03:51 +00:00
Polymeta 22a44bd7e9 Merge branch 'ImprovedPastureBees' into 'main'
Improved Pasture Combees and More

See merge request cable-mc/cobblemon!2043
2025-11-26 09:36:28 +00:00
Polymeta d37bd4ef03 Merge branch 'OmnipathNavigationCrashFix' into 'main'
OmnipathNavigationCrashFix

See merge request cable-mc/cobblemon!2045
2025-11-26 09:34:03 +00:00
Hiroku a3d9a10f2e Merge branch 'wallpaper' into 'main'
Remove auto generated screen glow due to rendering issues

See merge request cable-mc/cobblemon!2047
2025-11-26 08:48:00 +00:00
Test 7801e3feee changelog clarification [skip-ci] 2025-11-26 04:56:10 +00:00
Test 4a54cb4674 remove auto generated screen glow 2025-11-26 04:38:14 +00:00
JazzMcNade 24fe1c125c changelog 2025-11-25 21:47:45 -06:00
JazzMcNade 023160f87a Removed a really silly cast 2025-11-25 21:32:17 -06:00
RedGenesectNinja c45e34648c Fixed Toedscool and Toedscruel's hitboxes being too small 2025-11-25 18:53:12 -06:00
Polymeta 17fbf7c6f0 defensive pokemon casts as NPCs use this too
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-25 16:53:26 +00:00
Polymeta ec86b7d4bf fix tag reference
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-25 15:18:09 +00:00
阿鱼andWeblate 7561eb116f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.3% (8960 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-25 14:20:09 +00:00
Polymeta 6467b97a23 Merge branch 'implement_pokemon' into 'main'
marked furfrou as implemented

See merge request cable-mc/cobblemon!2041
2025-11-25 12:16:02 +00:00
JazzMcNade 6d5909a1e3 Added rain clause, do not attempt to enter a full hive, changelog 2025-11-25 02:17:28 -06:00
JazzMcNade 2bb0d43ca8 Fix wandering for pastured bees, fix hoverpos not being cleared 2025-11-25 00:51:04 -06:00
Watuneni iteiteandWeblate 1fb3f0ebdc Translated using Weblate (Japanese)
Currently translated at 99.2% (8954 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-25 06:46:07 +00:00
jackowes d56586ecac - Fix walking animation issues 2025-11-24 21:39:36 -06:00
violet fb2154e2c3 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-24 22:06:34 -05:00
violet 3b14d19fdb marked furfrou as implemented 2025-11-24 22:06:22 -05:00
Carmendar 6840c2fdef Merge branch 'main' into implement_pokemon 2025-11-24 17:28:35 -06:00
阿鱼andWeblate 8fc2031806 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.2% (8954 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-24 21:23:59 +00:00
jackowes 9df8be33e9 - revert a bad change 2025-11-24 14:51:33 -06:00
Alexis SalgueiroandWeblate 4795e2e1bc Translated using Weblate (French)
Currently translated at 99.6% (8984 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-11-24 11:22:45 +00:00
Carmendar c563627b05 Shiny female Combee is now actually shiny. 2025-11-24 02:31:25 -06:00
violet 73ebf7a789 tiny typo fix 2025-11-24 03:18:38 -05:00
Landon a1b3d3d2ca Merge branch 'lets-be-friends-again' into 'main'
Move friendship logic to spawn action

See merge request cable-mc/cobblemon!2037
2025-11-24 06:50:24 +00:00
lionandLandon 8baacbcf90 Move friendship logic to spawn action 2025-11-24 06:50:23 +00:00
Hiroku f2e357b749 Merge branch 'pc-crash-fix' into 'main'
Fix PC crash with VulkanMod

Closes #1793

See merge request cable-mc/cobblemon!2038
2025-11-24 04:28:32 +00:00
jackowes ff2afd546e changelog 2025-11-23 21:50:30 -06:00
Test b95900b29a Fix PC crash with VulkanMod 2025-11-23 22:39:28 -05:00
jackowes b8b7756a45 - Add double tap to sprint on land mounts
- Adjust step up in air and on ground to reflect vanilla behaviour
- Fix inAir check so pose does not change back to walking or running while in air
2025-11-23 21:29:30 -06:00
jackowes 3d6146f551 - Add double tap to sprint on land mounts.
- Adjust step up in air and on ground to reflect vanilla behaviour
2025-11-23 21:15:41 -06:00
Hiroku 03585fafb0 Merge branch 'HoneyIForgotTheNectar' into 'main'
Don't Forget the Nectar

See merge request cable-mc/cobblemon!2031
2025-11-24 01:38:14 +00:00
jackowes 31d81db243 Merge branch 'main' into cobble-land-fixes 2025-11-23 18:19:51 -06:00
jackowes 4c36db8685 - Fix ridden pokemon land collision and weird step up issues. Horse is smoother overall now.
- Change the turnrate debuff to be squareroot instead of linear.
- Accel stat does not affect land ridden mounts walks.
- Add vanilla sprinting fov to pokemon land mounts
2025-11-23 18:19:13 -06:00
washashu0905andWeblate e3d0252d75 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 94.4% (8519 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-11-24 00:10:57 +00:00
阿鱼andWeblate dbe8e57341 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.2% (8950 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-24 00:10:56 +00:00
Zack the GhastandWeblate 6f37fd69cd Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.4% (8791 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2025-11-24 00:10:55 +00:00
JazzMcNade b191f4e9fb Check hivecooldown memory registration 2025-11-23 15:42:56 -06:00
Hiroku a5a7cc20ba Merge branch 'eating-cough-drops' into 'main'
Throat Spray Recipe

See merge request cable-mc/cobblemon!2036
2025-11-23 11:48:00 +00:00
Polymeta 02b6c46082 [skip-ci] 1.7 tag doc files
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-23 11:39:39 +00:00
dhi_holo 881a30cca4 Merge branch 'main' into eating-cough-drops 2025-11-23 20:33:20 +10:00
dhi_holo d01011f4d0 Throat Spray Recipe
This either was lost at some point or never existed in the mod, I'm not sure which. It's here now!
2025-11-23 20:32:21 +10:00
Landon 309ed379c7 Merge branch 'AAAAAAAAAAAAAAAAAAAAA' into 'main'
unfudge camera maybe please

See merge request cable-mc/cobblemon!2030
2025-11-23 10:30:50 +00:00
Landon Wills edbf667f45 Add changelog 2025-11-23 04:44:02 -05:00
Landon Wills b6bc766adf Merge branch 'main' into AAAAAAAAAAAAAAAAAAAAA 2025-11-23 04:42:52 -05:00
Test 1ecf556cf2 Merge branch 'nom' into 'main'
Small Fixes

See merge request cable-mc/cobblemon!2035
2025-11-23 03:46:33 +00:00
dhi_holo 6d32073604 Small Fixes
- Ponigiri can no longer be eaten at full hunger
- Medicinal Brew's Campfire Pot recipe now correctly displays that it can be made using an empty glass bottle or a filled bottle
- Added trades for Saccharine Saplings, Hearty Grains, Chipped Pot, and Masterpiece Teacup to the Wandering Trader
- Reduced cost of the Vivichoke Seed trade with the Wandering Trader
2025-11-23 12:45:18 +10:00
Guilherme Pereira 7cedfb9047 update CHANGELOG.md 2025-11-22 22:02:14 -03:00
Guilherme Pereira a7ab2e37c2 Merge branch 'main' of gitlab.com:cable-mc/cobblemon into partner-mark 2025-11-22 21:57:49 -03:00
Guilherme Pereira 4723f91500 add riding stats 2025-11-22 21:57:25 -03:00
Hiroku aa0f5d8a05 Merge branch 'vanilla-ride-fix-and-misc-ride-fixes' into 'main'
Fix vanilla rides suffocating players and misc cobble riding fixes

See merge request cable-mc/cobblemon!2033
2025-11-22 23:50:31 +00:00
jackowes 6202c14215 - changelog update 2025-11-22 16:42:20 -06:00
Guilherme Pereira e23aa6b066 add partner mark molang callback 2025-11-22 19:39:21 -03:00
Hiroku b0790341c7 Merge branch 'some-fixes' into 'main'
Some fixes

See merge request cable-mc/cobblemon!2032
2025-11-22 22:36:17 +00:00
jackowes 4f0fa6af4a - Fix horse player suffocation on vanilla mounts
- stop passengers from hearing the shiny noise of a ridden shiny pokemon.
- Convert the riding freelook button to a configurable keybinding

(cherry picked from commit 6432db9f7d)
2025-11-22 16:24:25 -06:00
JazzMcNade 4e24e09924 Safer memory reading in hive occupant mixins 2025-11-22 16:19:30 -06:00
jackowes 48676067b7 Revert "- Fix horse player suffocation on vanilla mounts"
This reverts commit 6432db9f7d.
2025-11-22 16:16:17 -06:00
jackowes 6432db9f7d - Fix horse player suffocation on vanilla mounts
- stop passengers from hearing the shiny noise of a ridden shiny pokemon.
- Convert the riding freelook button to a configurable keybinding
2025-11-22 16:13:47 -06:00
Test 2cb28fb384 rm unused imports 2025-11-22 12:57:59 -05:00
JazzMcNade 3b59148151 changelog again 2025-11-22 11:43:44 -06:00
JazzMcNade d6198631ba New Changelog 2025-11-22 11:40:03 -06:00
geumuandWeblate 47daea6195 Translated using Weblate (Korean)
Currently translated at 75.6% (6826 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-22 17:37:36 +00:00
Watuneni iteiteandWeblate aca66a4bb0 Translated using Weblate (Japanese)
Currently translated at 99.2% (8954 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-22 17:37:35 +00:00
Test e9fe1774c0 fix poke snack sound issue, prevent ride controls from showing to passengers 2025-11-22 12:36:31 -05:00
JazzMcNade bb8b8a77c9 Fixed bees forgetting that they had nectar upon entering a hive 2025-11-22 11:07:37 -06:00
Paul c692b6b5c1 Reset changelog [skip-ci] 2025-11-22 23:09:37 +10:00
geumuandWeblate 68c6d5d9b2 Translated using Weblate (Korean)
Currently translated at 75.6% (6825 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-22 07:33:14 +00:00
Landon Wills 221547aabf unfuck camera maybe please 2025-11-21 22:39:19 -05:00
Watuneni iteiteandWeblate f6b3591d80 Translated using Weblate (Japanese)
Currently translated at 99.2% (8954 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-22 03:06:51 +00:00
geumuandWeblate f9878d6137 Translated using Weblate (Korean)
Currently translated at 75.2% (6740 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-22 01:45:14 +00:00
Watuneni iteiteandWeblate 94da3b8d21 Translated using Weblate (Japanese)
Currently translated at 100.0% (8962 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-22 01:45:14 +00:00
306 changed files with 22255 additions and 6957 deletions
+36 -996
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
# Changelog
## [1.7.1 (November 29th, 2025)](#1-7-1)
### Additions
- Added trades for Saccharine Saplings, Hearty Grains, Chipped Pot, and Masterpiece Teacup to the Wandering Trader.
- Added brewing recipe for Throat Spray.
- Added vanilla sprinting's field of view change to Pokémon land mounts.
- Added a customizable keybind for the riding freelook button.
- Added double tap to sprint on land mounts.
### Changes
- Made Jet pitch turning 1.5x faster across all Pokémon.
- Party Pokémon now attack only mobs that are attacking their owner, instead of randomly targeting unrelated mobs and getting themselves hurt.
- Reduced the cost of the Vivichoke Seed trade with the Wandering Trader.
### Fixes
- Fixed incorrect camera pivot on Bird, Jet, and Dolphin mounts, leading to some disorienting riding.
- Fixed players suffocating while on vanilla mounts.
- Fixed a graphics crash that could occur on some machines when campfire pots were nearby.
- Fixed ride controls overlay being displayed to passengers. The passengers probably don't need to know about those.
- Fixed mount jumping so that it doesn't switch back to ground animations.
- Fixed ridden Pokémon land collision and some issues around stepping up blocks. Land mounts are smoother overall now.
- Fixed Furfrou's pink and magenta trims being swapped. Only a man could make that mistake.
- Fixed friendship being reset to the default value when evolving a Pokémon.
- Fixed Combees not depositing honey upon leaving a hive if they entered it with nectar.
- Fixed pastured Combees not moving during the night or in rain.
- Fixed a case in which a Combee might try to path to a flower that no longer exists.
- Fixed Combees attempting to enter a full hive.
- Fixed a crash involving Combees and hives. 500 bee bugs. Bugged bees? We can be bees. Mark, this is good news.
- Fixed a crash related to NPC navigation.
- Fixed a crash when opening a PC box with certain wallpapers while using *VulkanMod*.
- Fixed a crash when you place a block in the way of hearty grains 2nd block.
- Fixed passengers hearing the shiny noise of a ridden shiny Pokémon.
- Ponigiri can no longer be eaten at full hunger.
- Fixed Poké Snack spawning sounds not coming from the block.
- Medicinal Brew's Campfire Pot recipe now correctly displays that it can be made using an empty glass bottle or a filled bottle.
- Fixed glass bottle not being returned when slathering honey on a saccharine leaf block.
- Fixed saccharine hanging signs sometimes dropping their oak wood counterpart when being broken.
- Fixed a bunch of incompatibilities with NeoForge mods.
- Fixed a bug where wind charges hitting pasture blocks would recall all Pokémon in it.
- Fixed the Home on the Range advancement triggering when opening the Pokémon interaction wheel.
- Fixed recipes that use concrete not working on NeoForge.
- Fixed Boltund's model.
- Fixed Cyclizar's textures.
### Developer
### Molang & Datapacks
- Removed automatic generation of PC wallpaper screen glow if no asset is provided; it is now optional.
- This is because there's no practical way to do this without blowing up things like *VulkanMod*.
### Particles
### Localization
- Updated translations for:
- French
- Japanese
- Korean
- Brazilian Portuguese
- Simplified Chinese
- Traditional Chinese
+9
View File
@@ -32,6 +32,10 @@ repositories {
maven(url = "https://api.modrinth.com/maven")
maven(url = "https://maven.neoforged.net/releases")
maven(url = "https://maven.gegy.dev")
exclusiveContent {
forRepository { maven(url = "https://maven.isxander.dev/releases") }
filter { includeGroup("dev.isxander") }
}
mavenLocal()
}
@@ -62,6 +66,11 @@ dependencies {
// Unit Testing
testImplementation(libs.bundles.unitTesting)
// Controlify Compat, same as flywheel so we pick one and only use the api
modCompileOnlyApi("dev.isxander:controlify:2.4.3+1.21.1-fabric") {
isTransitive = false
}
}
tasks.withType<Test> {
@@ -17,6 +17,7 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.ai.memory.MemoryStatus;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BeehiveBlock;
@@ -52,7 +53,9 @@ public abstract class BeeOccupantMixin {
var facing = state.getValue(HorizontalDirectionalBlock.FACING);
newPos = pos.relative(facing).getCenter();
newYaw = facing.toYRot();
brain.setMemory(CobblemonMemories.HIVE_LOCATION, pos); // This needs to be set in the case that the hive was picked up and moved.
if (brain.checkMemory(CobblemonMemories.HIVE_LOCATION, MemoryStatus.REGISTERED)) {
brain.setMemory(CobblemonMemories.HIVE_LOCATION, pos); // This needs to be set in the case that the hive was picked up and moved.
}
} else {
// Block has likely been destroyed
var center = pos.getCenter();
@@ -62,25 +65,31 @@ public abstract class BeeOccupantMixin {
center.z + level.random.nextFloat() * 0.6 - 0.3
);
newYaw = level.random.nextFloat() * 360F;
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION);
if (brain.checkMemory(CobblemonMemories.HIVE_LOCATION, MemoryStatus.REGISTERED)) {
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION);
}
}
entity.yRotO = newYaw;
entity.setPos(newPos);
// Do honey logic
var hasNectar = brain.getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
if (hasNectar) {
// Remove nectar and reset got to hive cooldown
brain.eraseMemory(CobblemonMemories.HAS_NECTAR);
brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, PathToBeeHiveTaskConfig.STAY_OUT_OF_HIVE_COOLDOWN);
// Increment honey level of the hive
if (state.is(BlockTags.BEEHIVES, (blockStateBase) -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL))) {
int i = state.getValue(BeehiveBlock.HONEY_LEVEL);
if (i < 5) {
int j = level.random.nextInt(100) == 0 ? 2 : 1;
if (i + j > 5) {
--j;
if (brain.checkMemory(CobblemonMemories.HAS_NECTAR, MemoryStatus.REGISTERED)) {
var hasNectar = brain.getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
if (hasNectar) {
// Remove nectar and reset got to hive cooldown
brain.eraseMemory(CobblemonMemories.HAS_NECTAR);
if (brain.checkMemory(CobblemonMemories.HIVE_LOCATION, MemoryStatus.REGISTERED)) {
brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, PathToBeeHiveTaskConfig.STAY_OUT_OF_HIVE_COOLDOWN);
}
// Increment honey level of the hive
if (state.is(BlockTags.BEEHIVES, (blockStateBase) -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL))) {
int i = state.getValue(BeehiveBlock.HONEY_LEVEL);
if (i < 5) {
int j = level.random.nextInt(100) == 0 ? 2 : 1;
if (i + j > 5) {
--j;
}
level.setBlockAndUpdate(pos, state.setValue(BeehiveBlock.HONEY_LEVEL, i + j));
}
level.setBlockAndUpdate(pos, state.setValue(BeehiveBlock.HONEY_LEVEL, i + j));
}
}
}
@@ -92,12 +101,13 @@ public abstract class BeeOccupantMixin {
@Inject(method = "of", at = @At("HEAD"), cancellable = true)
private static void cobblemon$of(Entity entity, CallbackInfoReturnable<BeehiveBlockEntity.Occupant> cir) {
if (entity instanceof PokemonEntity pokemonEntity) {
List<String> IGNORED_BEE_TAGS = Arrays.asList("Air", "ArmorDropChances", "ArmorItems", "Brain", "CanPickUpLoot", "DeathTime", "FallDistance", "FallFlying", "Fire", "HandDropChances", "HandItems", "HurtByTimestamp", "HurtTime", "LeftHanded", "Motion", "NoGravity", "OnGround", "PortalCooldown", "Pos", "Rotation", "Passengers", "leash", "UUID");
List<String> IGNORED_BEE_TAGS = Arrays.asList("Air", "ArmorDropChances", "ArmorItems", "CanPickUpLoot", "DeathTime", "FallDistance", "FallFlying", "Fire", "HandDropChances", "HandItems", "HurtByTimestamp", "HurtTime", "LeftHanded", "Motion", "NoGravity", "OnGround", "PortalCooldown", "Pos", "Rotation", "Passengers", "leash", "UUID");
CompoundTag compoundTag = new CompoundTag();
entity.save(compoundTag);
Objects.requireNonNull(compoundTag);
IGNORED_BEE_TAGS.forEach(compoundTag::remove);
Boolean hasNectar = pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
boolean hasNectar = pokemonEntity.getBrain().checkMemory(CobblemonMemories.HAS_NECTAR, MemoryStatus.REGISTERED)
&& pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
cir.setReturnValue(new BeehiveBlockEntity.Occupant(CustomData.of(compoundTag), 0, hasNectar ? 2400 : 600));
cir.cancel();
}
@@ -1,38 +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;
import com.cobblemon.mod.common.block.PreEmptsExplosion;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = Explosion.class)
public class ExplosionMixin {
@Redirect(
method = "finalizeExplosion",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/Level;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;",
ordinal = 0
)
)
public BlockState cobblemon$whenExploded(Level world, BlockPos pos) {
BlockState blockState = world.getBlockState(pos);
if(blockState.getBlock() instanceof PreEmptsExplosion preExplosionBlock) {
preExplosionBlock.whenExploded(world, blockState, pos);
}
return blockState;
}
}
@@ -1,32 +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;
import net.minecraft.stats.RecipeBookSettings;
import net.minecraft.world.inventory.RecipeBookType;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
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(RecipeBookSettings.class)
public class RecipeBookSettingsMixin {
@Shadow @Final public Map<RecipeBookType, RecipeBookSettings.TypeSettings> states;
@Inject(method = "<init>", at = @At("TAIL"))
private void cobblemon$init(CallbackInfo ci) {
states.put(RecipeBookType.valueOf("COOKING_POT"), new RecipeBookSettings.TypeSettings(true, true));
}
}
@@ -11,11 +11,15 @@ package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.PlayerSpawnerAccessor;
import com.cobblemon.mod.common.api.riding.RidingStyle;
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
import com.cobblemon.mod.common.api.stats.CobblemonStats;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
@@ -89,4 +93,32 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(ordinal=0) Entity entity) {
return original && !(entity instanceof PokemonEntity);
}
@WrapOperation(method = "checkRidingStatistics", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;getVehicle()Lnet/minecraft/world/entity/Entity;"))
public Entity cobblemon$checkRidingStatistics(ServerPlayer player, Operation<Entity> original, @Local int distance) {
var entity = original.call(player);
if (!(entity instanceof PokemonEntity pokemonEntity)) {
return entity;
}
var ridingController = pokemonEntity.getRidingController();
if (ridingController == null) return entity;
var activeContext = ridingController.getContext();
if (activeContext == null) return entity;
var ridingStyle = activeContext.getStyle();
CobblemonStats.CobblemonStat stat = switch (ridingStyle) {
case RidingStyle.LAND -> CobblemonStats.RIDING_LAND;
case RidingStyle.AIR -> CobblemonStats.RIDING_AIR;
case RidingStyle.LIQUID -> CobblemonStats.RIDING_LIQUID;
default -> null;
};
if (stat != null) {
player.awardStat(CobblemonStats.getStat(stat), distance);
}
return entity;
}
}
@@ -33,7 +33,7 @@ public class AbstractClientPlayerMixin {
cir.setReturnValue(usageContext.getFovMultiplier());
} else {
// Only modify fov through riding if the pokedex is not open
LocalPlayer player = (LocalPlayer) (Object) this;
AbstractClientPlayer player = (AbstractClientPlayer) (Object) this;
// Only modify fov for the driver and not the passengers
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity && player.getVehicle().getControllingPassenger() == player) {
PokemonEntity ride = (PokemonEntity) player.getVehicle();
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.client.CobblemonClient;
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
import com.cobblemon.mod.common.client.keybind.keybinds.RidingFreelookBinding;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
@@ -20,12 +21,14 @@ import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.blaze3d.Blaze3D;
import kotlin.Pair;
import kotlin.jvm.functions.Function4;
import net.minecraft.client.Minecraft;
import net.minecraft.client.MouseHandler;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.util.Mth;
import net.minecraft.util.SmoothDouble;
import net.minecraft.world.phys.Vec3;
import org.joml.Vector2d;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -145,6 +148,12 @@ public abstract class MouseHandlerMixin {
pokeVehicle.clampPassengerRotation(player);
}
for(Function4<LocalPlayer, Double, Double, Double, Vector2d> rideFun : CobblemonClient.INSTANCE.getRidingTurnInputHandler().values()) {
Vector2d vec = rideFun.invoke(player, cursorDeltaX, cursorDeltaY, d);
cursorDeltaX = vec.x;
cursorDeltaY = vec.y;
}
// If the ride is not orientation controllable then return and perform the normal turnPlayer logic
if (!(vehicle instanceof OrientationControllable controllableVehicle) || !controllableVehicle.getOrientationController().isActive()) {
xMouseSmoother.reset();
@@ -156,7 +165,7 @@ public abstract class MouseHandlerMixin {
}
var vehicleController = controllableVehicle.getOrientationController();
var lookaroundButtonPressed = Minecraft.getInstance().mouseHandler.isMiddlePressed();
var freeLooking = RidingFreelookBinding.INSTANCE.isDown();
Pair<Boolean, Boolean> mouseShouldModifyDriver = ((PokemonEntity) vehicle).ifRidingAvailableSupply(new Pair(false, false), (behaviour, settings, state) -> {
return behaviour.mouseModifiesDriverRotation(
settings,
@@ -170,7 +179,7 @@ public abstract class MouseHandlerMixin {
// affect the vehicle orientation when looking around.
// If the client is a passenger it will modify these rotations and return
//-------------------------------------------------------------------------
if (lookaroundButtonPressed || player.getControlledVehicle() == null) {
if (freeLooking || player.getControlledVehicle() == null) {
// Modify driver rotations
cobblemon$setDriverRotations(player, cursorDeltaX, cursorDeltaY);
@@ -192,10 +201,10 @@ public abstract class MouseHandlerMixin {
// Smoothly return driver rotations to zero when needed
//-------------------------------------------------------------------------
var playerRotater = (RidePassenger)player;
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getFirst()){
if( !freeLooking && !mouseShouldModifyDriver.getFirst()){
playerRotater.cobblemon$setRideYRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideYRot()), 0.0f));
}
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getSecond()) {
if( !freeLooking && !mouseShouldModifyDriver.getSecond()) {
playerRotater.cobblemon$setRideXRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideXRot()), 0.0f));
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.mixin.entity;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokemon.Pokemon;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.client.player.LocalPlayer;
@@ -23,6 +24,7 @@ import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
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;
@@ -48,16 +50,8 @@ public abstract class EntityMixin {
)
)
public boolean cobblemon$forceOnGroundForStepUp(Entity entity, Operation<Boolean> original) {
if (entity instanceof PokemonEntity && entity.hasControllingPassenger()) {
BlockPos below = entity.blockPosition().below();
Level level = entity.level();
var blockStateBelow = level.getBlockState(below);
boolean isAirOrLiquid = blockStateBelow.isAir() || !blockStateBelow.getFluidState().isEmpty();
boolean canSupportEntity = blockStateBelow.isFaceSturdy(level, below, Direction.UP);
boolean standingOnSolid = canSupportEntity && !isAirOrLiquid;
if (standingOnSolid) {
return true;
}
if (entity instanceof PokemonEntity vehicle && entity.hasControllingPassenger()) {
return true;
}
return original.call(entity);
}
@@ -68,18 +62,7 @@ public abstract class EntityMixin {
cancellable = true
)
private void cobblemon$modifyEyePosition_partial(float partialTicks, CallbackInfoReturnable<Vec3> cir) {
var entity = (Entity)(Object)this;
if (entity.level().isClientSide) return;
if (!(entity instanceof Player player)) return;
if (!(player instanceof RidePassenger ridePassenger)) return;
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
var vehicleController = vehicle.getOrientationController();
if (vehicleController == null) return;
// TODO: Determine if it needs partialtick involved.
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
cir.setReturnValue(customEyePos);
cobblemon$getCustomEyePos(cir);
}
@Inject(
@@ -88,15 +71,20 @@ public abstract class EntityMixin {
cancellable = true
)
private void cobblemon$modifyEyePosition_noPartial(CallbackInfoReturnable<Vec3> cir) {
cobblemon$getCustomEyePos(cir);
}
@Unique
private void cobblemon$getCustomEyePos(CallbackInfoReturnable<Vec3> cir) {
var entity = (Entity)(Object)this;
if (entity.level().isClientSide) return;
if (!(entity instanceof Player player)) return;
if (!(player instanceof RidePassenger ridePassenger)) return;
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
if (!(vehicle instanceof PokemonEntity)) return;
var vehicleController = vehicle.getOrientationController();
if (vehicleController == null) return;
// TODO: Determine if it needs partialtick involved.
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
cir.setReturnValue(customEyePos);
}
@@ -42,8 +42,8 @@ import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningZoneGenerator
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePositionResolver
import com.cobblemon.mod.common.api.spawning.SpawningZoneGenerator
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePositionResolver
import com.cobblemon.mod.common.api.starter.StarterHandler
import com.cobblemon.mod.common.api.stats.CobblemonStats
import com.cobblemon.mod.common.api.storage.PokemonStoreManager
@@ -76,12 +76,7 @@ import com.cobblemon.mod.common.config.LastChangedVersion
import com.cobblemon.mod.common.config.constraint.IntConstraint
import com.cobblemon.mod.common.config.starter.StarterConfig
import com.cobblemon.mod.common.data.CobblemonDataProvider
import com.cobblemon.mod.common.events.AdvancementHandler
import com.cobblemon.mod.common.events.EntityCallbackHandler
import com.cobblemon.mod.common.events.CallbackHandler
import com.cobblemon.mod.common.events.PokedexHandler
import com.cobblemon.mod.common.events.ServerTickHandler
import com.cobblemon.mod.common.events.StatHandler
import com.cobblemon.mod.common.events.*
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
import com.cobblemon.mod.common.permission.LaxPermissionValidator
import com.cobblemon.mod.common.platform.events.PlatformEvents
@@ -206,6 +201,7 @@ object Cobblemon {
implementation.registerEntityDataSerializers()
implementation.registerCriteria()
implementation.registerEntitySubPredicates()
implementation.registerMobEffects()
DispenserBehaviorRegistry.registerDispenserBehaviors()
DropEntry.register("command", CommandDropEntry::class.java)
@@ -215,7 +215,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val SACCHARINE_WALL_SIGN = this.create("saccharine_wall_sign", CobblemonWallSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_WALL_HANGING_SIGN = this.create("saccharine_wall_hanging_sign", CobblemonWallHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
@@ -117,6 +117,11 @@ interface CobblemonImplementation {
fun registerEntitySubPredicates()
/**
* TODO
*/
fun registerMobEffects()
/**
* Add a feature to the current platform implementation.
@@ -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
import com.cobblemon.mod.common.api.cooking.effects.CleanseAllEffect
import com.cobblemon.mod.common.api.cooking.effects.CleanseNegativeEffect
import com.cobblemon.mod.common.api.cooking.effects.MentalRestorationEffect
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.world.effect.MobEffect
object CobblemonMobEffects : PlatformRegistry<Registry<MobEffect>, ResourceKey<Registry<MobEffect>>, MobEffect>() {
override val registry: Registry<MobEffect> = BuiltInRegistries.MOB_EFFECT
override val resourceKey: ResourceKey<Registry<MobEffect>> = Registries.MOB_EFFECT
@JvmField
val CLEANSE_NEGATIVE = create("cleanse_negative", CleanseNegativeEffect())
@JvmField
val MENTAL_RESTORATION = create("mental_restoration", MentalRestorationEffect())
@JvmField
val CLEANSE_ALL = create("cleanse_all", CleanseAllEffect())
}
@@ -21,15 +21,12 @@ import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallb
import com.cobblemon.mod.common.client.net.cooking.ToggleCookingPotLidHandler
import com.cobblemon.mod.common.client.net.data.CobblemonMechanicsSyncHandler
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
import com.cobblemon.mod.common.client.net.data.PokemonInteractionsSyncHandler
import com.cobblemon.mod.common.client.net.data.RideSettingsSyncHandler
import com.cobblemon.mod.common.client.net.debug.OpenRidingStatsDebugGUIHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
import com.cobblemon.mod.common.client.net.effect.PokeSnackBlockParticlesHandler
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
import com.cobblemon.mod.common.client.net.effect.SaccharineLogBlockParticlesHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
import com.cobblemon.mod.common.client.net.effect.*
import com.cobblemon.mod.common.client.net.gui.ExpGainedDataPacketHandler
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
@@ -37,11 +34,7 @@ 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.ClientboundUpdateOrientationHandler
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.pasture.UpdatePastureConflictFlagHandler
import com.cobblemon.mod.common.client.net.pasture.*
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
@@ -59,14 +52,7 @@ import com.cobblemon.mod.common.client.net.storage.party.SetPartyPokemonHandler
import com.cobblemon.mod.common.client.net.storage.party.SetPartyReferenceHandler
import com.cobblemon.mod.common.client.net.storage.pc.*
import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
import com.cobblemon.mod.common.client.net.trade.TradeAcceptanceChangedHandler
import com.cobblemon.mod.common.client.net.trade.TradeCancelledHandler
import com.cobblemon.mod.common.client.net.trade.TradeCompletedHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
import com.cobblemon.mod.common.client.net.trade.TradeProcessStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
import com.cobblemon.mod.common.client.net.trade.*
import com.cobblemon.mod.common.net.PacketRegisterInfo
import com.cobblemon.mod.common.net.messages.client.CalculateSeatPositionsPacket
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
@@ -83,20 +69,12 @@ import com.cobblemon.mod.common.net.messages.client.data.*
import com.cobblemon.mod.common.net.messages.client.debug.RequestOpenRidingStatsDebugGUIPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
import com.cobblemon.mod.common.net.messages.client.effect.PokeSnackBlockParticlesPacket
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
import com.cobblemon.mod.common.net.messages.client.effect.SaccharineLogBlockParticlesPacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import com.cobblemon.mod.common.net.messages.client.effect.*
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.ClientboundUpdateDriverInputPacket
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
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonUnpasturedPacket
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureConflictFlagPacket
import com.cobblemon.mod.common.net.messages.client.pasture.*
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedRegisterPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket
@@ -116,43 +94,19 @@ import com.cobblemon.mod.common.net.messages.client.storage.party.InitializePart
import com.cobblemon.mod.common.net.messages.client.storage.party.MoveClientPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyReferencePacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.ClosePCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.InitializePCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.MoveClientPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.RenamePCBoxPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.*
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.ChangePCBoxWallpaperPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.RequestPCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.SetPCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.UnlockPCBoxWallpaperPacket
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCompletedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeProcessStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
import com.cobblemon.mod.common.net.messages.client.trade.*
import com.cobblemon.mod.common.net.messages.client.ui.ExpGainedDataPacket
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengeResponsePacket
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamLeavePacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
import com.cobblemon.mod.common.net.messages.server.*
import com.cobblemon.mod.common.net.messages.server.battle.*
import com.cobblemon.mod.common.net.messages.server.behaviour.DamageOnCollisionPacket
import com.cobblemon.mod.common.net.messages.server.behaviour.SetEntityBehaviourPacket
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
@@ -177,11 +131,7 @@ import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPack
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.FinishScanningPacket
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.StartScanningPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHiddenPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.*
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
@@ -192,21 +142,11 @@ import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokem
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.*
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
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.messages.server.trade.*
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
import com.cobblemon.mod.common.net.serverhandling.battle.TeamLeaveHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestResponseHandler
import com.cobblemon.mod.common.net.serverhandling.battle.*
import com.cobblemon.mod.common.net.serverhandling.behaviour.DamageOnCollisionPacketHandler
import com.cobblemon.mod.common.net.serverhandling.behaviour.SetEntityBehaviourHandler
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
@@ -232,11 +172,7 @@ import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandl
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.FinishScanningHandler
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.StartScanningHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.ServerboundUpdateRidingStateHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetItemHiddenHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.*
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdateRiderRotationHandler
@@ -250,12 +186,7 @@ import com.cobblemon.mod.common.net.serverhandling.storage.party.MovePartyPokemo
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.serverhandling.storage.pc.*
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHandler
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
import com.cobblemon.mod.common.net.serverhandling.trade.*
import com.cobblemon.mod.common.util.server
import net.minecraft.server.level.ServerPlayer
@@ -401,6 +332,7 @@ object CobblemonNetwork {
// Data registries
list.add(PacketRegisterInfo(AbilityRegistrySyncPacket.ID, AbilityRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(CobblemonMechanicsSyncPacket.ID, CobblemonMechanicsSyncPacket::decode, CobblemonMechanicsSyncHandler))
list.add(PacketRegisterInfo(PokemonInteractionsSyncPacket.ID, PokemonInteractionsSyncPacket::decode, PokemonInteractionsSyncHandler))
list.add(PacketRegisterInfo(MovesRegistrySyncPacket.ID, MovesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
@@ -9,14 +9,15 @@
package com.cobblemon.mod.common
import net.minecraft.client.RecipeBookCategories
import net.minecraft.world.inventory.RecipeBookType
enum class CobblemonRecipeCategories {
COOKING_POT_SEARCH("COOKING_POT_SEARCH"),
COOKING_POT_FOODS("COOKING_POT_FOODS"),
COOKING_POT_MEDICINES("COOKING_POT_MEDICINES"),
COOKING_POT_COMPLEX_DISHES("COOKING_POT_COMPLEX_DISHES"),
COOKING_POT_MISC("COOKING_POT_MISC");
COOKING_POT_SEARCH("COBBLEMON_COOKING_POT_SEARCH"),
COOKING_POT_FOODS("COBBLEMON_COOKING_POT_FOODS"),
COOKING_POT_MEDICINES("COBBLEMON_COOKING_POT_MEDICINES"),
COOKING_POT_COMPLEX_DISHES("COBBLEMON_COOKING_POT_COMPLEX_DISHES"),
COOKING_POT_MISC("COBBLEMON_COOKING_POT_MISC");
companion object {
val customAggregateCategories: Map<RecipeBookCategories, List<RecipeBookCategories>> = mapOf(
@@ -35,6 +36,9 @@ enum class CobblemonRecipeCategories {
fun toVanillaCategory(): RecipeBookCategories {
return RecipeBookCategories.valueOf(this.id)
}
}
object CobblemonRecipeBookTypes {
const val COOKING_POT_NAME = "COBBLEMON_COOKING_POT"
val COOKING_POT: RecipeBookType = RecipeBookType.valueOf(COOKING_POT_NAME)
}
@@ -89,7 +89,14 @@ object CobblemonTradeOffers {
* @return The resulting list.
*/
fun resolveWanderingTradeOffers(): List<WandererTradeOffer> = listOf(
WandererTradeOffer(false, listOf(VillagerTrades.ItemsForEmeralds(CobblemonItems.VIVICHOKE_SEEDS, 24, 1, 1, 6)))
WandererTradeOffer(false, listOf(
VillagerTrades.ItemsForEmeralds(CobblemonItems.VIVICHOKE_SEEDS, 6, 1, 1, 6),
VillagerTrades.ItemsForEmeralds(CobblemonItems.SACCHARINE_SAPLING, 5, 1, 4, 1),
VillagerTrades.ItemsForEmeralds(CobblemonItems.HEARTY_GRAINS, 1, 1, 12, 1),
VillagerTrades.ItemsForEmeralds(CobblemonItems.CHIPPED_POT, 5, 1, 1, 2),
VillagerTrades.ItemsForEmeralds(CobblemonItems.MASTERPIECE_TEACUP, 5, 1, 1, 2)
))
)
/**
@@ -0,0 +1,44 @@
/*
* 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.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.DefendOwnerTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class DefendOwnerTaskConfig : SingleTaskConfig {
override fun getVariables(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): List<MoLangConfigVariable> {
return emptyList()
}
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
behaviourConfigurationContext.addMemories(
MemoryModuleType.ATTACK_TARGET,
CobblemonMemories.NEAREST_VISIBLE_ATTACKER,
)
return WrapperLivingEntityTask(
DefendOwnerTask.create(),
PokemonEntity::class.java
)
}
}
@@ -109,7 +109,7 @@ class PollinateFlowerTaskConfig : SingleTaskConfig {
}
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
hoverPos = null
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
entity.brain.setMemory(CobblemonMemories.HAS_NECTAR, true)
}
@@ -105,6 +105,7 @@ interface TaskConfig {
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
cobblemonResource("manage_flight_in_battle") to ManageFlightInBattleTaskConfig::class.java,
cobblemonResource("attack_hostile_mobs") to AttackHostileMobsTaskConfig::class.java,
cobblemonResource("defend_owner") to DefendOwnerTaskConfig::class.java,
cobblemonResource("move_to_sweet_berry_bush") to MoveToSweetBerryBushTaskConfig::class.java,
cobblemonResource("stop_moving_to_sweet_berry_bush") to StopTryingToReachSweetBerryBushTaskConfig::class.java,
cobblemonResource("harvest_sweet_berry_bush") to HarvestSweetBerryBushTaskConfig::class.java,
@@ -9,13 +9,8 @@
package com.cobblemon.mod.common.api.cooking
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.util.math.geometry.toDegrees
import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.minecraft.util.FastColor
import net.minecraft.world.item.ItemStack
import kotlin.math.atan2
import kotlin.math.cos
import kotlin.math.sin
private val colourMap = mapOf(
Flavour.SPICY to 0xFEB37D,
@@ -34,27 +29,30 @@ private val bubbleColourMap = mapOf(
)
fun getColourMixFromSeasonings(seasonings: List<ItemStack>, forBubbles: Boolean = false): Int? {
val flavors = seasonings
.mapNotNull { Seasonings.getFlavoursFromItemStack(it) }
.flatMap { it.entries }
.groupingBy { it.key }
.fold(0) { acc, entry -> acc + entry.value }
val flavourValues = mutableMapOf<Flavour, Int>()
for (seasoning in seasonings) {
val flavours = Seasonings.getFlavoursFromItemStack(seasoning) ?: continue
for ((flavour, value) in flavours.entries) {
flavourValues[flavour] = (flavourValues[flavour] ?: 0) + value
}
}
if (flavors.isEmpty()) return null
if (flavourValues.isEmpty()) {
return null
}
val maxFlavorValue = flavors.values.maxOrNull()
val dominantFlavors = flavors.filter { it.value == maxFlavorValue }.map { it.key }
val maxFlavorValue = flavourValues.values.maxOrNull()
val dominantFlavours = flavourValues.filter { it.value == maxFlavorValue }.map { it.key }
return getColourMixFromFlavours(dominantFlavors, forBubbles)
return getColourMixFromFlavours(dominantFlavours, forBubbles)
}
fun getColourMixFromFlavours(dominantFlavours: List<Flavour>, forBubbles: Boolean = false): Int? {
val colors =
dominantFlavours.mapNotNull { if (forBubbles) bubbleColourMap[it] else colourMap[it] }
dominantFlavours
.mapNotNull { if (forBubbles) bubbleColourMap[it] else colourMap[it] }
.map { FastColor.ARGB32.opaque(it) }
if (colors.isEmpty()) return null
return getColourMixFromColors(colors)
}
@@ -62,104 +60,33 @@ fun getColourMixFromRideStatBoosts(dominantBoosts: Iterable<RidingStat>, forBubb
return getColourMixFromFlavours(dominantBoosts.map { it.flavour }, forBubbles)
}
// Mixing RGB colors directly often gives poor results
// Converting them to HSL and averaging hues circularly produces more natural blends
fun getColourMixFromColors(colors: List<Int>): Int? {
if (colors.isEmpty()) return null
if (colors.size == 1) return colors[0]
val hslColors = colors.map {
val red = FastColor.ARGB32.red(it)
val green = FastColor.ARGB32.green(it)
val blue = FastColor.ARGB32.blue(it)
val firstWeight = 0.7f
val otherWeightTotal = 1f - firstWeight
val otherWeight = otherWeightTotal / (colors.size - 1)
rgbToHsl(red, green, blue)
var alphaSum = 0f
var redSum = 0f
var greenSum = 0f
var blueSum = 0f
for (i in colors.indices) {
val weight = if (i == 0) firstWeight else otherWeight
val color = colors[i]
alphaSum += FastColor.ARGB32.alpha(color) * weight
redSum += FastColor.ARGB32.red(color) * weight
greenSum += FastColor.ARGB32.green(color) * weight
blueSum += FastColor.ARGB32.blue(color) * weight
}
val hues = hslColors.map { it.h.toDouble() }
val huesAverage = hueAverage(hues).toFloat()
val saturations = hslColors.map { it.s }
val saturationsAverage = average(saturations)
val lightness = hslColors.map { it.l }
val lightnessAverage = average(lightness)
val rgbColor = hslToRgb(huesAverage, saturationsAverage, lightnessAverage)
return FastColor.ARGB32.color(rgbColor.r, rgbColor.g, rgbColor.b)
}
// Based on https://iter.ca/post/hue-avg
fun hueAverage(hues: List<Double>): Float {
val points = hues.map { hue ->
val rad = hue.toRadians()
Pair(cos(rad), sin(rad))
}
val avgX = points.sumOf { it.first.toDouble() } / points.size
val avgY = points.sumOf { it.second.toDouble() } / points.size
var degrees = atan2(avgY, avgX).toDegrees()
if (degrees < 0) {
degrees += 360f
} else if (degrees > 360) {
degrees -= 360f
}
return degrees
}
fun average(values: List<Float>): Float {
if (values.isEmpty()) return 0f
return values.sum() / values.size
}
data class HSL(val h: Float, val s: Float, val l: Float)
fun rgbToHsl(r: Int, g: Int, b: Int): HSL {
val rf = r / 255f
val gf = g / 255f
val bf = b / 255f
val max = maxOf(rf, gf, bf)
val min = minOf(rf, gf, bf)
val delta = max - min
var h = 0f
val l = (max + min) / 2f
val s = if (delta == 0f) 0f else delta / (1f - kotlin.math.abs(2f * l - 1f))
if (delta != 0f) {
h = when (max) {
rf -> ((gf - bf) / delta) % 6f
gf -> ((bf - rf) / delta) + 2f
else -> ((rf - gf) / delta) + 4f
}
h *= 60f
if (h < 0) h += 360f
}
return HSL(h, s, l)
}
data class RGB(val r: Int, val g: Int, val b: Int)
fun hslToRgb(h: Float, s: Float, l: Float): RGB {
val c = (1f - kotlin.math.abs(2f * l - 1f)) * s
val x = c * (1f - kotlin.math.abs((h / 60f) % 2f - 1f))
val m = l - c / 2f
val (rf, gf, bf) = when {
h < 60f -> Triple(c, x, 0f)
h < 120f -> Triple(x, c, 0f)
h < 180f -> Triple(0f, c, x)
h < 240f -> Triple(0f, x, c)
h < 300f -> Triple(x, 0f, c)
else -> Triple(c, 0f, x)
}
return RGB(
((rf + m) * 255).toInt().coerceIn(0, 255),
((gf + m) * 255).toInt().coerceIn(0, 255),
((bf + m) * 255).toInt().coerceIn(0, 255)
return FastColor.ARGB32.color(
alphaSum.toInt(),
redSum.toInt(),
greenSum.toInt(),
blueSum.toInt()
)
}
@@ -0,0 +1,22 @@
/*
* 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.cooking.effects
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectCategory
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
class CleanseAllEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xFFFFFF) {
override fun isInstantenous() = true
override fun applyInstantenousEffect(source: Entity?, indirect: Entity?, target: LivingEntity, amplifier: Int, proximity: Double) {
target.removeAllEffects()
}
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = false
}
@@ -0,0 +1,27 @@
/*
* 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.cooking.effects
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectCategory
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
class CleanseNegativeEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xFFFFFF) {
override fun isInstantenous() = true
override fun applyInstantenousEffect(source: Entity?, indirect: Entity?, target: LivingEntity, amplifier: Int, proximity: Double) {
val snapshot = target.activeEffects.toList()
for (ei in snapshot) {
if (ei.effect.value().category == MobEffectCategory.HARMFUL) {
target.removeEffect(ei.effect)
}
}
}
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = false
}
@@ -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.cooking.effects
import net.minecraft.server.level.ServerPlayer
import net.minecraft.stats.Stats
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectCategory
import net.minecraft.world.entity.LivingEntity
class MentalRestorationEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xAA66FF) {
override fun applyEffectTick(entity: LivingEntity, amplifier: Int): Boolean {
if (entity is ServerPlayer) {
val stats = entity.stats
val statType = Stats.CUSTOM.get(Stats.TIME_SINCE_REST)
val current = stats.getValue(statType)
val reduction = 31 * (amplifier + 1)// reduce by half a minute every second per level (30 ticks removed per tick + 1 to account for the tick passing)
val newValue = Math.max(current - reduction, 0)
stats.setValue(entity, statType, newValue)
}
return true
}
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int): Boolean {
return true
}
}
@@ -37,8 +37,6 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.util.FormattedCharSequence
import org.joml.Matrix4f
import org.joml.Vector3f
import org.lwjgl.opengl.GL30
import java.nio.ByteBuffer
@JvmOverloads
fun blitk(
@@ -357,10 +355,10 @@ fun renderSprite(matrixStack: PoseStack, sprite: ResourceLocation) {
val matrix: PoseStack.Pose = matrixStack.last()
matrix.pose().translate(-1f, 0f, 0f)
RenderSystem.setShaderTexture(0, sprite);
RenderSystem.setShaderTexture(0, sprite)
RenderSystem.setShader(GameRenderer::getPositionTexShader)
var buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX)
val buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX)
buffer.addVertex(matrix, 2f, 0f, 0.0f).setUv(1f, 0f)
buffer.addVertex(matrix, 0f, 0f, 0.0f).setUv(0f, 0f)
@@ -369,25 +367,3 @@ fun renderSprite(matrixStack: PoseStack, sprite: ResourceLocation) {
BufferUploader.drawWithShader(buffer.buildOrThrow())
}
fun getPixelRGB(x: Int, y: Int): Triple<Int, Int, Int> {
val window = Minecraft.getInstance().window
val scale = window.guiScale
val buffer = ByteBuffer.allocateDirect(4)
RenderSystem.readPixels(
(x * scale).toInt(),
(window.height - y * scale - scale).toInt(),
1,
1,
GL30.GL_RGBA,
GL30.GL_UNSIGNED_BYTE,
buffer
)
return Triple(
buffer[0].toInt() and 0xFF,
buffer[1].toInt() and 0xFF,
buffer[2].toInt() and 0xFF
)
}
@@ -12,10 +12,10 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.requirement.OwnerQueryRequirement
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.data.PokemonInteractionsSyncPacket
import com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.requirements.PokemonPropertiesRequirement
@@ -51,7 +51,12 @@ object PokemonInteractions : JsonDataRegistry<PokemonInteractionSet> {
val speciesInteractions = mutableListOf<PokemonInteractionSet>()
val generalInteractions = mutableListOf<PokemonInteractionSet>()
override fun sync(player: ServerPlayer) {}
override fun sync(player: ServerPlayer) {
PokemonInteractionsSyncPacket(
speciesInteractions,
generalInteractions,
).sendToPlayer(player)
}
override fun reload(data: Map<ResourceLocation, PokemonInteractionSet>) {
speciesInteractions.clear()
@@ -15,11 +15,10 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.giveOrDropItemStack
import com.cobblemon.mod.common.util.withPlayerValue
import com.cobblemon.mod.common.util.withQueryValue
import com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.util.*
import net.minecraft.core.registries.Registries
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
@@ -28,30 +27,83 @@ import net.minecraft.world.entity.EquipmentSlot
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.item.ItemStack
/**
* A
*/
data class PokemonInteractionSet(
val requirements: List<Requirement> = listOf(),
val interactions: List<PokemonInteraction> = listOf()
)
val interactions: List<PokemonInteraction> = listOf(),
) {
fun encode(buffer: FriendlyByteBuf) {
buffer.writeCollection(requirements) { it, requirement ->
CobblemonRequirementAdapter.encode(requirement, it)
}
buffer.writeCollection(interactions) { it, interaction ->
interaction.encode(it)
}
}
companion object {
fun decode(buffer: FriendlyByteBuf): PokemonInteractionSet {
val requirements = buffer.readList { it ->
CobblemonRequirementAdapter.decode(it)
}
val interactions = buffer.readList { it ->
PokemonInteraction.decode(it)
}
return PokemonInteractionSet(
requirements,
interactions,
)
}
}
}
data class PokemonInteraction(
val grouping: ResourceLocation,
val requirements: List<Requirement> = listOf(),
val effects: List<InteractionEffect> = listOf(),
val cooldown: ExpressionLike = "0".asExpressionLike()
)
) {
fun encode(buffer: FriendlyByteBuf) {
buffer.writeResourceLocation(grouping)
buffer.writeCollection(requirements) { it, requirement ->
CobblemonRequirementAdapter.encode(requirement, it)
}
buffer.writeExpressionLike(cooldown)
}
companion object {
fun decode(buffer: FriendlyByteBuf): PokemonInteraction {
val grouping = buffer.readResourceLocation()
val requirements = buffer.readList { it ->
CobblemonRequirementAdapter.decode(it)
}
// No need to sync these for now
val effects = emptyList<InteractionEffect>()
val cooldown = buffer.readExpressionLike()
return PokemonInteraction(
grouping,
requirements,
effects,
cooldown,
)
}
}
}
interface InteractionEffect {
fun applyEffect(pokemon: PokemonEntity, player: ServerPlayer)
}
class DropItemEffect(val item: ResourceLocation, val amount: IntRange?): InteractionEffect {
class DropItemEffect(val item: ResourceLocation, val amount: IntRange?) : InteractionEffect {
override fun applyEffect(
pokemon: PokemonEntity,
player: ServerPlayer
) {
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(item) ?: throw IllegalArgumentException("Cannot load item with id: $item")
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(item) ?: throw IllegalArgumentException(
"Cannot load item with id: $item"
)
val stack = ItemStack(item)
stack.count = amount?.randomOrNull() ?: 1
if (stack.isEmpty)
@@ -68,12 +120,14 @@ class DropItemEffect(val item: ResourceLocation, val amount: IntRange?): Interac
}
}
class GiveItemEffect(val item: ResourceLocation, val amount: IntRange?): InteractionEffect {
class GiveItemEffect(val item: ResourceLocation, val amount: IntRange?) : InteractionEffect {
override fun applyEffect(
pokemon: PokemonEntity,
player: ServerPlayer
) {
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(item) ?: throw IllegalArgumentException("Cannot load item with id: $item")
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(item) ?: throw IllegalArgumentException(
"Cannot load item with id: $item"
)
val stack = ItemStack(item)
stack.count = amount?.randomOrNull() ?: 1
if (stack.isEmpty)
@@ -86,14 +140,29 @@ class GiveItemEffect(val item: ResourceLocation, val amount: IntRange?): Interac
}
}
class PlaySoundEffect(val sound: ResourceLocation, val soundSource: SoundSource?, val playAround: Boolean = true, val distance: Double = 64.0, val volume: Float = 1.0F, val pitch: Float = 1.0F): InteractionEffect {
class PlaySoundEffect(
val sound: ResourceLocation,
val soundSource: SoundSource?,
val playAround: Boolean = true,
val distance: Double = 64.0,
val volume: Float = 1.0F,
val pitch: Float = 1.0F
) : InteractionEffect {
override fun applyEffect(
pokemon: PokemonEntity,
player: ServerPlayer
) {
val packet = UnvalidatedPlaySoundS2CPacket(sound, soundSource ?: SoundSource.NEUTRAL, pokemon.x, pokemon.y, pokemon.z, volume, pitch)
val packet = UnvalidatedPlaySoundS2CPacket(
sound,
soundSource ?: SoundSource.NEUTRAL,
pokemon.x,
pokemon.y,
pokemon.z,
volume,
pitch
)
if (playAround) {
packet.sendToPlayersAround( pokemon.x, pokemon.y, pokemon.z, distance, pokemon.level().dimension())
packet.sendToPlayersAround(pokemon.x, pokemon.y, pokemon.z, distance, pokemon.level().dimension())
} else {
packet.sendToPlayer(player)
}
@@ -104,7 +173,7 @@ class PlaySoundEffect(val sound: ResourceLocation, val soundSource: SoundSource?
}
}
class ShrinkItemEffect(val amount: Int = 1): InteractionEffect {
class ShrinkItemEffect(val amount: Int = 1) : InteractionEffect {
override fun applyEffect(
pokemon: PokemonEntity,
player: ServerPlayer
@@ -120,7 +189,7 @@ class ShrinkItemEffect(val amount: Int = 1): InteractionEffect {
}
}
class ScriptEffect(val script: ExpressionLike): InteractionEffect {
class ScriptEffect(val script: ExpressionLike) : InteractionEffect {
override fun applyEffect(
pokemon: PokemonEntity,
player: ServerPlayer
@@ -779,6 +779,20 @@ object MoLangFunctions {
battleStartResult.ifSuccessful { returnValue = it.struct }
return@put returnValue
}
map.put("get_custom_stat") { params ->
val statName = params.getString(0)
val resourceLocation = ResourceLocation.tryParse(statName) ?: return@put DoubleValue.ZERO
val statResourceLocation = BuiltInRegistries.CUSTOM_STAT.get(resourceLocation) ?: return@put DoubleValue.ZERO
val exists = net.minecraft.stats.Stats.CUSTOM.contains(statResourceLocation)
if (!exists) return@put DoubleValue.ZERO
val stat = net.minecraft.stats.Stats.CUSTOM.get(statResourceLocation)
val value = player.stats.getValue(stat)
DoubleValue(value)
}
}
map
}
@@ -1739,22 +1753,35 @@ object MoLangFunctions {
pokemon.removeCosmeticItem()
}
map.put("add_marks") { params ->
var appliedMark = false
for (param in params.params) {
val identifier = param.asString().asIdentifierDefaultingNamespace()
val mark = Marks.getByIdentifier(identifier)
if (mark != null) pokemon.exchangeMark(mark, true)
if (mark != null) {
pokemon.exchangeMark(mark, true)
appliedMark = true
}
}
DoubleValue(appliedMark)
}
map.put("add_marks_with_chance") { params ->
var appliedMark = false
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)
if (randomValue < probability) {
pokemon.exchangeMark(it, true)
appliedMark = true
}
}
}
DoubleValue(appliedMark)
}
map.put("add_potential_marks") { params ->
for (param in params.params) {
@@ -409,13 +409,7 @@ open class PokemonProperties {
shiny?.let { pokemon.shiny = it }
gender?.let { pokemon.gender = it }
level?.let { pokemon.level = it }
friendship.also {
if (it != null) {
pokemon.setFriendship(it)
} else {
pokemon.setFriendship(pokemon.form.baseFriendship)
}
}
friendship?.also { pokemon.setFriendship(it) }
fullness?.let { pokemon.currentFullness = it }
pokeball?.let { PokeBalls.getPokeBall(it.asIdentifierDefaultingNamespace())?.let { pokeball -> pokemon.caughtBall = pokeball } }
nature?.let { Natures.getNature(it.asIdentifierDefaultingNamespace())?.let { nature -> pokemon.nature = nature } }
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
/**
* A [Requirement] that expects a [LivingEntity] to be attached to the [Pokemon].
@@ -26,7 +27,7 @@ interface OwnerQueryRequirement : Requirement {
override fun check(pokemon: Pokemon): Boolean {
val owner = pokemon.getOwnerEntity() ?: return false
return when (owner) {
is ServerPlayer -> {
is Player -> {
this.checkPlayer(pokemon, owner)
}
is NPCEntity -> {
@@ -37,13 +38,13 @@ interface OwnerQueryRequirement : Requirement {
}
/**
* Checks if the given [Pokemon] & [ServerPlayer] satisfies the requirement.
* Checks if the given [Pokemon] & [Player] satisfies the requirement.
*
* @param pokemon The [Pokemon] being queried.
* @param owner The [ServerPlayer] that owns this [Pokemon].
* @param owner The [Player] that owns this [Pokemon].
* @return If the requirement was satisfied.
*/
fun checkPlayer(pokemon: Pokemon, owner: ServerPlayer): Boolean
fun checkPlayer(pokemon: Pokemon, owner: Player): Boolean
/**
* Checks if the given [Pokemon] & [NPCEntity] satisfies the requirement.
@@ -322,7 +322,7 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
val pitchRot = handling * state.currMouseYForce.get()
// Roll
val rollRot = handling * 1.5 * state.currMouseXForce.get()
val rollRot = handling * state.currMouseXForce.get()
val mouseRotation = Vec3(0.0, pitchRot, rollRot)
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.api.riding.posing.PoseOption
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
@@ -114,10 +115,10 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
input: Vec3
) {
if (vehicle.level().isClientSide) {
handleSprinting(state)
handleSprinting(state, driver)
inAirCheck(state, vehicle)
tickStamina(settings, state, vehicle)
state.walking.set(state.rideVelocity.get().horizontalDistance() > 0.01)
state.walking.set(state.rideVelocity.get().horizontalDistance() > 0.01 || driver.zza != 0.0f)
}
}
@@ -139,11 +140,27 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
}
fun handleSprinting(
state: HorseState
state: HorseState,
driver: Player
) {
val tryingToSprint = Minecraft.getInstance().options.keySprint.isDown() && Minecraft.getInstance().options.keyUp.isDown()
val sprintTimerTickLength = 7 // Emulate vanillas tick timer length
var hasDoubleTapped = false
val forward = Minecraft.getInstance().player?.input?.up == true
if (state.stamina.get() <= 0.0f || !Minecraft.getInstance().options.keyUp.isDown()) {
// If you are not sprinting and you just pressed down and theres no
if (!state.forwardHeldLastTick.get() && forward && !state.sprinting.get() && state.sprintTickTimer.get() == 0) {
state.sprintTickTimer.set(sprintTimerTickLength)
} else if (!state.forwardHeldLastTick.get() && forward && state.sprintTickTimer.get() != 0) { // If has double tapped
hasDoubleTapped = true
}else if(!state.sprinting.get() && state.sprintTickTimer.get() > 0) {
state.sprintTickTimer.set(state.sprintTickTimer.get() - 1)
} else {
state.sprintTickTimer.set(0)
}
val tryingToSprint = hasDoubleTapped || CobblemonClient.ridingSprintHandler.any { it.value.invoke() }
if (state.stamina.get() <= 0.0f || !forward) {
// If stamina runs out or the player is not holding forward then stop sprinting
state.sprinting.set(false)
if (state.stamina.get() <= 0.0f) {
@@ -156,6 +173,9 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
// If you are trying to sprint and the toggle allows it then start sprinting and disable toggle
state.sprinting.set(true)
}
// Take note of whether forward was held last tick
state.forwardHeldLastTick.set(forward)
}
fun tickStamina(
@@ -227,7 +247,7 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
// Normalize the current rotation diff
val rotDiff = Mth.wrapDegrees(driver.yRot - vehicle.yRot).coerceIn(-maxYawDiff,maxYawDiff)
val rotDiffNorm = rotDiff / maxYawDiff
val rotDiffNorm = rotDiff / maxYawDiff//(rotDiff / maxYawDiff).coerceIn(-0.2f, 0.2f)
// Take the square root so that the ride levels out quicker when at lower differences between entity
// y and driver y
@@ -240,7 +260,7 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
val walkSpeed = getWalkSpeed(vehicle)
val w = max(walkSpeed, vehicle.deltaMovement.horizontalDistance())
val invRelSpeed = (RidingBehaviour.scaleToRange(w, walkSpeed, topSpeed ) - 1.0f) * -1.0f
val turnRate = ((handling.toFloat() / 20.0f) * max(walkHandlingBoost * invRelSpeed, 1.0)).toFloat()
val turnRate = ((handling.toFloat() / 20.0f) * max(walkHandlingBoost * sqrt(abs(invRelSpeed)), 1.0)).toFloat()
// Ensure you only ever rotate as much difference as there is between the angles.
val turnSpeed = turnRate * rotDiffMod
@@ -273,30 +293,24 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalHorse.speedExpr!!)
val walkSpeed = getWalkSpeed(vehicle)
val topSpeed = if(canSprint && state.sprinting.get()) rideTopSpeed else walkSpeed
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalHorse.accelerationExpr!!) * 20.0)
val accelTime = if(state.sprinting.get()) (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalHorse.accelerationExpr!!) * 20.0) else 0.5 * 20.0
val accel = topSpeed / accelTime
var activeInput = false
/******************************************************
* Gather the previous velocity and check for horizontal
* collisions
*****************************************************/
val dmSpeed = vehicle.deltaMovement.length()
val rvSpeed = state.rideVelocity.get().length()
var newVelocity = state.rideVelocity.get() //.normalize().scale(vehicle.deltaMovement.horizontalDistance())
/******************************************************
* Gather the previous velocity and check for horizontal
* collisions
*****************************************************/
// if (dmSpeed > rvSpeed) {
// // align the velocity vector to be in local vehicle space
// newVelocity = vehicle.deltaMovement
// val yawAligned = Matrix3f().rotateY(-vehicle.yRot.toRadians())
// newVelocity = (newVelocity.toVector3f().mul(yawAligned)).toVec3d()
// }
if (vehicle.horizontalCollision) {
newVelocity = newVelocity.normalize().scale(vehicle.deltaMovement.length())
var horizontalVec = Vec3(newVelocity.x, 0.0, newVelocity.z)
horizontalVec = horizontalVec.normalize().scale(min(horizontalVec.length(), 0.3))
newVelocity = Vec3(horizontalVec.x, newVelocity.y, horizontalVec.z)
}
/******************************************************
@@ -372,7 +386,7 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
state.jumpTicks.set(state.jumpTicks.get() + 1)
}
//Zero out lateral velocity possibly picked up from a controller transition
// Zero out lateral velocity possibly picked up from a controller transition
newVelocity = Vec3(0.0, newVelocity.y, newVelocity.z)
@@ -461,7 +475,7 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
vehicle: PokemonEntity,
driver: Player
): Float {
return 1.0f
return if (state.sprinting.get()) 1.15f else 1.0f
}
override fun useAngVelSmoothing(
@@ -520,6 +534,14 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
return true
}
override fun maxUpStep(
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity
): Float? {
return if (state.inAir.get()) 0.0f else 1.2f
}
override fun getRideSounds(
settings: HorseSettings,
state: HorseState,
@@ -618,6 +640,8 @@ class HorseState : RidingBehaviourState() {
var sprintToggleable = ridingState(false, Side.CLIENT)
var inAir = ridingState(false, Side.CLIENT)
var jumpTicks = ridingState(0, Side.CLIENT)
var sprintTickTimer = ridingState(0, Side.CLIENT)
var forwardHeldLastTick = ridingState(false, Side.CLIENT)
override fun encode(buffer: FriendlyByteBuf) {
super.encode(buffer)
@@ -626,6 +650,8 @@ class HorseState : RidingBehaviourState() {
buffer.writeBoolean(sprintToggleable.get())
buffer.writeBoolean(inAir.get())
buffer.writeInt(jumpTicks.get())
buffer.writeInt(sprintTickTimer.get())
buffer.writeBoolean(forwardHeldLastTick.get())
}
override fun decode(buffer: FriendlyByteBuf) {
@@ -635,6 +661,8 @@ class HorseState : RidingBehaviourState() {
sprintToggleable.set(buffer.readBoolean(), forced = true)
inAir.set(buffer.readBoolean(), forced = true)
jumpTicks.set(buffer.readInt(), forced = true)
sprintTickTimer.set(buffer.readInt(), forced = true)
forwardHeldLastTick.set(buffer.readBoolean(), forced = true)
}
override fun reset() {
@@ -644,6 +672,8 @@ class HorseState : RidingBehaviourState() {
sprintToggleable.set(false, forced = true)
inAir.set(false, forced = true)
jumpTicks.set(0, forced = true)
sprintTickTimer.set(0, forced = true)
forwardHeldLastTick.set(false, forced = true)
}
override fun copy() = HorseState().also {
@@ -654,6 +684,8 @@ class HorseState : RidingBehaviourState() {
it.sprintToggleable.set(this.sprintToggleable.get(), forced = true)
it.inAir.set(this.inAir.get(), forced = true)
it.jumpTicks.set(this.jumpTicks.get(), forced = true)
it.sprintTickTimer.set(this.sprintTickTimer.get(), forced = true)
it.forwardHeldLastTick.set(this.forwardHeldLastTick.get(), forced = true)
}
override fun shouldSync(previous: RidingBehaviourState): Boolean {
@@ -12,6 +12,7 @@ package com.cobblemon.mod.common.api.riding.sound
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeState
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.getIsSubmerged
import com.cobblemon.mod.common.util.resolveDouble
import net.minecraft.client.Minecraft
import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance
@@ -65,6 +66,21 @@ class RideLoopSound(val ride: PokemonEntity, val soundSettings: RideSoundSetting
return
}
// Mute the sound if it's not meant to play for the passenger
if (this.isPassenger && !this.soundSettings.playForPassengers) {
this.volume = 0.0f
return
}
// Mute sounds when submerged unless they support underwater sounds, underwater sounds don't play above water
if (this.ride.getIsSubmerged() && !this.soundSettings.submerged) {
this.volume = 0.0f
return
} else if (!this.ride.getIsSubmerged() && this.soundSettings.submerged) {
this.volume = 0.0f
return
}
// Perform data driven pitch and volume calculation
this.volume = ((soundSettings.volumeExpr.let { ride.runtime.resolveDouble(it) })).toFloat()
this.volume *= this.fade
@@ -27,7 +27,9 @@ data class RideSoundSettings(
val soundLocation: ResourceLocation,
@SerializedName("volumeExpr") private val _volumeExpr: Expression? = "1.0".asExpression(),
@SerializedName("pitchExpr") private val _pitchExpr: Expression? = "1.0".asExpression(),
val playForPassengers: Boolean = true,
val playForNonPassengers: Boolean = false,
val submerged: Boolean = false,
val muffleEnabled: Boolean = false,
@SerializedName("attenuationModel") private val _attenuationModel: RideAttenuationModel? = RideAttenuationModel.NONE
): Encodable {
@@ -46,7 +48,9 @@ data class RideSoundSettings(
buffer.writeResourceLocation(soundLocation)
buffer.writeExpression(volumeExpr)
buffer.writeExpression(pitchExpr)
buffer.writeBoolean(playForPassengers)
buffer.writeBoolean(playForNonPassengers)
buffer.writeBoolean(submerged)
buffer.writeBoolean(muffleEnabled)
buffer.writeEnum(attenuationModel)
}
@@ -57,7 +61,9 @@ data class RideSoundSettings(
val soundLocation = buffer.readResourceLocation()
val volumeExpr = buffer.readExpression()
val pitchExpr = buffer.readExpression()
val playForPassengers = buffer.readBoolean()
val playForNonPassengers = buffer.readBoolean()
val submerged = buffer.readBoolean()
val muffleEnabled = buffer.readBoolean()
val attenuationModel = buffer.readEnum(RideAttenuationModel::class.java)
@@ -65,7 +71,9 @@ data class RideSoundSettings(
soundLocation,
volumeExpr,
pitchExpr,
playForPassengers,
playForNonPassengers,
submerged,
muffleEnabled,
attenuationModel
)
@@ -40,9 +40,12 @@ class PokemonSpawnAction(
override fun createEntity(): PokemonEntity {
val props = props.copy()
props.level = levelRange.random()
val sourcePlayer = spawnablePosition.cause.entity as? ServerPlayer
val entity = props.createEntity(spawnablePosition.world, sourcePlayer)
entity.spawnCause = spawnablePosition.cause
entity.pokemon.setFriendship(entity.pokemon.form.baseFriendship)
SeasonFeatureHandler.updateSeason(entity.pokemon, Cobblemon.seasonResolver(spawnablePosition.world, spawnablePosition.position))
val heldItem = heldItem
if (heldItem != ItemStack.EMPTY && heldItem != null) {
@@ -44,11 +44,7 @@ abstract class SpawnAction<R>(
spawnablePosition.applyInfluences { it.affectAction(this) }
val result = run()
if (result != null) {
future.complete(result)
} else {
future.completeExceptionally(Exception("Nothing was spawned."))
}
future.complete(result)
return result
}
@@ -61,7 +61,9 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
val baitEVStat = effects.firstOrNull { it.type == Effects.EV }?.subcategory?.path?.let { Stats.getStat(it) }
if (detailSpecies != null && baitEVStat != null) {
val evYieldValue = detailSpecies.evYield[baitEVStat]?.toFloat() ?: 0f
val detailAspects = detail.pokemon.aspects
val formData = detailSpecies.getForm(detailAspects)
val evYieldValue = formData.evYield[baitEVStat]?.toFloat() ?: 0f
return when {
evYieldValue > 0 -> {
markUsed()
@@ -83,7 +85,9 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
val baitTypingEffect = baitEffect?.subcategory?.path?.let { ElementalTypes.get(it) }
if (detailSpecies != null && baitTypingEffect != null) {
val isMatchingType = detailSpecies.types.contains(baitTypingEffect)
val detailAspects = detail.pokemon.aspects
val formData = detailSpecies.getForm(detailAspects)
val isMatchingType = formData.types.contains(baitTypingEffect)
return when {
isMatchingType -> {
markUsed()
@@ -100,6 +104,9 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
if (detailSpecies != null) {
val detailAspects = detail.pokemon.aspects
val formData = detailSpecies.getForm(detailAspects)
// Collect all the egg group effects
val eggGroupEffects = effects.filter { it.type == Effects.EGG_GROUP }
@@ -111,7 +118,7 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
LOGGER.warn("Unknown egg group identifier: $effectEggGroupKey")
return@firstOrNull false
}
detailSpecies.eggGroups.contains(eggGroup)
formData.eggGroups.contains(eggGroup)
}
if (matchingEffect != null) {
@@ -8,30 +8,58 @@
package com.cobblemon.mod.common.api.stats
import com.cobblemon.mod.common.Cobblemon
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.resources.ResourceLocation
import net.minecraft.stats.StatFormatter
object CobblemonStats {
val stats = mutableMapOf<String, ResourceLocation>()
val stats = mutableMapOf<String, CobblemonStat>()
var CAPTURED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "captured") //makeCustomStat("captured", StatFormatter.DEFAULT)
val SHINIES_CAPTURED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "shinies_captured") //makeCustomStat("shinies_captured", StatFormatter.DEFAULT)
val RELEASED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "released") //makeCustomStat("released", StatFormatter.DEFAULT)
val EVOLVED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "evolved") //makeCustomStat("evolved", StatFormatter.DEFAULT)
val LEVEL_UP: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "level_up") //makeCustomStat("level_up", StatFormatter.DEFAULT)
val BATTLES_WON: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_won") //makeCustomStat("battles_won", StatFormatter.DEFAULT)
val BATTLES_LOST: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_lost") //makeCustomStat("battles_lost", StatFormatter.DEFAULT)
val BATTLES_FLED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_fled") //makeCustomStat("battles_fled", StatFormatter.DEFAULT)
val BATTLES_TOTAL: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_total") //makeCustomStat("battles_total", StatFormatter.DEFAULT)
val DEX_ENTRIES: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "dex_entries") //makeCustomStat("dex_entries", StatFormatter.DEFAULT)
val EGGS_COLLECTED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "eggs_collected") //makeCustomStat("eggs_collected", StatFormatter.DEFAULT)
val EGGS_HATCHED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "eggs_hatched") //makeCustomStat("eggs_hatched", StatFormatter.DEFAULT)
val TRADED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "traded") //makeCustomStat("traded", StatFormatter.DEFAULT)
val FOSSILS_REVIVED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "fossils_revived") //makeCustomStat("fossils_revived", StatFormatter.DEFAULT)
val TIMES_RIDDEN: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "times_ridden")
val ROD_CASTS: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "rod_casts")
val REEL_INS: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "reel_ins")
val POKEMON_INTERACTED_WITH: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "pokemon_interacted_with") //makeCustomStat("pokemon_interacted_with", StatFormatter.DEFAULT)
//TODO block, stats (interact, gimmi), riding (styles?)
@JvmField
var CAPTURED: CobblemonStat = CobblemonStat("captured")
@JvmField
val SHINIES_CAPTURED: CobblemonStat = CobblemonStat("shinies_captured")
@JvmField
val RELEASED: CobblemonStat = CobblemonStat("released")
@JvmField
val EVOLVED: CobblemonStat = CobblemonStat("evolved")
@JvmField
val LEVEL_UP: CobblemonStat = CobblemonStat("level_up")
@JvmField
val BATTLES_WON: CobblemonStat = CobblemonStat("battles_won")
@JvmField
val BATTLES_LOST: CobblemonStat = CobblemonStat("battles_lost")
@JvmField
val BATTLES_FLED: CobblemonStat = CobblemonStat("battles_fled")
@JvmField
val BATTLES_TOTAL: CobblemonStat = CobblemonStat("battles_total")
@JvmField
val DEX_ENTRIES: CobblemonStat = CobblemonStat("dex_entries")
@JvmField
val EGGS_COLLECTED: CobblemonStat = CobblemonStat("eggs_collected")
@JvmField
val EGGS_HATCHED: CobblemonStat = CobblemonStat("eggs_hatched")
@JvmField
val TRADED: CobblemonStat = CobblemonStat("traded")
@JvmField
val FOSSILS_REVIVED: CobblemonStat = CobblemonStat("fossils_revived")
@JvmField
val TIMES_RIDDEN: CobblemonStat = CobblemonStat("times_ridden")
@JvmField
val ROD_CASTS: CobblemonStat = CobblemonStat("rod_casts")
@JvmField
val REEL_INS: CobblemonStat = CobblemonStat("reel_ins")
@JvmField
val POKEMON_INTERACTED_WITH: CobblemonStat = CobblemonStat("pokemon_interacted_with")
@JvmField
val RIDING_LAND: CobblemonStat = CobblemonStat("riding_land", StatFormatter.DISTANCE)
@JvmField
val RIDING_AIR: CobblemonStat = CobblemonStat("riding_air", StatFormatter.DISTANCE)
@JvmField
val RIDING_LIQUID: CobblemonStat = CobblemonStat("riding_liquid", StatFormatter.DISTANCE)
//TODO block, stats (interact, gimmi)
fun registerStats() {
stats["captured"] = CAPTURED
@@ -52,5 +80,22 @@ object CobblemonStats {
stats["rod_casts"] = ROD_CASTS
stats["reel_ins"] = REEL_INS
stats["pokemon_interacted_with"] = POKEMON_INTERACTED_WITH
stats["riding_land"] = RIDING_LAND
stats["riding_air"] = RIDING_AIR
stats["riding_liquid"] = RIDING_LIQUID
}
@JvmStatic
fun getStat(cobblemonStat: CobblemonStat) : ResourceLocation {
val resourceLocation = cobblemonStat.resourceLocation
val stat = BuiltInRegistries.CUSTOM_STAT.get(resourceLocation)
if (stat == null) {
Cobblemon.LOGGER.error("Could not find stat with id {}", resourceLocation)
}
return stat ?: throw NullPointerException("Could not find stat with id $resourceLocation")
}
data class CobblemonStat(val path: String, val formatter: StatFormatter = StatFormatter.DEFAULT) {
val resourceLocation: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", path);
}
}
@@ -88,7 +88,6 @@ abstract class OneToOneFileStoreAdapter<S>(
result
}
else {
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
var result = storeClass.getConstructor(UUID::class.java).newInstance(uuid)
save(storeClass, uuid, serialize(result, registryAccess))
oldFile.delete()
@@ -19,7 +19,6 @@ import net.minecraft.server.level.ServerLevel
import net.minecraft.tags.FluidTags
import net.minecraft.util.Mth
import net.minecraft.util.RandomSource
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.*
import net.minecraft.world.level.block.Block
@@ -175,7 +174,7 @@ class HeartyGrainsBlock(settings: Properties) : CropBlock(settings), SimpleWater
UPDATE_CLIENTS
)
}
else if (stateAbove.getValue(HALF) == DoubleBlockHalf.UPPER) {
else if (stateAbove.hasProperty(HALF) && stateAbove.getValue(HALF) == DoubleBlockHalf.UPPER) {
world.setBlock(
abovePos,
stateAbove.setValue(AGE, newAge),
@@ -34,6 +34,7 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Explosion
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.LevelReader
@@ -55,9 +56,10 @@ import net.minecraft.world.phys.shapes.VoxelShape
import java.util.*
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
import net.minecraft.world.level.gameevent.GameEvent
import java.util.function.BiConsumer
@Suppress("OVERRIDE_DEPRECATION", "DEPRECATION")
class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWaterloggedBlock, PreEmptsExplosion {
class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWaterloggedBlock {
companion object {
val CODEC = simpleCodec(::PastureBlock)
@@ -213,9 +215,19 @@ class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWater
return super.playerWillDestroy(world, pos, state, player)
}
override fun whenExploded(world: Level, state: BlockState, pos: BlockPos) {
val blockEntity = world.getBlockEntity(pos) as? PokemonPastureBlockEntity ?: return
blockEntity.onBroken()
override fun onExplosionHit(
state: BlockState,
level: Level,
pos: BlockPos,
explosion: Explosion,
dropConsumer: BiConsumer<ItemStack?, BlockPos?>
) {
val interaction = explosion.blockInteraction
if (interaction == Explosion.BlockInteraction.DESTROY || interaction == Explosion.BlockInteraction.DESTROY_WITH_DECAY) {
val blockEntity = level.getBlockEntity(pos) as? PokemonPastureBlockEntity ?: return
blockEntity.onBroken()
}
super.onExplosionHit(state, level, pos, explosion, dropConsumer)
}
override fun <T : BlockEntity?> getTicker(world: Level, state: BlockState, type: BlockEntityType<T>): BlockEntityTicker<T>? {
@@ -1,17 +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.block
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.core.BlockPos
import net.minecraft.world.level.Level
interface PreEmptsExplosion {
fun whenExploded(world: Level, state: BlockState, pos: BlockPos)
}
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.block
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import com.cobblemon.mod.common.util.isServerSide
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.dispenser.DispenseItemBehavior
@@ -263,23 +264,39 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
val isGlassBottle = itemStack.`is`(Items.GLASS_BOTTLE)
val isHoneyBottle = itemStack.`is`(Items.HONEY_BOTTLE)
if (isGlassBottle && !isAtMinAge(state)) {
if (isGlassBottle && isAtMaxAge(state)) {
if (level.isClientSide) return ItemInteractionResult.SUCCESS
// Decrement stack if not in creative mode
itemStack.consume(1, player)
// Give player honey bottle for now
player.addItem(Items.HONEY_BOTTLE.defaultInstance)
// Give player a honey bottle
if (stack.isEmpty) {
// Replace the consumed empty bottle with a honey bottle
player.setItemInHand(hand, ItemStack(Items.HONEY_BOTTLE));
} else {
player.addItem(Items.HONEY_BOTTLE.defaultInstance)
}
level.playSound(null, pos, SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS)
level.setBlock(pos, state.setValue(AGE, 0), 2)
level.setBlock(pos, state.setValue(AGE, 0), UPDATE_CLIENTS)
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
return ItemInteractionResult.SUCCESS
} else if (isHoneyBottle && !isAtMaxAge(state)) {
if (level.isClientSide) return ItemInteractionResult.SUCCESS
// Decrement stack if not in creative mode
itemStack.consume(1, player)
if (!player.isCreative) {
itemStack.consume(1, player)
if (stack.isEmpty) {
// Replace the consumed honey bottle with an empty bottle
player.setItemInHand(hand, ItemStack(Items.GLASS_BOTTLE));
} else {
player.addItem(Items.GLASS_BOTTLE.defaultInstance)
}
}
level.playSound(null, pos, SoundEvents.HONEY_BLOCK_PLACE, SoundSource.BLOCKS)
level.setBlock(pos, state.setValue(AGE, 2), 2)
level.setBlock(pos, state.setValue(AGE, 2), UPDATE_CLIENTS)
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
return ItemInteractionResult.SUCCESS
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.block.campfirepot
import com.cobblemon.mod.common.CobblemonMenuType
import com.cobblemon.mod.common.CobblemonRecipeBookTypes.COOKING_POT
import com.cobblemon.mod.common.CobblemonRecipeTypes
import com.cobblemon.mod.common.api.cooking.Seasonings
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity
@@ -211,7 +212,7 @@ class CookingPotMenu : RecipeBookMenu<CraftingInput, CookingPotRecipeBase>, Cont
}
override fun getRecipeBookType(): RecipeBookType {
return RecipeBookType.valueOf("COOKING_POT")
return COOKING_POT
}
override fun shouldMoveToInventory(slotIndex: Int): Boolean {
@@ -111,13 +111,18 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
BlockEntitySoundTracker.stop(pos, campfireBlockEntity.ambientSound.location)
}
campfireBlockEntity.brothColor =
getColourMixFromSeasonings(campfireBlockEntity.getSeasonings())
?: BASE_BROTH_COLOR
val seasonings = campfireBlockEntity.getSeasonings()
if (seasonings.size != campfireBlockEntity.lastSeasoningStacks.size || seasonings.any { it !in campfireBlockEntity.lastSeasoningStacks }) {
campfireBlockEntity.lastSeasoningStacks = seasonings
campfireBlockEntity.bubbleColor =
getColourMixFromSeasonings(campfireBlockEntity.getSeasonings(), true)
?: BASE_BROTH_BUBBLE_COLOR
campfireBlockEntity.brothColor =
getColourMixFromSeasonings(seasonings)
?: BASE_BROTH_COLOR
campfireBlockEntity.bubbleColor =
getColourMixFromSeasonings(seasonings, true)
?: BASE_BROTH_BUBBLE_COLOR
}
if (campfireBlockEntity.particleCooldown > 0) {
campfireBlockEntity.particleCooldown--
@@ -241,6 +246,9 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
var bubbleColor: Int = BASE_BROTH_BUBBLE_COLOR
var time: Int = 0
/** Used to know if we should be changing the colour of the broth or if we can go with the previous colour. */
var lastSeasoningStacks = listOf<ItemStack>()
var dataAccess: ContainerData = object : ContainerData {
override fun get(index: Int): Int {
return when (index) {
@@ -49,7 +49,6 @@ import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.state.BlockState
import java.util.*
open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) :
TintBlockEntity(CobblemonBlockEntities.POKE_SNACK, pos, state),
@@ -120,7 +119,7 @@ open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) :
level.dimension(),
)
block.eat(level, blockPos, blockState, action.spawnablePosition.cause.entity as? Player)
block.eat(level, blockPos, blockState, null)
}
}
@@ -74,6 +74,7 @@ import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.isLookingAt
import net.minecraft.client.Minecraft
import net.minecraft.client.color.block.BlockColor
@@ -83,16 +84,19 @@ import net.minecraft.client.gui.screens.Screen
import net.minecraft.client.model.BoatModel
import net.minecraft.client.model.ChestBoatModel
import net.minecraft.client.model.PlayerModel
import net.minecraft.client.player.LocalPlayer
import net.minecraft.client.renderer.RenderType
import net.minecraft.client.renderer.blockentity.HangingSignRenderer
import net.minecraft.client.renderer.blockentity.SignRenderer
import net.minecraft.client.renderer.entity.EntityRenderer
import net.minecraft.client.renderer.entity.LivingEntityRenderer
import net.minecraft.client.resources.PlayerSkin
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.packs.resources.ResourceManager
import net.minecraft.world.InteractionHand
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.AABB
import org.joml.Vector2d
object CobblemonClient {
@@ -112,6 +116,8 @@ object CobblemonClient {
val battleOverlay: BattleOverlay by lazy { BattleOverlay() }
val pokedexUsageContext: PokedexUsageContext by lazy { PokedexUsageContext() }
val rideControlsOverlay: RideControlsOverlay by lazy { RideControlsOverlay() }
val ridingTurnInputHandler: MutableMap<ResourceLocation, (LocalPlayer, Double, Double, Double) -> Vector2d> = mutableMapOf()
val ridingSprintHandler: MutableMap<ResourceLocation, () -> Boolean> = mutableMapOf()
fun onLogin() {
clientPlayerData = ClientGeneralPlayerData()
@@ -186,7 +192,7 @@ object CobblemonClient {
) { it is PokemonEntity }
nearbyPokemon?.forEach { entity ->
if (entity is PokemonEntity && !entity.isSilent) {
if (entity is PokemonEntity && !entity.isSilent && !entity.passengers.contains(player)) {
if (player.isLookingAt(entity) && !player.isSpectator && entity.pokemon.shiny) entity.delegate.spawnShinyParticle(player)
entity.delegate.spawnAspectParticle()
}
@@ -195,6 +201,8 @@ object CobblemonClient {
ClientPlayerIcon.onTick()
PartyOverlayDataControl.tick(event.client.isPaused)
}
ridingSprintHandler.put(cobblemonResource("normal")) { Minecraft.getInstance().options.keySprint.isDown }
}
private fun registerTooltipManagers() {
@@ -38,7 +38,7 @@ import kotlin.math.max
class RideControlsOverlay : Gui(Minecraft.getInstance()) {
companion object {
private const val FADE_FRAMES = 20F
private const val CONTROLS_FADE_FRAMES = 20F
private const val BASELINE_FPS = 60F
private const val HALF_SCALE = 0.5F
@@ -63,9 +63,9 @@ class RideControlsOverlay : Gui(Minecraft.getInstance()) {
private val screenExemptions: List<Class<out Screen>> = listOf(ChatScreen::class.java)
private var maxDurationFrames = Cobblemon.config.displayControlSeconds * BASELINE_FPS
private var durationFrames = maxDurationFrames
private var fadeFrames = FADE_FRAMES
private var controlsMaxDurationFrames = Cobblemon.config.displayControlSeconds * BASELINE_FPS
private var controlsDurationFrames = controlsMaxDurationFrames
private var controlsFadeFrames = CONTROLS_FADE_FRAMES
private var lastMouseX = 0
private var lastMouseY = 0
@@ -88,123 +88,132 @@ class RideControlsOverlay : Gui(Minecraft.getInstance()) {
if (minecraft.options.hideGui || minecraft.debugOverlay.showDebugScreen()) return
val riddenEntity = minecraft.player?.vehicle
if (riddenEntity != null && riddenEntity is PokemonEntity) {
// Update max duration if user has changed config
val configDuration = Cobblemon.config.displayControlSeconds * BASELINE_FPS
if (maxDurationFrames != configDuration) {
maxDurationFrames = configDuration
resetOverlayState()
}
// Don't render if duration config set to 0 or less
if (maxDurationFrames <= 0F) return
val rideBehaviourSettings = riddenEntity.ridingController?.context?.settings ?: return
val ridingBehaviourState = riddenEntity.ridingController?.context?.state ?: return
val rideBehaviourKey = rideBehaviourSettings.key
// Update current ride behaviour if changed
// If composite, get active behaviour instead
if (rideBehaviourKey == CompositeBehaviour.KEY) {
val activeBehaviour = (ridingBehaviourState as CompositeState).activeBehaviour.get()
if (currentBehaviourKey != activeBehaviour) {
currentBehaviourKey = activeBehaviour
resetOverlayState()
minecraft.player?.let { player ->
val riddenEntity = player.vehicle
if (riddenEntity != null && riddenEntity is PokemonEntity) {
// Only show controls to driver
if (riddenEntity === player.controlledVehicle) {
renderControls(minecraft, context, tickCounter, riddenEntity)
}
} else if (currentBehaviourKey != rideBehaviourKey) {
currentBehaviourKey = rideBehaviourKey
resetOverlayState()
} else {
resetControlsOverlayState()
}
// Render elements if entity has ride behaviour and if display duration has not ended yet
if (rideBehaviourSettings != null && fadeFrames > 0) {
val tickDelta = tickCounter.realtimeDeltaTicks.takeIf { !minecraft.isPaused } ?: 0F
val updateInterval = (tickDelta / 20F) * BASELINE_FPS
durationFrames = max(durationFrames - updateInterval, 0F)
if (durationFrames == 0F && fadeFrames > 0) fadeFrames = max(fadeFrames - updateInterval, 0F)
var showVerticalMouse = true // Show moving mouse up and down with arrows
var showHorizontalMouse = true // Show moving mouse left and right with arrows
var showSneakKey = true
var showJumpKey = true
var showMovementKeys = true
var disableHorizontalMovementKeys = false // Disable left and right movement keys
// Configure what controls to show for each behaviour
when (currentBehaviourKey) {
BirdBehaviour.KEY -> {}
BoatBehaviour.KEY -> {
showVerticalMouse = false
showHorizontalMouse = false
showSneakKey = false
}
BurstBehaviour.KEY -> {}
DolphinBehaviour.KEY -> {
disableHorizontalMovementKeys = true
showSneakKey = false
showJumpKey = false
}
GliderBehaviour.KEY -> {}
HelicopterBehaviour.KEY -> {}
HorseBehaviour.KEY -> {
showVerticalMouse = false
disableHorizontalMovementKeys = true
showSneakKey = false
}
HoverBehaviour.KEY -> {
showVerticalMouse = false
}
JetBehaviour.KEY -> {
showSneakKey = false
showJumpKey = false
}
MinekartBehaviour.KEY -> {
showVerticalMouse = false
showHorizontalMouse = false
showSneakKey = false
}
RocketBehaviour.KEY -> {
showVerticalMouse = false
showHorizontalMouse = false
}
VehicleBehaviour.KEY -> {}
}
val centerX = minecraft.window.guiScaledWidth / 2
val centerY = minecraft.window.guiScaledHeight / 2
renderMouseControls(
context,
!showMovementKeys && !showJumpKey && !showSneakKey,
showHorizontalMouse,
showVerticalMouse,
centerX,
centerY / 2,
fadeFrames / FADE_FRAMES
)
renderKeyControls(
context,
!showHorizontalMouse && !showVerticalMouse,
showMovementKeys,
disableHorizontalMovementKeys,
showJumpKey,
showSneakKey,
minecraft.player?.input,
centerX,
centerY / 2,
fadeFrames / FADE_FRAMES
)
}
} else {
resetOverlayState()
}
}
private fun resetOverlayState() {
if (durationFrames != maxDurationFrames) durationFrames = maxDurationFrames
if (fadeFrames != FADE_FRAMES) fadeFrames = FADE_FRAMES
private fun renderControls(minecraft: Minecraft, context: GuiGraphics, tickCounter: DeltaTracker, riddenEntity: PokemonEntity) {
// Update max duration if user has changed config
val configDuration = Cobblemon.config.displayControlSeconds * BASELINE_FPS
if (controlsMaxDurationFrames != configDuration) {
controlsMaxDurationFrames = configDuration
resetControlsOverlayState()
}
// Don't render if duration config set to 0 or less
if (controlsMaxDurationFrames <= 0F) return
val rideBehaviourSettings = riddenEntity.ridingController?.context?.settings ?: return
val ridingBehaviourState = riddenEntity.ridingController?.context?.state ?: return
val rideBehaviourKey = rideBehaviourSettings.key
// Update current ride behaviour if changed
// If composite, get active behaviour instead
if (rideBehaviourKey == CompositeBehaviour.KEY) {
val activeBehaviour = (ridingBehaviourState as CompositeState).activeBehaviour.get()
if (currentBehaviourKey != activeBehaviour) {
currentBehaviourKey = activeBehaviour
resetControlsOverlayState()
}
} else if (currentBehaviourKey != rideBehaviourKey) {
currentBehaviourKey = rideBehaviourKey
resetControlsOverlayState()
}
// Render elements if entity has ride behaviour and if display duration has not ended yet
if (rideBehaviourSettings != null && controlsFadeFrames > 0) {
val tickDelta = tickCounter.realtimeDeltaTicks.takeIf { !minecraft.isPaused } ?: 0F
val updateInterval = (tickDelta / 20F) * BASELINE_FPS
controlsDurationFrames = max(controlsDurationFrames - updateInterval, 0F)
if (controlsDurationFrames == 0F && controlsFadeFrames > 0) controlsFadeFrames = max(controlsFadeFrames - updateInterval, 0F)
var showVerticalMouse = true // Show moving mouse up and down with arrows
var showHorizontalMouse = true // Show moving mouse left and right with arrows
var showSneakKey = true
var showJumpKey = true
var showMovementKeys = true
var disableHorizontalMovementKeys = false // Disable left and right movement keys
// Configure what controls to show for each behaviour
when (currentBehaviourKey) {
BirdBehaviour.KEY -> {}
BoatBehaviour.KEY -> {
showVerticalMouse = false
showHorizontalMouse = false
showSneakKey = false
}
BurstBehaviour.KEY -> {}
DolphinBehaviour.KEY -> {
disableHorizontalMovementKeys = true
showSneakKey = false
showJumpKey = false
}
GliderBehaviour.KEY -> {}
HelicopterBehaviour.KEY -> {}
HorseBehaviour.KEY -> {
showVerticalMouse = false
disableHorizontalMovementKeys = true
showSneakKey = false
}
HoverBehaviour.KEY -> {
showVerticalMouse = false
}
JetBehaviour.KEY -> {
showSneakKey = false
showJumpKey = false
}
MinekartBehaviour.KEY -> {
showVerticalMouse = false
showHorizontalMouse = false
showSneakKey = false
}
RocketBehaviour.KEY -> {
showVerticalMouse = false
showHorizontalMouse = false
}
VehicleBehaviour.KEY -> {}
}
val centerX = minecraft.window.guiScaledWidth / 2
val centerY = minecraft.window.guiScaledHeight / 2
renderMouseControls(
context,
!showMovementKeys && !showJumpKey && !showSneakKey,
showHorizontalMouse,
showVerticalMouse,
centerX,
centerY / 2,
controlsFadeFrames / CONTROLS_FADE_FRAMES
)
renderKeyControls(
context,
!showHorizontalMouse && !showVerticalMouse,
showMovementKeys,
disableHorizontalMovementKeys,
showJumpKey,
showSneakKey,
minecraft.player?.input,
centerX,
centerY / 2,
controlsFadeFrames / CONTROLS_FADE_FRAMES
)
}
}
private fun resetControlsOverlayState() {
if (controlsDurationFrames != controlsMaxDurationFrames) controlsDurationFrames = controlsMaxDurationFrames
if (controlsFadeFrames != CONTROLS_FADE_FRAMES) controlsFadeFrames = CONTROLS_FADE_FRAMES
if (mouseMovedUp != null) {
mouseMovedUp = null
lastMouseY = 0
@@ -413,7 +422,7 @@ class RideControlsOverlay : Gui(Minecraft.getInstance()) {
if (showJump || showSneak) {
val offsetY = if (showMovement) 0 else -14
var label: MutableComponent? = null
var label: MutableComponent?
if (showJump && showSneak) {
label = "key.sneak".asTranslated().append("/").append("key.jump".asTranslated())
@@ -74,12 +74,12 @@ class InteractWheelButton(
y = y,
width = width,
height = height,
vOffset = if (isHovered(mouseX.toFloat(), mouseY.toFloat()) && isEnabled) height else 0,
vOffset = if ((isHovered(mouseX.toFloat(), mouseY.toFloat()) || isFocused) && isEnabled) height else 0,
textureHeight = height * 2,
alpha = if (isEnabled) 1f else 0.4F
)
if(isEnabled && isHovered(mouseX.toFloat(), mouseY.toFloat())){
if(isEnabled && (isHovered(mouseX.toFloat(), mouseY.toFloat()) || isFocused)){
tooltipText?.let {
context.renderTooltip(Minecraft.getInstance().font, Component.translatable(it), mouseX, mouseY)
}
@@ -23,9 +23,9 @@ class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelO
private val backgroundResource = cobblemonResource("textures/gui/interact/interact_wheel_base.png")
}
private val buttons = mutableListOf<InteractWheelButton>()
private var maxPage = 1
private var currentPage = 0
val buttons = mutableListOf<InteractWheelButton>()
var maxPage = 1
var currentPage = 0
override fun renderBlurredBackground(delta: Float) { }
override fun renderMenuBackground(context: GuiGraphics) {}
@@ -77,7 +77,7 @@ class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelO
currentPage = page
buttons.forEach { removeWidget(it) }
buttons.clear()
val orientations = Orientation.values()
val orientations = Orientation.entries.toTypedArray()
orientations.forEach { orientation ->
val option = options[orientation].toList().getOrNull(page)
addButton(orientation, option)
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.client.gui.pc
import com.cobblemon.mod.common.CobblemonNetwork
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.gui.getPixelRGB
import com.cobblemon.mod.common.api.storage.StorePosition
import com.cobblemon.mod.common.api.storage.party.PartyPosition
import com.cobblemon.mod.common.api.storage.pc.PCPosition
@@ -284,20 +283,6 @@ class StorageWidget(
height = 189,
alpha = if (screenLoaded) 1F else ((pcGui.ticksElapsed).toFloat() / 10F).coerceIn(0F, 1F)
)
} else {
val rgb = getPixelRGB(x + (SCREEN_WIDTH / 2), y + (SCREEN_HEIGHT / 2))
blitk(
matrixStack = matrices,
texture = screenGlowResource,
x = x - 17,
y = y - 17,
width = 208,
height = 189,
red = rgb.first / 255F,
green = rgb.second / 255F,
blue = rgb.third / 255F,
alpha = if (screenLoaded) 1F else ((pcGui.ticksElapsed).toFloat() / 10F).coerceIn(0F, 1F)
)
}
blitk(
@@ -592,6 +592,10 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
}
private fun switchForm(nextIndex: Boolean) {
if (visibleForms.isEmpty() || currentEntry == null) {
return
}
selectedPoseIndex = 0
if (nextIndex) {
@@ -602,6 +606,8 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
else selectedFormIndex = visibleForms.lastIndex
}
selectedFormIndex = selectedFormIndex.coerceIn(0, visibleForms.lastIndex)
setupButtons(currentEntry!!, visibleForms[selectedFormIndex])
updateAspects()
}
@@ -0,0 +1,319 @@
/*
* 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.client.integration.controlify
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.OrientationControllable
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonClient.ridingTurnInputHandler
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
import com.cobblemon.mod.common.client.gui.behaviour.BehaviourEditorScreen
import com.cobblemon.mod.common.client.gui.config.CobblemonConfigScreen
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen
import com.cobblemon.mod.common.client.gui.debug.riding.RidingStatsDebugGUI
import com.cobblemon.mod.common.client.gui.dialogue.DialogueScreen
import com.cobblemon.mod.common.client.gui.interact.battleRequest.BattleConfigureGUI
import com.cobblemon.mod.common.client.gui.interact.moveselect.MoveSelectGUI
import com.cobblemon.mod.common.client.gui.interact.partyselect.PartySelectGUI
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelGUI
import com.cobblemon.mod.common.client.gui.npc.NPCEditorScreen
import com.cobblemon.mod.common.client.gui.pc.PCGUI
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUI
import com.cobblemon.mod.common.client.gui.pokenav.PokeNav
import com.cobblemon.mod.common.client.gui.snapshots.SnapshotWarningScreen
import com.cobblemon.mod.common.client.gui.startselection.StarterSelectionScreen
import com.cobblemon.mod.common.client.gui.summary.Summary
import com.cobblemon.mod.common.client.gui.trade.TradeGUI
import com.cobblemon.mod.common.client.integration.controlify.gui.CobblemonGUIProcessor
import com.cobblemon.mod.common.client.integration.controlify.gui.InteractWheelProcessor
import com.cobblemon.mod.common.client.keybind.CobblemonKeyBinds
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.cobblemonResource
import dev.isxander.controlify.api.ControlifyApi
import dev.isxander.controlify.api.bind.ControlifyBindApi
import dev.isxander.controlify.api.bind.InputBindingBuilder
import dev.isxander.controlify.api.bind.InputBindingSupplier
import dev.isxander.controlify.api.entrypoint.ControlifyEntrypoint
import dev.isxander.controlify.api.entrypoint.InitContext
import dev.isxander.controlify.api.entrypoint.PreInitContext
import dev.isxander.controlify.bindings.BindContext
import dev.isxander.controlify.bindings.ControlifyBindings
import dev.isxander.controlify.bindings.RadialIcons
import dev.isxander.controlify.screenop.ScreenProcessorFactory
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.screens.Screen
import net.minecraft.client.player.LocalPlayer
import net.minecraft.network.chat.Component
import net.minecraft.world.item.Items
import org.joml.Vector2d
import kotlin.jvm.optionals.getOrNull
import kotlin.reflect.KClass
import kotlin.reflect.full.primaryConstructor
class CobblemonControlifyEntrypoint : ControlifyEntrypoint {
override fun onControlifyInit(initContext: InitContext) {
ridingTurnInputHandler.put(
cobblemonResource("compat.controlify"),
({ localPlayer: LocalPlayer, xDelta: Double, yDelta: Double, deltaTime: Double ->
val vec = Vector2d(xDelta, yDelta)
val controller = initContext.controlify().currentController.getOrNull()
val vehicle = localPlayer.vehicle
if (vehicle is OrientationControllable && vehicle.orientationController.isActive() && initContext.controlify().currentInputMode().isController && controller != null){
val multiplier = deltaTime * 1500
val config = controller.input().getOrNull()?.config()?.config()
val vSensitivity = config?.vLookSensitivity ?: 0.9f
val hSensitivity = config?.hLookSensitivity ?: 1f
// Should never be null once bindings are set
var vAxis = (RIDING_DOWN!!.on(controller).analogueNow() - RIDING_UP!!.on(controller).analogueNow()).toDouble()
var hAxis = (RIDING_RIGHT!!.on(controller).analogueNow() - RIDING_LEFT!!.on(controller).analogueNow()).toDouble()
vAxis *= multiplier * vSensitivity
hAxis *= multiplier * hSensitivity
vec.x = hAxis
vec.y = vAxis
}
vec
})
)
CobblemonClient.ridingSprintHandler.put(
cobblemonResource("compat.controlify")
) {
initContext.controlify().currentController.getOrNull()?.let { ControlifyBindings.SPRINT.on(it).digitalNow() } == true
}
}
override fun onControlifyPreInit(initContext: PreInitContext) {
val bindings = ControlifyBindApi.get()
bindings.registerBindContext(ORIENTATION_CONTROLLER_ACTIVE)
RIDING_UP =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("riding_up"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("controlify.bind.cobblemon.riding_up"))
.allowedContexts(ORIENTATION_CONTROLLER_ACTIVE, BindContext.IN_GAME)
}
RIDING_DOWN =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("riding_down"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("controlify.bind.cobblemon.riding_down"))
.allowedContexts(ORIENTATION_CONTROLLER_ACTIVE, BindContext.IN_GAME)
}
RIDING_LEFT =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("riding_left"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("controlify.bind.cobblemon.riding_left"))
.allowedContexts(ORIENTATION_CONTROLLER_ACTIVE, BindContext.IN_GAME)
}
RIDING_RIGHT =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("riding_right"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("controlify.bind.cobblemon.riding_right"))
.allowedContexts(ORIENTATION_CONTROLLER_ACTIVE, BindContext.IN_GAME)
}
HIDE_PARTY =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("hide_party"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("key.cobblemon.hideparty"))
.allowedContexts(BindContext.IN_GAME)
.radialCandidate(RadialIcons.getItem(Items.BARRIER))
.addKeyCorrelation(CobblemonKeyBinds.HIDE_PARTY)
.keyEmulation(CobblemonKeyBinds.HIDE_PARTY)
}
SUMMARY =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("summary"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("key.cobblemon.summary"))
.allowedContexts(BindContext.IN_GAME)
.radialCandidate(RadialIcons.getItem(CobblemonItems.GREAT_BALL))
.addKeyCorrelation(CobblemonKeyBinds.SUMMARY)
.keyEmulation(CobblemonKeyBinds.SUMMARY)
}
PARTY_OVERLAY_DOWN =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("party_overlay_down"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("key.cobblemon.downshiftparty"))
.allowedContexts(HAS_POKEMON, BindContext.IN_GAME)
.radialCandidate(RadialIcons.EMPTY)
.addKeyCorrelation(CobblemonKeyBinds.PARTY_OVERLAY_DOWN)
.keyEmulation(CobblemonKeyBinds.PARTY_OVERLAY_DOWN)
}
PARTY_OVERLAY_UP =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("party_overlay_up"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("key.cobblemon.upshiftparty"))
.allowedContexts(HAS_POKEMON, BindContext.IN_GAME)
.radialCandidate(RadialIcons.EMPTY)
.addKeyCorrelation(CobblemonKeyBinds.PARTY_OVERLAY_UP)
.keyEmulation(CobblemonKeyBinds.PARTY_OVERLAY_DOWN)
}
SEND_OUT_POKEMON =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("send_out_pokemon"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("key.cobblemon.throwpartypokemon"))
.allowedContexts(HAS_POKEMON, BindContext.IN_GAME)
.radialCandidate(RadialIcons.getItem(CobblemonItems.POKE_BALL))
.addKeyCorrelation(CobblemonKeyBinds.SEND_OUT_POKEMON)
.keyEmulation(CobblemonKeyBinds.SEND_OUT_POKEMON)
}
RIDING_FREELOOK =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("riding_freelook"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("key.cobblemon.ridingfreelook"))
.allowedContexts(RIDING_POKEMON, BindContext.IN_GAME)
.radialCandidate(RadialIcons.EMPTY)
.addKeyCorrelation(CobblemonKeyBinds.RIDING_FREELOOK)
.keyEmulation(CobblemonKeyBinds.RIDING_FREELOOK)
}
INTERACT_WHEEL_UP_AXIS =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("interact_wheel_up"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("controlify.bind.cobblemon.interact_wheel_up"))
.allowedContexts(INTERACT_WHEEL_SCREEN, BindContext.IN_GAME)
}
INTERACT_WHEEL_DOWN_AXIS =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("interact_wheel_down"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("controlify.bind.cobblemon.interact_wheel_down"))
.allowedContexts(INTERACT_WHEEL_SCREEN, BindContext.IN_GAME)
}
INTERACT_WHEEL_RIGHT_AXIS =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("interact_wheel_right"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("controlify.bind.cobblemon.interact_wheel_right"))
.allowedContexts(INTERACT_WHEEL_SCREEN, BindContext.IN_GAME)
}
INTERACT_WHEEL_LEFT_AXIS =
bindings.registerBinding { builder: InputBindingBuilder ->
builder
.id(cobblemonResource("interact_wheel_left"))
.category(Component.translatable("controlify.category.cobblemon.cobblemon"))
.name(Component.translatable("controlify.bind.cobblemon.interact_wheel_left"))
.allowedContexts(INTERACT_WHEEL_SCREEN, BindContext.IN_GAME)
}
addProcessor(InteractWheelGUI::class, InteractWheelProcessor::class)
// This is the lazy way to do all of these (just using the vmouse), if someone with more time and dedication did this that would be better
addProcessor(BattleGUI::class, CobblemonGUIProcessor::class)
addProcessor(BehaviourEditorScreen::class, CobblemonGUIProcessor::class)
addProcessor(CobblemonConfigScreen::class, CobblemonGUIProcessor::class)
addProcessor(CookingPotScreen::class, CobblemonGUIProcessor::class)
addProcessor(RidingStatsDebugGUI::class, CobblemonGUIProcessor::class)
addProcessor(DialogueScreen::class, CobblemonGUIProcessor::class)
addProcessor(BattleConfigureGUI::class, CobblemonGUIProcessor::class)
addProcessor(MoveSelectGUI::class, CobblemonGUIProcessor::class)
addProcessor(PartySelectGUI::class, CobblemonGUIProcessor::class)
addProcessor(NPCEditorScreen::class, CobblemonGUIProcessor::class)
addProcessor(PCGUI::class, CobblemonGUIProcessor::class)
addProcessor(PokedexGUI::class, CobblemonGUIProcessor::class)
addProcessor(PokeNav::class, CobblemonGUIProcessor::class)
addProcessor(SnapshotWarningScreen::class, CobblemonGUIProcessor::class)
addProcessor(StarterSelectionScreen::class, CobblemonGUIProcessor::class)
addProcessor(Summary::class, CobblemonGUIProcessor::class)
addProcessor(TradeGUI::class, CobblemonGUIProcessor::class)
}
override fun onControllersDiscovered(controlifyApi: ControlifyApi) {
}
// This is jank, but I did it after I got my wisdom teeth extracted so tbh I think I did good enough, but I won't be offended if someone changes it to something sane.
fun addProcessor(t: KClass<out Screen>, processorClazz: KClass<out CobblemonGUIProcessor>) {
ScreenProcessorFactory.registerProvider(t.java) {
processorClazz.primaryConstructor?.call(it)
}
}
companion object {
var RIDING_UP: InputBindingSupplier? = null
var RIDING_DOWN: InputBindingSupplier? = null
var RIDING_RIGHT: InputBindingSupplier? = null
var RIDING_LEFT: InputBindingSupplier? = null
var HIDE_PARTY: InputBindingSupplier? = null
var SUMMARY: InputBindingSupplier? = null
var PARTY_OVERLAY_DOWN: InputBindingSupplier? = null
var PARTY_OVERLAY_UP: InputBindingSupplier? = null
var SEND_OUT_POKEMON: InputBindingSupplier? = null
var RIDING_FREELOOK: InputBindingSupplier? = null
var INTERACT_WHEEL_UP_AXIS: InputBindingSupplier? = null
var INTERACT_WHEEL_DOWN_AXIS: InputBindingSupplier? = null
var INTERACT_WHEEL_LEFT_AXIS: InputBindingSupplier? = null
var INTERACT_WHEEL_RIGHT_AXIS: InputBindingSupplier? = null
val RIDING_POKEMON: BindContext = BindContext(
cobblemonResource("riding"),
{ mc: Minecraft ->
mc.player?.vehicle is PokemonEntity
}
)
val ORIENTATION_CONTROLLER_ACTIVE: BindContext = BindContext(
cobblemonResource("orientation_controller_active"),
{ mc: Minecraft ->
val localPlayer = mc.player
if (localPlayer == null) return@BindContext false
val vehicle = localPlayer.vehicle
vehicle is OrientationControllable && vehicle.getOrientationController().isActive()
}
)
val HAS_POKEMON: BindContext = BindContext(
cobblemonResource("has_pokemon"),
{mc: Minecraft ->
!CobblemonClient.storage.party.isEmpty()
}
)
val INTERACT_WHEEL_SCREEN: BindContext = BindContext(
cobblemonResource("wheel_screen"),
{ it.screen is InteractWheelGUI}
)
}
}
@@ -0,0 +1,22 @@
/*
* 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.client.integration.controlify.gui
import com.cobblemon.mod.common.client.integration.controlify.gui.component.ControllerComponentManager
import dev.isxander.controlify.screenop.ScreenProcessor
import dev.isxander.controlify.virtualmouse.VirtualMouseBehaviour
import net.minecraft.client.gui.screens.Screen
open class CobblemonGUIProcessor(open val screen: Screen) : ScreenProcessor<Screen>(screen) {
val controllerComponentManager = ControllerComponentManager(screen)
override fun virtualMouseBehaviour(): VirtualMouseBehaviour {
return VirtualMouseBehaviour.DISABLED
}
}
@@ -0,0 +1,70 @@
/*
* 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.client.integration.controlify.gui
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelGUI
import com.cobblemon.mod.common.client.integration.controlify.CobblemonControlifyEntrypoint
import dev.isxander.controlify.controller.ControllerEntity
import dev.isxander.controlify.controller.haptic.HapticEffects
import dev.isxander.controlify.screenop.ScreenControllerEventListener
import net.minecraft.util.Mth
import kotlin.math.abs
// Lots of this is taken from the RadialMenu in Controlify to make this screen feel consistent with it
class InteractWheelProcessor(override val screen: InteractWheelGUI) : CobblemonGUIProcessor(screen), ScreenControllerEventListener {
private var selectedButton = -1
private var idleTicks: Int = 0
private var idleTicksTimeout: Int? = null
init {
addEventListener(this)
}
override fun onControllerInput(controller: ControllerEntity) {
if (idleTicksTimeout == null) {
idleTicksTimeout = controller.input().orElseThrow().confObj().radialButtonFocusTimeoutTicks
}
// If not created from entrypoint then something is very wrong
val x = CobblemonControlifyEntrypoint.INTERACT_WHEEL_RIGHT_AXIS!!.on(controller).analogueNow()
- CobblemonControlifyEntrypoint.INTERACT_WHEEL_LEFT_AXIS!!.on(controller).analogueNow()
val y = CobblemonControlifyEntrypoint.INTERACT_WHEEL_DOWN_AXIS!!.on(controller).analogueNow()
- CobblemonControlifyEntrypoint.INTERACT_WHEEL_UP_AXIS!!.on(controller).analogueNow()
val threshold = controller.input().orElseThrow().config().config().buttonActivationThreshold
if (abs(x) >= threshold || abs(y) >= threshold) {
val angle = Mth.wrapDegrees(Mth.RAD_TO_DEG * Mth.atan2(y.toDouble(), x.toDouble()) - 90f) + 180f
val buttonCount = screen.buttons.size
val each = 360f / buttonCount
val newSelected = Mth.floor((angle + each / 2f) / each) % buttonCount
if (newSelected != selectedButton) {
selectedButton = newSelected
controller.hdHaptics().ifPresent { haptics -> haptics.playHaptic(HapticEffects.NAVIGATE) }
}
for (button in 0..<buttonCount) {
val selected = button == selectedButton
screen.buttons[button].isFocused = selected
}
idleTicks = 0
} else {
idleTicks = idleTicks+ 1
if (idleTicks>= idleTicksTimeout!! && selectedButton != -1) {
selectedButton = -1
for (button in screen.buttons) {
button.isFocused = false
}
controller.hdHaptics().ifPresent { haptics -> haptics.playHaptic(HapticEffects.NAVIGATE) }
}
}
}
}
@@ -0,0 +1,33 @@
package com.cobblemon.mod.common.client.integration.controlify.gui.component
import net.minecraft.client.gui.components.events.GuiEventListener
import net.minecraft.client.gui.screens.Screen
class ControllerComponent<T : Screen> {
var left: (T) -> ControllerComponent<T>? = { null }
var right: (T) -> ControllerComponent<T>? = { null }
var up: (T) -> ControllerComponent<T>? = { null }
var down: (T) -> ControllerComponent<T>? = { null }
var associatedGUIElement: GuiEventListener? = null
fun pairLeft(leftComponent: ControllerComponent<T>) {
left = { leftComponent }
leftComponent.right = { this }
}
fun pairRight(rightComponent: ControllerComponent<T>) {
right = { rightComponent }
rightComponent.left = { this }
}
fun pairUp(upComponent: ControllerComponent<T>) {
up = { upComponent }
upComponent.down = { this }
}
fun pairDown(downComponent: ControllerComponent<T>) {
down = { downComponent }
downComponent.up = { this }
}
}
@@ -0,0 +1,17 @@
package com.cobblemon.mod.common.client.integration.controlify.gui.component
import net.minecraft.client.gui.screens.Screen
class ControllerComponentManager<T : Screen>(val screen: T) {
var focused: ControllerComponent<T>?
get() = focused
set(value) {
focused = value
focused?.associatedGUIElement?.let { screen.focused = it }
}
fun left() = focused?.left?.invoke(screen)?.let { focused = it }
fun right() = focused?.right?.invoke(screen)?.let { focused = it }
fun up() = focused?.up?.invoke(screen)?.let { focused = it }
fun down() = focused?.down?.invoke(screen)?.let { focused = it }
}
@@ -38,6 +38,7 @@ object CobblemonKeyBinds {
val PARTY_OVERLAY_DOWN = this.queue(DownShiftPartyBinding)
val PARTY_OVERLAY_UP = this.queue(UpShiftPartyBinding)
val SEND_OUT_POKEMON = this.queue(PartySendBinding)
val RIDING_FREELOOK = this.queue(RidingFreelookBinding)
fun register(registrar: (KeyMapping) -> Unit) {
this.keyBinds.forEach(registrar::invoke)
@@ -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.client.keybind.keybinds
import com.cobblemon.mod.common.client.keybind.CobblemonBlockingKeyBinding
import com.cobblemon.mod.common.client.keybind.KeybindCategories
import com.mojang.blaze3d.platform.InputConstants
object RidingFreelookBinding : CobblemonBlockingKeyBinding(
"key.cobblemon.ridingfreelook",
InputConstants.Type.KEYSYM,
InputConstants.KEY_LALT,
KeybindCategories.COBBLEMON_CATEGORY
) {
override fun onTick() {
}
override fun onRelease() {
}
override fun onPress() {
}
}
@@ -0,0 +1,27 @@
/*
* 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.client.net.data
import com.cobblemon.mod.common.api.interaction.PokemonInteractions
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.net.messages.client.data.PokemonInteractionsSyncPacket
import net.minecraft.client.Minecraft
object PokemonInteractionsSyncHandler : ClientNetworkPacketHandler<PokemonInteractionsSyncPacket> {
override fun handle(
packet: PokemonInteractionsSyncPacket,
client: Minecraft,
) {
PokemonInteractions.speciesInteractions.clear()
PokemonInteractions.speciesInteractions.addAll(packet.speciesInteractions)
PokemonInteractions.generalInteractions.clear()
PokemonInteractions.generalInteractions.addAll(packet.generalInteractions)
}
}
@@ -8,6 +8,8 @@
package com.cobblemon.mod.common.client.persisted
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.config.CobblemonConfig
import java.io.BufferedReader
import java.io.BufferedWriter
@@ -31,7 +33,14 @@ object ClientPersistedData {
fun readSnapshotsData() : SnapshotAcknowledgementData? {
if (snapshotsPath.exists()) {
BufferedReader(InputStreamReader(FileInputStream(snapshotsPath.toFile()))).use { reader ->
return gson.fromJson(reader, SnapshotAcknowledgementData::class.java)
try {
return gson.fromJson(reader, SnapshotAcknowledgementData::class.java)
} catch (exception: Exception) {
LOGGER.error("Failed to load snapshots.json... Resetting File")
val data = SnapshotAcknowledgementData(Cobblemon.VERSION, false)
writeSnapshotsData(data)
return data
}
}
}
@@ -46,16 +55,23 @@ object ClientPersistedData {
fun readRidingPerspectivesData() : RidingPerspectiveData? {
if (ridingPerspectivesPath.exists()) {
BufferedReader(InputStreamReader(FileInputStream(ridingPerspectivesPath.toFile()))).use { reader ->
return gson.fromJson(reader, RidingPerspectiveData::class.java)
try {
return gson.fromJson(reader, RidingPerspectiveData::class.java)
} catch (exception: Exception) {
LOGGER.error("Failed to load riding_perspectives.json... Resetting File")
val data = RidingPerspectiveData()
saveRidingPerspectivesData(data)
return data
}
}
}
return null
}
fun saveRidingPerspectivesData() {
fun saveRidingPerspectivesData(data: RidingPerspectiveData) {
ridingPerspectivesPath.toFile().parentFile.mkdirs()
BufferedWriter(FileWriter(ridingPerspectivesPath.toFile())).use { writer -> gson.toJson(ridingPerspectives, writer) }
BufferedWriter(FileWriter(ridingPerspectivesPath.toFile())).use { writer -> gson.toJson(data, writer) }
}
data class SnapshotAcknowledgementData(val version: String, val dontShowAgain: Boolean)
@@ -64,7 +80,7 @@ object ClientPersistedData {
) {
fun updatePerspective(key: ResourceLocation, cameraType: CameraType) {
perspectives[key] = cameraType
saveRidingPerspectivesData()
saveRidingPerspectivesData(this)
}
}
}
@@ -34,6 +34,7 @@ import net.minecraft.world.phys.HitResult
import net.minecraft.world.phys.Vec3
import org.joml.Matrix3f
import org.joml.Quaternionf
import org.joml.Vector3d
import org.joml.Vector3f
import kotlin.math.min
import kotlin.math.sign
@@ -78,15 +79,15 @@ object MountedCameraRenderer {
// Get additional offset from poser and add to the eyeHeight offset
val currEyeHeight: Double = Mth.lerp(instance.partialTickTime.toDouble(), eyeHeight, eyeHeightOld)
val offset = Vec3(0.0, currEyeHeight - (driver.bbHeight / 2), 0.0)
val eyeOffset = Vec3(0.0, currEyeHeight - (driver.bbHeight / 2), 0.0)
var offset = Vec3(0.0, currEyeHeight - (driver.bbHeight / 2), 0.0)
var eyeOffset = Vec3(0.0, currEyeHeight - (driver.bbHeight / 2), 0.0)
val shouldFlip = !(vehicleController.active && vehicleController.orientation != null) // Do not flip the offset for 3rd person reverse unless we are using normal mc camera rotation.
val isFirstPerson = Minecraft.getInstance().options.cameraType == CameraType.FIRST_PERSON
eyeOffset.add(getFirstPersonOffset(model, locatorName))
eyeOffset = eyeOffset.add(getFirstPersonOffset(model, locatorName))
// Get the offset based on first person, third person, or third person with view bobbing enabled from the posers.
offset.add(
offset = offset.add(
if (isFirstPerson) {
getFirstPersonOffset(model, locatorName)
} else /* if (Cobblemon.config.thirdPersonViewBobbing) */ {
@@ -101,8 +102,8 @@ object MountedCameraRenderer {
else Quaternionf()
.rotateY((Math.PI.toFloat() - Mth.lerp(instance.partialTickTime, vehicle.yRotO, vehicle.yRot).toRadians()))
rotation.transform(offset.toVector3f())
rotation.transform(eyeOffset.toVector3f())
offset = rotation.transform(Vector3d(offset.x, offset.y, offset.z)).let { Vec3(it.x, it.y, it.z) }
eyeOffset = rotation.transform(Vector3d(eyeOffset.x, eyeOffset.y, eyeOffset.z)).let { Vec3(it.x, it.y, it.z) }
val eyeLocatorOffset = Vec3(locator.matrix.getTranslation(Vector3f()))
val eyePos = eyeLocatorOffset.add(entityPos)
@@ -1,120 +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.client.render.models.blockbench.pokemon.gen9
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class TinkatinkModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("tinkatink")
override val head = getPart("head")
override val rightArm = getPart("arm_right")
override val leftArm = getPart("arm_left")
override val rightLeg = getPart("leg_right")
override val leftLeg = getPart("leg_left")
override var portraitScale = 2.0F
override var portraitTranslation = Vec3(0.0, -1.01, 0.0)
override var profileScale = 1.0F
override var profileTranslation = Vec3(0.0, 0.25, 0.0)
lateinit var standing: Pose
lateinit var walking: Pose
lateinit var sleep: Pose
lateinit var battleidle: Pose
lateinit var shoulderLeft: Pose
lateinit var shoulderRight: Pose
val shoulderOffset = 1
override val cryAnimation = CryProvider { bedrockStateful("tinkatink", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("tinkatink", "blink") }
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("tinkatink", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 10,
condition = { !it.isBattling },
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("tinkatink", "ground_idle")
)
)
walking = registerPose(
poseName = "walking",
poseTypes = PoseType.MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("tinkatink", "ground_walk")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("tinkatink", "battle_idle")
)
)
shoulderLeft = registerPose(
poseType = PoseType.SHOULDER_LEFT,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("tinkatink", "shoulder_left")
),
transformedParts = arrayOf(
rootPart.createTransformation().addPosition(ModelPartTransformation.X_AXIS, shoulderOffset)
)
)
shoulderRight = registerPose(
poseType = PoseType.SHOULDER_RIGHT,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("tinkatink", "shoulder_right")
),
transformedParts = arrayOf(
rootPart.createTransformation().addPosition(ModelPartTransformation.X_AXIS, -shoulderOffset)
)
)
}
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walking, battleidle, sleep)) bedrockStateful("tinkatink", "faint") else null
}
@@ -1,87 +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.client.render.models.blockbench.pokemon.gen9
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class TinkatuffModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("tinkatuff")
override val head = getPart("head")
override val rightArm = getPart("arm_right")
override val leftArm = getPart("arm_left")
override val rightLeg = getPart("leg_right")
override val leftLeg = getPart("leg_left")
override var portraitScale = 1.9F
override var portraitTranslation = Vec3(0.0, -0.41, 0.0)
override var profileScale = 0.9F
override var profileTranslation = Vec3(0.0, 0.4, 0.0)
lateinit var standing: Pose
lateinit var walking: Pose
lateinit var sleep: Pose
lateinit var battleidle: Pose
override val cryAnimation = CryProvider { bedrockStateful("tinkatuff", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("tinkatuff", "blink") }
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("tinkatuff", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 10,
condition = { !it.isBattling },
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("tinkatuff", "ground_idle")
)
)
walking = registerPose(
poseName = "walking",
poseTypes = PoseType.MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("tinkatuff", "ground_walk")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("tinkatuff", "battle_idle")
)
)
}
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walking, battleidle, sleep)) bedrockStateful("tinkatuff", "faint") else null
}
@@ -477,8 +477,6 @@ object VaryingModelRepository {
inbuilt("illumise", ::IllumiseModel)
inbuilt("yamper", ::YamperModel)
inbuilt("boltund", ::BoltundModel)
inbuilt("tinkatink", ::TinkatinkModel)
inbuilt("tinkatuff", ::TinkatuffModel)
inbuilt("fuecoco", :: FuecocoModel)
inbuilt("crocalor", :: CrocalorModel)
inbuilt("skeledirge", :: SkeledirgeModel)
@@ -39,15 +39,16 @@ class FollowWalkTargetTask(
private var lookTargetPos: BlockPos? = null
private var speed = 0f
override fun checkExtraStartConditions(arg: ServerLevel, arg2: PathfinderMob): Boolean {
override fun checkExtraStartConditions(level: ServerLevel, entity: PathfinderMob): Boolean {
if (this.pathUpdateCountdownTicks > 0) {
--this.pathUpdateCountdownTicks
return false
} else {
val brain = arg2.brain
val brain = entity.brain
val walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get()
val hasReached = this.hasReached(arg2, walkTarget)
if (!hasReached && this.hasFinishedPath(arg2, walkTarget, arg.gameTime)) {
val hasReached = this.hasReached(entity, walkTarget)
resetPathUpdateCountdownTicks(entity)
if (!hasReached && this.hasFinishedPath(entity, walkTarget, level.gameTime)) {
this.lookTargetPos = walkTarget.target.currentBlockPosition()
return true
} else {
@@ -61,6 +62,10 @@ class FollowWalkTargetTask(
}
}
fun resetPathUpdateCountdownTicks(entity: PathfinderMob) {
pathUpdateCountdownTicks = entity.random.nextInt(20) + 20
}
override fun canStillUse(arg: ServerLevel, arg2: PathfinderMob, l: Long): Boolean {
if (this.path != null && this.lookTargetPos != null) {
val optional = arg2.brain.getMemory(MemoryModuleType.WALK_TARGET)
@@ -75,7 +80,7 @@ class FollowWalkTargetTask(
override fun stop(world: ServerLevel, entity: PathfinderMob, l: Long) {
val walkTarget = entity.brain.getMemory(MemoryModuleType.WALK_TARGET).orElse(null)
if (walkTarget != null && !this.hasReached(entity, walkTarget) && entity.navigation.isStuck) {
this.pathUpdateCountdownTicks = world.getRandom().nextInt(40)
resetPathUpdateCountdownTicks(entity)
}
entity.navigation.stop()
@@ -186,7 +186,7 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
val blockState = this.world.getBlockState(target)
val path = if (!blockState.isSolid
|| (blockState.`is`(BlockTags.LEAVES) && blockState.block == CobblemonBlocks.SACCHARINE_LEAVES && (this.entity as PokemonEntity).canPathThroughSaccLeaves())) {
|| (blockState.`is`(BlockTags.LEAVES) && blockState.block == CobblemonBlocks.SACCHARINE_LEAVES && pather.canPathThroughSaccLeaves())) {
findPath(target, distance)
} else {
blockPos = target.above()
@@ -269,7 +269,7 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
// If we can fly and we're airborne, return the current Y position
return vec.y
}
if (world.getBlockState(blockPos).block == CobblemonBlocks.SACCHARINE_LEAVES && (this.entity as PokemonEntity).canPathThroughSaccLeaves()) {
if (world.getBlockState(blockPos).block == CobblemonBlocks.SACCHARINE_LEAVES && pather.canPathThroughSaccLeaves()) {
return vec.y + 0.5
}
return if ((canFloat()) && blockGetter.getFluidState(blockPos).`is`(FluidTags.WATER)) vec.y + 0.5 else super.getGroundY(vec)
@@ -802,13 +802,14 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
spawnAction.complete()
val result = spawnAction.future
if (result.isCompletedExceptionally) {
val resultingSpawn = result.get()
if (resultingSpawn == null) {
noBite(player)
return false
}
var spawnedPokemon: PokemonEntity? = null
val resultingSpawn = result.get()
if (resultingSpawn is EntitySpawnResult) {
for (entity in resultingSpawn.entities) {
@@ -547,6 +547,11 @@ open class PokemonEntity(
ifRidingAvailable { _, _, state -> pokemon.rideStamina = state.stamina.get() }
ridingController?.context?.state?.reset()
ridingAnimationData.clear()
// reset riding orientation
if (this is OrientationControllable) {
this.orientationController.reset()
}
}
}
@@ -1203,14 +1208,13 @@ open class PokemonEntity(
}
}
if (hand == InteractionHand.MAIN_HAND && player is ServerPlayer) {
if (player.isShiftKeyDown) {
if (hand == InteractionHand.MAIN_HAND) {
if (player.isShiftKeyDown && player is ServerPlayer) {
showInteractionWheel(player, itemStack)
return InteractionResult.sidedSuccess(level().isClientSide)
}
else if (pokemon.getOwnerPlayer() == player) {
// TODO #105
if (this.attemptItemInteraction(player, player.getItemInHand(hand))) return InteractionResult.SUCCESS
else if (this.ownerUUID == player.uuid && this.attemptItemInteraction(player, player.getItemInHand(hand))) {
return InteractionResult.sidedSuccess(level().isClientSide)
}
}
@@ -1277,7 +1281,7 @@ open class PokemonEntity(
}
override fun shouldBeSaved(): Boolean {
if (ownerUUID == null && !pokemon.isNPCOwned() && (Cobblemon.config.savePokemonToWorld || isPersistenceRequired || this.pokemon.canDropHeldItem)) {
if (ownerUUID == null && !pokemon.isNPCOwned() && (Cobblemon.config.savePokemonToWorld || isPersistenceRequired)) {
CobblemonEvents.POKEMON_ENTITY_SAVE_TO_WORLD.postThen(PokemonEntitySaveToWorldEvent(this)) {
return true
}
@@ -1386,18 +1390,24 @@ open class PokemonEntity(
return bagItemLike.handleInteraction(player, battlePokemon, stack)
}
if (player !is ServerPlayer || this.isBusy) {
if (this.isBusy) {
return false
}
val interaction = PokemonInteractions.findInteraction(this)
if (interaction != null && !pokemon.isOnInteractionCooldown(interaction.grouping)) {
interaction.effects.forEach { it.applyEffect(this, player) }
pokemon.interactionCooldowns.put(interaction.grouping, runtime.resolveInt(interaction.cooldown))
if (player is ServerPlayer) {
interaction.effects.forEach { it.applyEffect(this, player) }
pokemon.interactionCooldowns.put(interaction.grouping, runtime.resolveInt(interaction.cooldown))
}
return true
}
if (player !is ServerPlayer) {
return false
}
// Evolution item logic
if (pokemon.getOwnerPlayer() == player) {
val context = ItemInteractionEvolution.ItemInteractionContext(stack, player.level())
@@ -10,8 +10,11 @@ package com.cobblemon.mod.common.entity.pokemon.ai.sensors
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.getMemorySafely
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.Mob
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities
import net.minecraft.world.entity.ai.sensing.Sensor
@@ -28,8 +31,17 @@ class DefendOwnerSensor : Sensor<PokemonEntity>(10) {
}
private fun setNearestAttacker(entity: PokemonEntity, visibleMobs: NearestVisibleLivingEntities, owner: LivingEntity) {
val nearestAttacker = visibleMobs.findClosest { mob ->
mob.lastHurtMob == owner
val nearestAttacker = visibleMobs.findClosest { livingEntity ->
// Prevents Pokémons from attacking players as owned Pokémons are currently invulnerable
if (livingEntity is ServerPlayer) return@findClosest false
if (livingEntity.lastHurtMob == owner) return@findClosest true
if (livingEntity is Mob && livingEntity.target == owner) return@findClosest true
val mobAttackTarget = livingEntity.brain.getMemorySafely(MemoryModuleType.ATTACK_TARGET)
if (mobAttackTarget.isPresent && mobAttackTarget.get() == owner) return@findClosest true
return@findClosest false
}.map { mob -> mob as LivingEntity }
entity.brain.setMemory(CobblemonMemories.NEAREST_VISIBLE_ATTACKER, nearestAttacker)
@@ -10,18 +10,10 @@ package com.cobblemon.mod.common.entity.pokemon.ai.tasks
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.google.common.collect.ImmutableMap
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.attributes.Attributes
import net.minecraft.world.entity.ai.behavior.Behavior
import net.minecraft.world.entity.ai.behavior.OneShot
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.memory.WalkTarget
import net.minecraft.world.entity.ai.targeting.TargetingConditions
object DefendOwnerTask {
fun create(): OneShot<PokemonEntity> {
@@ -52,8 +52,9 @@ object PlaceHoneyInHiveTask {
if (blockEntity.isFull) {
// Erase Hive memory and give the bee a moment to locate a new hive
entity.brain.eraseMemory(CobblemonMemories.HIVE_LOCATION)
} else {
blockEntity.addOccupant(entity)
}
blockEntity.addOccupant(entity)
}
return@Trigger true
@@ -30,21 +30,13 @@ import com.cobblemon.mod.common.api.events.battles.BattleStartedEvent
import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
import com.cobblemon.mod.common.api.events.fishing.PokerodCastEvent
import com.cobblemon.mod.common.api.events.fishing.PokerodReelEvent
import com.cobblemon.mod.common.api.events.pokemon.CollectEggEvent
import com.cobblemon.mod.common.api.events.pokemon.FossilRevivedEvent
import com.cobblemon.mod.common.api.events.pokemon.HatchEggEvent
import com.cobblemon.mod.common.api.events.pokemon.LevelUpEvent
import com.cobblemon.mod.common.api.events.pokemon.PokemonCapturedEvent
import com.cobblemon.mod.common.api.events.pokemon.PokemonGainedEvent
import com.cobblemon.mod.common.api.events.pokemon.RidePokemonEvent
import com.cobblemon.mod.common.api.events.pokemon.TradeEvent
import com.cobblemon.mod.common.api.events.pokemon.*
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEvent
import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent
import com.cobblemon.mod.common.api.stats.CobblemonStats.getStat
import com.cobblemon.mod.common.util.getPlayer
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import java.util.UUID
import java.util.*
object StatHandler : EventHandler {
override fun registerListeners() {
@@ -100,13 +92,13 @@ object StatHandler : EventHandler {
fun onBattleStart(event : BattleStartedEvent) {
event.battle.players.forEach { player ->
player.awardStat(this.getStat(getStat(Cobblemon.statistics.BATTLES_TOTAL)))
player.awardStat(getStat(Cobblemon.statistics.BATTLES_TOTAL))
}
}
fun onDexEntryGain(event : PokemonGainedEvent) {
val player = event.pokemon.getOwnerPlayer()
player?.awardStat(getStat(getStat(Cobblemon.statistics.DEX_ENTRIES)))
player?.awardStat(getStat(Cobblemon.statistics.DEX_ENTRIES))
}
fun onCollectEgg(event : CollectEggEvent) {
@@ -139,12 +131,4 @@ object StatHandler : EventHandler {
fun onReelIn(event : PokerodReelEvent) {
event.player.awardStat(getStat(Cobblemon.statistics.REEL_INS))
}
fun getStat(resourceLocation: ResourceLocation) : ResourceLocation {
val stat = BuiltInRegistries.CUSTOM_STAT.get(resourceLocation)
if (stat == null) {
Cobblemon.LOGGER.error("Could not find stat with id {}", resourceLocation)
}
return stat ?: throw NullPointerException("Could not find stat with id $resourceLocation")
}
}
@@ -25,9 +25,7 @@ class MochiItem(stat: Stats): EVIncreaseItem(stat, 4) {
}
pokemon.feedPokemon(1)
stack.consume(1, player)
return super.applyToPokemon(player, stack, pokemon)
}
}
@@ -23,7 +23,6 @@ import net.minecraft.world.level.Level
class PonigiriItem : Item(
Properties().stacksTo(64)
.food(FoodProperties.Builder()
.alwaysEdible()
.nutrition(2)
.saturationModifier(0.55f)
.build())
@@ -35,9 +35,16 @@ class SinisterTeaItem : Item(
val effectsComponent = stack.get(CobblemonItemComponents.MOB_EFFECTS)
if (effectsComponent != null) {
for (effect in effectsComponent.mobEffects) {
val effectCopy = MobEffectInstance(effect)
user.addEffect(effectCopy)
for (raw in effectsComponent.mobEffects) {
val inst = MobEffectInstance(raw)
val holder = inst.effect
val effect = holder.value()
if (effect.isInstantenous) {
effect.applyInstantenousEffect(user as? Player, null, user, inst.amplifier, 1.0)
} else {
user.addEffect(inst)
}
}
}
}
@@ -0,0 +1,48 @@
/*
* 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.net.messages.client.data
import com.cobblemon.mod.common.api.interaction.PokemonInteractionSet
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.RegistryFriendlyByteBuf
class PokemonInteractionsSyncPacket(
val speciesInteractions: List<PokemonInteractionSet>,
val generalInteractions: List<PokemonInteractionSet>,
) : NetworkPacket<PokemonInteractionsSyncPacket> {
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeCollection(speciesInteractions) { it, speciesInteraction ->
speciesInteraction.encode(it)
}
buffer.writeCollection(generalInteractions) { it, generalInteraction ->
generalInteraction.encode(it)
}
}
companion object {
val ID = cobblemonResource("pokemon_interactions_sync")
fun decode(buffer: RegistryFriendlyByteBuf): PokemonInteractionsSyncPacket {
val speciesInteractions = buffer.readList { it ->
PokemonInteractionSet.decode(it)
}
val generalInteractions = buffer.readList { it ->
PokemonInteractionSet.decode(it)
}
return PokemonInteractionsSyncPacket(
speciesInteractions,
generalInteractions,
)
}
}
}
@@ -21,7 +21,9 @@ class PokemonStateUpdatePacket(pokemon: () -> Pokemon?, value: PokemonState): Si
value.writeToBuffer(buffer)
}
override fun set(pokemon: Pokemon, value: PokemonState) { pokemon.state = value }
override fun set(pokemon: Pokemon, value: PokemonState) {
pokemon.state = value
}
companion object {
val ID = cobblemonResource("state_update")
@@ -13,30 +13,24 @@ import com.cobblemon.mod.common.api.mark.Marks
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.entity.PlatformType
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readEnumConstant
import com.cobblemon.mod.common.util.readIdentifier
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.readText
import com.cobblemon.mod.common.util.writeEnumConstant
import com.cobblemon.mod.common.util.writeIdentifier
import com.cobblemon.mod.common.util.writeString
import com.cobblemon.mod.common.util.writeText
import java.util.UUID
import com.cobblemon.mod.common.util.*
import net.minecraft.client.multiplayer.ClientLevel
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.Entity
import java.util.*
class SpawnPokemonPacket(
var ownerId: UUID?,
var pokemonUUID: UUID,
var storageUUID: UUID?,
var scaleModifier: Float,
var speciesId: ResourceLocation,
var gender: Gender,
@@ -61,6 +55,7 @@ class SpawnPokemonPacket(
var tickSpawned: Int,
var rideBoosts: Map<RidingStat, Float>,
var rideStamina: Float,
var silent: Boolean,
vanillaSpawnPacket: ClientboundAddEntityPacket,
) : SpawnExtraDataEntityPacket<SpawnPokemonPacket, PokemonEntity>(vanillaSpawnPacket) {
@@ -69,6 +64,7 @@ class SpawnPokemonPacket(
constructor(entity: PokemonEntity, vanillaSpawnPacket: ClientboundAddEntityPacket) : this(
entity.ownerUUID,
entity.pokemon.uuid,
entity.pokemon.storeCoordinates.get()?.store?.uuid,
entity.pokemon.scaleModifier,
entity.exposedSpecies.resourceIdentifier,
entity.pokemon.gender,
@@ -93,12 +89,14 @@ class SpawnPokemonPacket(
entity.tickCount,
entity.entityData.get(PokemonEntity.RIDE_BOOSTS),
entity.entityData.get(PokemonEntity.RIDE_STAMINA),
entity.isSilent,
vanillaSpawnPacket
)
override fun encodeEntityData(buffer: RegistryFriendlyByteBuf) {
buffer.writeNullable(ownerId) { _, v -> buffer.writeUUID(v) }
buffer.writeUUID(this.pokemonUUID)
buffer.writeNullable(this.storageUUID) { pb, value -> pb.writeUUID(value) }
buffer.writeFloat(this.scaleModifier)
buffer.writeIdentifier(this.speciesId)
buffer.writeEnumConstant(this.gender)
@@ -127,10 +125,21 @@ class SpawnPokemonPacket(
{ _, value -> buffer.writeFloat(value) }
)
buffer.writeFloat(rideStamina)
buffer.writeBoolean(silent)
}
override fun applyData(entity: PokemonEntity, level: ClientLevel) {
entity.ownerUUID = ownerId
// Reuse the stored Pokémon instance to avoid creating a duplicate,
// preventing client/entity desync issues.
this@SpawnPokemonPacket.storageUUID?.let {
val storedPokemon = CobblemonClient.storage.locatePokemon(it, this@SpawnPokemonPacket.pokemonUUID)
if (storedPokemon != null) {
entity.pokemon = storedPokemon
}
}
entity.pokemon.apply {
uuid = this@SpawnPokemonPacket.pokemonUUID
scaleModifier = this@SpawnPokemonPacket.scaleModifier
@@ -162,6 +171,7 @@ class SpawnPokemonPacket(
entity.entityData.set(PokemonEntity.RIDE_BOOSTS, rideBoosts)
entity.entityData.set(PokemonEntity.RIDE_STAMINA, rideStamina)
entity.entityData.set(PokemonEntity.SCALE_MODIFIER, scaleModifier)
entity.isSilent = silent
entity.ejectPassengers()
passengers.forEach {
@@ -179,6 +189,7 @@ class SpawnPokemonPacket(
fun decode(buffer: RegistryFriendlyByteBuf): SpawnPokemonPacket {
val ownerId = buffer.readNullable { buffer.readUUID() }
val pokemonUUID = buffer.readUUID()
val storageUUID = buffer.readNullable { buffer.readUUID() }
val scaleModifier = buffer.readFloat()
val speciesId = buffer.readIdentifier()
val gender = buffer.readEnumConstant(Gender::class.java)
@@ -206,11 +217,13 @@ class SpawnPokemonPacket(
{ buffer.readFloat() }
)
val rideStamina = buffer.readFloat()
val silent = buffer.readBoolean()
val vanillaPacket = decodeVanillaPacket(buffer)
return SpawnPokemonPacket(
ownerId,
pokemonUUID,
storageUUID,
scaleModifier,
speciesId,
gender,
@@ -235,6 +248,7 @@ class SpawnPokemonPacket(
tickSpawned,
rideBoosts,
rideStamina,
silent,
vanillaPacket
)
}
@@ -1437,6 +1437,11 @@ open class Pokemon : ShowdownIdentifiable {
}
fun getOwnerEntity(): LivingEntity? {
if (isClient) {
val ownerUUID = entity?.ownerUUID ?: return null
return entity?.level()?.getPlayerByUUID(ownerUUID)
}
return storeCoordinates.get()?.let {
if (isPlayerOwned()) {
server()?.playerList?.getPlayer(it.store.uuid)
@@ -8,13 +8,22 @@
package com.cobblemon.mod.common.pokemon.adapters
import com.cobblemon.mod.common.api.interaction.InteractionEffect
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.adapters.RequirementAdapter
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.requirements.*
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeString
import com.google.common.collect.HashBiMap
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonElement
import com.google.gson.JsonSerializationContext
import com.google.gson.*
import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.LowerCaseEnumTypeAdapterFactory
import java.lang.reflect.Type
import kotlin.reflect.KClass
@@ -60,21 +69,60 @@ object CobblemonRequirementAdapter : RequirementAdapter {
this.registerType(OwnerHoldsItemRequirement.ADAPTER_VARIANT, OwnerHoldsItemRequirement::class)
}
val gson: Gson by lazy {
GsonBuilder()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
.registerTypeAdapter(Requirement::class.java, CobblemonRequirementAdapter)
.registerTypeAdapter(InteractionEffect::class.java, InteractionEffectAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
.registerTypeAdapterFactory(LowerCaseEnumTypeAdapterFactory())
.setPrettyPrinting()
.create()
}
override fun <T : Requirement> registerType(id: String, type: KClass<T>) {
this.types[id.lowercase()] = type
}
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Requirement {
val variant = json.asJsonObject.get(VARIANT).asString.lowercase()
val type = this.types[variant] ?: throw IllegalArgumentException("Cannot resolve evolution requirement type for variant $variant")
val type = getRequirementType(variant)
return context.deserialize(json, type.java)
}
override fun serialize(src: Requirement, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
val json = context.serialize(src, src::class.java).asJsonObject
val variant = this.types.inverse()[src::class] ?: throw IllegalArgumentException("Cannot resolve evolution requirement for type ${src::class.qualifiedName}")
override fun serialize(requirement: Requirement, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
val json = context.serialize(requirement, requirement::class.java).asJsonObject
val variant = getVariant(requirement)
json.addProperty(VARIANT, variant)
return json
}
fun encode(requirement: Requirement, buffer: FriendlyByteBuf) {
buffer.writeString(gson.toJson(requirement, Requirement::class.java))
}
fun decode(buffer: FriendlyByteBuf): Requirement {
return gson.fromJson(buffer.readString(), Requirement::class.java)
}
private fun getVariant(requirement: Requirement): String {
val variant = this.types.inverse()[requirement::class]
if (variant == null) {
throw IllegalArgumentException("Cannot resolve evolution requirement for type ${requirement::class.qualifiedName}")
}
return variant
}
private fun getRequirementType(variant: String): KClass<out Requirement> {
val requirementType = this.types[variant]
if (requirementType == null) {
throw IllegalArgumentException("Cannot resolve evolution requirement type for variant $variant")
}
return requirementType
}
}
@@ -11,9 +11,9 @@ package com.cobblemon.mod.common.pokemon.requirements
import com.cobblemon.mod.common.api.pokemon.requirement.OwnerQueryRequirement
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.server.level.ServerPlayer
import net.minecraft.resources.ResourceLocation
import kotlin.collections.iterator
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.player.Player
/**
* An [com.cobblemon.mod.common.api.pokemon.requirement.Requirement] that checks if the player has a certain [net.minecraft.advancements.Advancement]
@@ -26,13 +26,16 @@ class AdvancementRequirement(val requiredAdvancement: ResourceLocation) : OwnerQ
override fun checkPlayer(
pokemon: Pokemon,
owner: ServerPlayer
owner: Player
): Boolean {
for (entry in owner.advancements.progress) {
val serverPlayer = owner as? ServerPlayer ?: return false
for (entry in serverPlayer.advancements.progress) {
if (entry.key.id == requiredAdvancement && entry.value.isDone) {
return true
}
}
return false
}
@@ -12,11 +12,9 @@ import com.cobblemon.mod.common.api.pokemon.requirement.OwnerQueryRequirement
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.server.level.ServerPlayer
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.InteractionHand
import net.minecraft.world.entity.LivingEntity
import kotlin.collections.iterator
import net.minecraft.world.entity.player.Player
/**
* An [OwnerQueryRequirement] that checks if the player/npc is holding a certain [ItemPredicate]
@@ -30,7 +28,7 @@ class OwnerHoldsItemRequirement(val itemCondition: ItemPredicate)
override fun checkPlayer(
pokemon: Pokemon,
owner: ServerPlayer
owner: Player
): Boolean {
return checkItem(owner)
}
@@ -8,22 +8,22 @@
package com.cobblemon.mod.common.util.adapters
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonSerializationContext
import com.google.gson.JsonSerializer
import com.google.gson.*
import com.mojang.serialization.Codec
import com.mojang.serialization.JsonOps
import java.lang.reflect.Type
class CodecBackedAdapter<T>(val codec: Codec<T>) : JsonDeserializer<T>, JsonSerializer<T> {
override fun deserialize(
jElement: JsonElement,
typeOfT: Type,
context: JsonDeserializationContext
): T {
return JsonOps.INSTANCE.withDecoder(codec).apply(jElement).result().get().first as T
val ops = RegistryOpsProvider.getOpsWithDefaultFallback()
val result = ops.withDecoder(codec).apply(jElement)
return result.result().orElseThrow {
IllegalStateException("Failed to deserialize $jElement: ${result.error().orElse(null)}")
}.first
}
override fun serialize(
@@ -31,6 +31,10 @@ class CodecBackedAdapter<T>(val codec: Codec<T>) : JsonDeserializer<T>, JsonSeri
typeOfSrc: Type?,
context: JsonSerializationContext?
): JsonElement {
return JsonOps.INSTANCE.withEncoder(codec).apply(src).result().get()
val ops = RegistryOpsProvider.getOpsWithDefaultFallback()
val result = ops.withEncoder(codec).apply(src)
return result.result().orElseThrow {
IllegalStateException("Failed to serialize $src: ${result.error().orElse(null)}")
}
}
}
@@ -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.util.adapters
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Environment
import com.cobblemon.mod.common.util.server
import com.google.gson.JsonElement
import com.mojang.serialization.DynamicOps
import com.mojang.serialization.JsonOps
import net.minecraft.client.Minecraft
import net.minecraft.resources.RegistryOps
/**
* Utility for obtaining RegistryOps with the correct client/server registry access.
* Used when manually encoding/decoding registry-backed values (e.g., items, predicates).
*/
object RegistryOpsProvider {
fun getOpsWithDefaultFallback(): DynamicOps<JsonElement> {
if (Cobblemon.implementation.environment() == Environment.CLIENT) {
val minecraft = Minecraft.getInstance()
if (minecraft != null && minecraft.level != null)
return RegistryOps.create(JsonOps.INSTANCE, minecraft.level!!.registryAccess())
}
if (Cobblemon.implementation.environment() == Environment.SERVER) {
val server = server()
if (server != null)
return RegistryOps.create(JsonOps.INSTANCE, server.registryAccess())
}
return JsonOps.INSTANCE
}
}
@@ -297,6 +297,11 @@
"1.0833": [0, 0, 0]
}
}
},
"sound_effects": {
"0.25": {
"effect": "pokemon.ditto.cry"
}
}
},
"animation.ditto.blink": {
@@ -3,7 +3,7 @@
"animations": {
"animation.metagross.ground_idle": {
"loop": true,
"animation_length": 11.4167,
"animation_length": 0,
"bones": {
"body2": {
"position": [0, -11.9, 0]
@@ -299,6 +299,14 @@
"rotation": [0, 0, 15]
}
}
},
"animation.eelektrik.cry": {
"animation_length": 1.25,
"sound_effects": {
"0.0417": {
"effect": "pokemon.eelektrik.cry"
}
}
}
}
}
@@ -869,6 +869,14 @@
"position": [-0.1, 0, 0]
}
}
},
"animation.eelektross.cry": {
"animation_length": 1.25,
"sound_effects": {
"0.0417": {
"effect": "pokemon.eelektross.cry"
}
}
}
}
}
@@ -84,7 +84,7 @@
"position": [0, "0+Math.cos((query.anim_time) * 90 * 8 - 60) * -0.1", 0]
},
"hair3": {
"rotation": ["0+Math.cos((query.anim_time) * 90 * 8 - 100) * 3", 0, 0]
"rotation": ["-2+Math.cos((query.anim_time) * 90 * 8 - 100) * 3", 0, 0]
},
"hair": {
"rotation": ["0+Math.cos((query.anim_time) * 90 * 8 - 120) * 10", 12.5, "0+Math.cos((query.anim_time) * 90 * 4 - 180) * 10"]
@@ -356,7 +356,7 @@
"position": [-1.63659, -1.07651, 3.16823]
},
"arm_right": {
"rotation": [-80.89079, -82.69097, -6.55875]
"rotation": [-99.86576, -52.80463, 0.06108]
},
"finger_right": {
"rotation": [0, 0, 17.5]
@@ -375,6 +375,21 @@
},
"arm_hammer_left": {
"rotation": [-85, 100, 0]
},
"hand_right": {
"rotation": [0, 0, -22.5]
},
"brow_right": {
"position": [0, -0.75, 0]
},
"brow_left": {
"position": [0, -0.75, 0]
},
"eyes_ditto": {
"position": [0, 0, 0.1]
},
"eyes_blink_ditto": {
"position": [0, 0, -0.1]
}
}
},
@@ -460,40 +475,26 @@
"1.875": [0, 0, 0]
}
},
"eyelid_right": {
"position": {
"0.375": [0, 0, 0],
"0.4167": [0, 0, -0.125],
"0.625": [0, 0, -0.125],
"0.6667": [0, 0, 0],
"0.8333": [0, 0, 0],
"0.875": [0, 0, -0.125],
"1.5833": [0, 0, -0.125],
"1.625": [0, 0, 0],
"1.7083": [0, 0, 0],
"1.75": [0, 0, -0.125]
}
},
"eyelid_left": {
"position": {
"0.375": [0, 0, 0],
"0.4167": [0, 0, -0.125],
"0.625": [0, 0, -0.125],
"0.4167": [0, 0, -0.1],
"0.625": [0, 0, -0.1],
"0.6667": [0, 0, 0],
"0.8333": [0, 0, 0],
"0.875": [0, 0, -0.125],
"1.5833": [0, 0, -0.125],
"1.625": [0, 0, 0],
"0.875": [0, 0, -0.1],
"1.5833": [0, 0, -0.1],
"1.625": [0, 0, 1],
"1.7083": [0, 0, 0],
"1.75": [0, 0, -0.125]
"1.75": [0, 0, -0.1]
}
},
"mouth_open": {
"mouth_open_cry": {
"position": {
"0.8333": [0, 0, 0],
"0.875": [0, 0, -0.125],
"1.875": [0, 0, -0.125],
"1.9167": [0, 0, 0]
"0.875": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"1.875": {"pre": [0, 0, -0.1], "post": [0, 0, -0.1]},
"1.9167": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"arm_left": {
@@ -556,13 +557,6 @@
"1.75": [0, 0, 0]
}
},
"eye_right": {
"scale": {
"1.5833": [1, 1, 1],
"1.625": [1.4, 1.4, 3.3],
"1.7083": [1, 1, 1]
}
},
"eye_left": {
"scale": {
"1.5833": [1, 1, 1],
@@ -722,6 +716,55 @@
"1.7083": [1, 1, 1]
}
},
"leg_left": {
"rotation": {
"0.0": [0, 0, 0],
"0.2917": [0, -20, -2.5],
"0.4167": [-5.68, -13.75, -2.5],
"0.5833": [-32.36, -7.5, -2.5],
"0.7083": [-40.5, 2.5, -2.5],
"0.75": [-33.83, 2.5, -2.5],
"0.8333": [-30.5, 2.5, -2.5]
},
"position": {
"0.4167": [0, 0, 0],
"0.5833": [0, 0, -0.75],
"1.5833": [0, 0, -0.75],
"1.625": [1.25, 0, -0.75],
"1.75": [0, 0, 0]
}
},
"arm_hammer_left": {
"rotation": {
"0.0": [0, 0, 17.5],
"0.25": [0, -25, 5],
"0.4167": [0, -32.5, 3.5],
"0.5": [-11.25, 40.75, -16.75],
"0.5833": [-22.5, 46.75, -37],
"0.7083": [-25, 44, -40.75]
}
},
"eye_right": {
"scale": {
"1.5833": [1, 1, 1],
"1.625": [1.4, 1.4, 3.3],
"1.7083": [1, 1, 1]
}
},
"eyelid_right": {
"position": {
"0.375": [0, 0, 0],
"0.4167": [0, 0, -0.1],
"0.625": [0, 0, -0.1],
"0.6667": [0, 0, 0],
"0.8333": [0, 0, 0],
"0.875": [0, 0, -0.1],
"1.5833": [0, 0, -0.1],
"1.625": [0, 0, 1],
"1.7083": [0, 0, 0],
"1.75": [0, 0, -0.1]
}
},
"arm_right": {
"rotation": {
"0.0": [0, 0, -20],
@@ -753,24 +796,6 @@
"finger_right3": {
"rotation": [0, 0, -22.5]
},
"leg_left": {
"rotation": {
"0.0": [0, 0, 0],
"0.2917": [0, -20, -2.5],
"0.4167": [-5.68, -13.75, -2.5],
"0.5833": [-32.36, -7.5, -2.5],
"0.7083": [-40.5, 2.5, -2.5],
"0.75": [-33.83, 2.5, -2.5],
"0.8333": [-30.5, 2.5, -2.5]
},
"position": {
"0.4167": [0, 0, 0],
"0.5833": [0, 0, -0.75],
"1.5833": [0, 0, -0.75],
"1.625": [1.25, 0, -0.75],
"1.75": [0, 0, 0]
}
},
"leg_right": {
"rotation": {
"0.0": [0, 0, 0],
@@ -789,33 +814,146 @@
"1.75": [-0.5, 0, 0]
}
},
"arm_hammer_left": {
"rotation": {
"0.0": [0, 0, 17.5],
"0.25": [0, -25, 5],
"0.4167": [0, -32.5, 3.5],
"0.5": [-11.25, 40.75, -16.75],
"0.5833": [-22.5, 46.75, -37],
"0.7083": [-25, 44, -40.75]
"brow_left": {
"position": {
"0.375": [0, 0, 0],
"0.4167": [0, -0.75, 0],
"0.625": [0, -0.75, 0],
"0.6667": [0, 0, 0],
"0.8333": [0, 0, 0],
"0.875": [0, -0.75, 0],
"1.5833": [0, -0.75, 0],
"1.625": [0, 0, 0],
"1.7083": [0, 0, 0],
"1.75": [0, -0.75, 0]
}
},
"brow_right": {
"position": {
"0.375": [0, 0, 0],
"0.4167": [0, -0.75, 0],
"0.625": [0, -0.75, 0],
"0.6667": [0, 0, 0],
"0.8333": [0, 0, 0],
"0.875": [0, -0.75, 0],
"1.5833": [0, -0.75, 0],
"1.625": [0, 0, 0],
"1.7083": [0, 0, 0],
"1.75": [0, -0.75, 0]
}
},
"mouth_closed": {
"position": {
"0.8333": [0, 0, 0],
"0.875": {"pre": [0, 0, 0], "post": [0, -0.5, 0]},
"1.875": {"pre": [0, -0.5, 0], "post": [0, -0.5, 0]},
"1.9167": {"pre": [0, -0.5, 0], "post": [0, 0, 0]}
}
},
"mouth_lip_top": {
"position": {
"0.8333": [0, 0, 0],
"0.875": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"1.875": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
"1.9167": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyes_ditto": {
"position": {
"0.375": [0, 0, 0],
"0.4167": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"0.625": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
"0.6667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
"0.8333": {"pre": [0, 0, 0], "post": [0, 0, 0]},
"0.875": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"1.5833": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
"1.75": {"pre": [0, 0, 0], "post": [0, 0, 0.1]}
},
"scale": {
"1.5833": [1, 1, 1],
"1.625": [1.4, 1.4, 3.3],
"1.7083": [1, 1, 1]
}
},
"eyes_blink_ditto": {
"position": {
"0.375": [0, 0, 0],
"0.4167": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"0.625": {"pre": [0, 0, -0.1], "post": [0, 0, -0.1]},
"0.6667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
"0.8333": {"pre": [0, 0, 0], "post": [0, 0, 0]},
"0.875": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"1.5833": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
"1.75": {"pre": [0, 0, 0], "post": [0, 0, -0.1]}
}
},
"mouth_ditto": {
"position": {
"0.8333": [0, 0, 0],
"0.875": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"1.875": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
"1.9167": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"mouth_open_ditto": {
"position": {
"0.8333": [0, 0, 0],
"0.875": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"1.875": {"pre": [0, 0, -0.1], "post": [0, 0, -0.1]},
"1.9167": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
}
},
"animation.tinkatink.blink": {
"animation_length": 0.16667,
"animation_length": 0.1667,
"bones": {
"eyelid_right": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"brow_left": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"brow_right": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eye_left": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyes_ditto": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyes_blink_ditto": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
}
@@ -823,38 +961,6 @@
"animation.tinkatink.cry": {
"animation_length": 1.5,
"bones": {
"neck": {
"rotation": {
"0.0": [0, 0, 0],
"0.25": [10, 0, 0],
"1.25": [10, 0, 0],
"1.5": [0, 0, 0]
}
},
"mouth": {
"position": {
"0.0": [0, 0, 0],
"0.25": [0, -2, 0],
"1.25": [0, -2, 0],
"1.5": [0, 0, 0]
}
},
"mouth2": {
"position": {
"0.0": [0, 0, 0],
"0.25": [0, -5, 0],
"1.25": [0, -5, 0],
"1.5": [0, 0, 0]
}
},
"jaw": {
"position": {
"0.0": [0, 0, 0],
"0.25": [0, -3, 0],
"1.25": [0, -3, 0],
"1.5": [0, 0, 0]
}
},
"head": {
"rotation": {
"0.0": [0, 0, 0],
@@ -863,60 +969,12 @@
"1.5": [0, 0, 0]
}
},
"head2": {
"rotation": {
"0.0": [0, 0, 0],
"0.25": [-15, 0, 0],
"1.25": [-15, 0, 0],
"1.5": [0, 0, 0]
}
},
"mouth_closed2": {
"position": {
"0.25": [0, 0, -0.1],
"0.3333": [0, 0, 0],
"1.1667": [0, 0, 0],
"1.25": [0, 0, -0.1]
}
},
"mouth_open2": {
"position": {
"0.0": [0, 0, 0.1],
"0.25": [0, 0, 0],
"1.25": [0, 0, 0],
"1.5": [0, 0, 0.1]
}
},
"head3": {
"rotation": {
"0.0": [0, 0, 0],
"0.25": [-15, 0, 0],
"1.25": [-15, 0, 0],
"1.5": [0, 0, 0]
}
},
"mouth_closed3": {
"position": {
"0.25": [0, 0, -0.1],
"0.3333": [0, 0, 0],
"1.1667": [0, 0, 0],
"1.25": [0, 0, -0.1]
}
},
"mouth_open3": {
"position": {
"0.0": [0, 0, 0.1],
"0.25": [0, 0, 0],
"1.25": [0, 0, 0],
"1.5": [0, 0, 0.1]
}
},
"mouth_open": {
"mouth_open_cry": {
"position": {
"0.0833": [0, 0, 0],
"0.1667": [0, 0, -0.15],
"1.25": [0, 0, -0.15],
"1.3333": [0, 0, 0]
"0.1667": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"1.25": {"pre": [0, 0, -0.1], "post": [0, 0, -0.1]},
"1.3333": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"arm_left": {
@@ -948,10 +1006,38 @@
"1.25": [0, 0, -2.4],
"1.5": [0, 0, 0]
}
},
"mouth_closed": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [0, -0.5, 0]},
"1.3333": {"pre": [0, -0.5, 0], "post": [0, 0, 0]}
}
},
"mouth_lip_top": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"1.3333": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"mouth_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"1.3333": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"mouth_open_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"1.3333": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
},
"sound_effects": {
"0.25": {
"0.0": {
"effect": "pokemon.tinkatink.cry"
}
}
@@ -1062,6 +1148,128 @@
"rotation": [0, 0, 32.5]
}
}
},
"animation.tinkatink.ditto_face": {
"loop": true,
"bones": {
"face": {
"position": [0, 0, 0.1],
"scale": 0
},
"face_ditto": {
"position": [0, 0, -0.1]
}
}
},
"animation.tinkatink.happy": {
"loop": true,
"bones": {
"brow_left": {
"position": [0, 0, 0.1]
},
"brow_right": {
"position": [0, 0, 0.1]
},
"eye_left": {
"position": [0, 0, 0.1]
},
"eye_right": {
"position": [0, 0, 0.1]
},
"mouth_closed": {
"position": [0, 0, 0.1]
},
"mouth_lip_top": {
"position": [0, 0, 0.1]
},
"mouth_open_happy": {
"position": [0, 0, -0.1]
},
"eyelid_happy_left": {
"position": [0, 0, -0.1]
},
"eyelid_happy_right": {
"position": [0, 0, -0.1]
}
}
},
"animation.tinkatink.angry": {
"loop": true,
"bones": {
"eye_emote_left": {
"scale": [1, 0.5, 1]
},
"eye_emote_right": {
"scale": [1, 0.5, 1]
},
"eye_emote_left2": {
"position": [0.25, 0, 0],
"scale": [0.5, 1, 1]
},
"eye_emote_right2": {
"position": [-0.25, 0, 0],
"scale": [0.5, 1, 1]
}
}
},
"animation.tinkatink.very_sad": {
"loop": true,
"bones": {
"eye_emote_left": {
"scale": [1, 0.5, 1]
},
"eye_emote_right": {
"scale": [1, 0.5, 1]
},
"eye_emote_left2": {
"position": [-0.25, 0, 0],
"scale": [0.5, 1, 1]
},
"eye_emote_right2": {
"position": [0.25, 0, 0],
"scale": [0.5, 1, 1]
}
}
},
"animation.tinkatink.hurt": {
"loop": true,
"bones": {
"brow_left": {
"position": [0, 0, 0.1]
},
"brow_right": {
"position": [0, 0, 0.1]
},
"eye_left": {
"position": [0, 0, 0.1]
},
"eye_right": {
"position": [0, 0, 0.1]
},
"eyelid_hurt_left": {
"position": [0, 0, -0.1]
},
"eyelid_hurt_right": {
"position": [0, 0, -0.1]
}
}
},
"animation.tinkatink.disinterested": {
"loop": true,
"bones": {
"eye_emote_left": {
"scale": [1, 0.5, 1]
},
"eye_emote_right": {
"scale": [1, 0.5, 1]
},
"eye_emote_left2": {
"position": [0, 0, 0.1]
},
"eye_emote_right2": {
"position": [0, 0, 0.1]
}
}
}
}
}
@@ -4,12 +4,6 @@
"animation.tinkatuff.ground_idle": {
"loop": true,
"bones": {
"tail": {
"rotation": [12.5, 0, 0]
},
"tail2": {
"rotation": [12.5, 0, 0]
},
"arm_right": {
"rotation": [55.98303, 0.22836, "-40.7651+Math.cos((query.anim_time) * 90 * 2 - 120) * 1"],
"position": [-0.25, -0.5, 0]
@@ -21,7 +15,8 @@
"rotation": [0, 0, -5]
},
"finger_right2": {
"rotation": [0, -10, 37.5]
"rotation": [0, -17.5, 37.5],
"position": [-0.25, 0, 0]
},
"arm_left": {
"rotation": [-84.39003, 4.58778, "53.5046+Math.cos((query.anim_time) * 90 * 2 - 120) * 1"]
@@ -30,17 +25,11 @@
"rotation": [0, -15, 55]
},
"finger_left": {
"rotation": [0, 0, -25]
"rotation": [0, 0, -40]
},
"finger_left2": {
"rotation": [20, 0, 0]
},
"hand_left": {
"rotation": [0, 17.5, 0]
},
"hand_right": {
"rotation": [0, -17.5, 0]
},
"leg_left": {
"rotation": [0, -12.5, -5]
},
@@ -48,7 +37,7 @@
"rotation": [0, 12.5, 5]
},
"finger_left3": {
"rotation": [0, 0, 57.5]
"rotation": [0, 0, 67.5]
},
"finger_right3": {
"rotation": [0, 0, -20]
@@ -78,9 +67,6 @@
"head": {
"rotation": ["12.5+Math.cos((query.anim_time) * 90 * 2 - 50) * 2", 0, 0]
},
"mouth_closed": {
"position": [0, 0, 0]
},
"ponytail": {
"rotation": ["0+Math.cos((query.anim_time) * 90 * 2 - 120) * 1", 0, 0]
},
@@ -187,10 +173,24 @@
}
},
"finger_right2": {
"rotation": [7.5, 0, 10]
"rotation": [7.5, 0, 42.5],
"position": [-0.25, 0.25, 0]
},
"finger_right3": {
"rotation": [-0.88045, -9.96156, 5.07673]
},
"finger_left": {
"rotation": [0, 0, -55],
"position": [0, 0.5, 0]
},
"finger_left2": {
"rotation": [0, 0, -17.5]
},
"finger_left3": {
"rotation": [0, 0, 22.5]
},
"finger_right": {
"rotation": [0, 0, 20]
}
}
},
@@ -210,7 +210,7 @@
"rotation": [-15, -2.5, 62.5]
},
"finger_left3": {
"rotation": [0, 0, 52.5]
"rotation": [0, 0, 22.5]
},
"arm_right": {
"rotation": [22.5, -10, -35],
@@ -299,18 +299,29 @@
},
"arm_hammer_right2": {
"rotation": [0, -70, 0]
},
"finger_left": {
"rotation": [0, 0, -52.5],
"position": [0, 0.75, 0]
},
"finger_left2": {
"rotation": [0, 0, -15]
},
"finger_right": {
"rotation": [0, 0, 20]
},
"finger_right2": {
"rotation": [7.5, 0, 37.5],
"position": [-0.25, 0.25, 0]
},
"finger_right3": {
"rotation": [0, 0, -32.5]
}
}
},
"animation.tinkatuff.battle_idle": {
"loop": true,
"bones": {
"tail": {
"rotation": [12.5, 0, 0]
},
"tail2": {
"rotation": [12.5, 0, 0]
},
"arm_right": {
"rotation": [40.98303, 0.22836, "-45.7651+Math.cos((query.anim_time) * 90 * 2 - 40) * 2"]
},
@@ -318,7 +329,8 @@
"rotation": [0, -52.5, 0]
},
"finger_right": {
"rotation": [0, 0, -5]
"rotation": [0, 0, 37.5],
"position": [0, 0.25, 0]
},
"finger_right2": {
"rotation": [0, 0, 37.5]
@@ -330,17 +342,12 @@
"rotation": [0, 0, "55+Math.cos((query.anim_time) * 90 * 2 - 40) * -2"]
},
"finger_left": {
"rotation": [0, 0, -25]
"rotation": [0, 0, -47.5],
"position": [0, 0.5, 0]
},
"finger_left2": {
"rotation": [20, 0, 0]
},
"hand_left": {
"rotation": [0, 17.5, 0]
},
"hand_right": {
"rotation": [0, -17.5, 0]
},
"leg_left": {
"rotation": ["-11.2025+Math.cos((query.anim_time) * 90 * 2) * 3", -21.49336, -9.33448]
},
@@ -348,10 +355,11 @@
"rotation": ["-13.5954+Math.cos((query.anim_time) * 90 * 2) * 3", 22.38126, 10.45107]
},
"finger_left3": {
"rotation": [0, 0, 57.5]
"rotation": [0, 0, 42.5],
"position": [-0.5, -0.25, 0]
},
"finger_right3": {
"rotation": [0, 0, -20]
"rotation": [0, 0, -40]
},
"hammer": {
"rotation": [-12.18122, -2.58318, 113.79667]
@@ -416,7 +424,8 @@
"position": [-0.5, 0, 0]
},
"hammer": {
"rotation": [15, 0, 0]
"rotation": [15, 0, 0],
"position": [0, 0.5, 3.75]
},
"hammer2": {
"rotation": ["90+Math.cos((query.anim_time) * 90 * 1) * -1", 0, 0],
@@ -456,43 +465,18 @@
},
"leg_right": {
"rotation": [-90, 20, 0]
},
"eyes_ditto": {
"position": [0, 0, 0.1]
},
"eyes_blink_ditto": {
"position": [0, 0, -0.1]
}
}
},
"animation.tinkatuff.faint": {
"animation_length": 3,
"bones": {
"arm_right": {
"rotation": {
"0.0": [40.98303, 0.22836, -45.7651],
"0.2083": [5.98, 0.23, -45.77],
"0.2917": [35.98, 0.23, -45.77],
"0.75": [18.48, 5.23, -23.27],
"0.9167": [60.98, -12.27, -35.77],
"1.2083": [30.98, -59.77, -35.77],
"1.3333": [32.05, -62.98, -35.77],
"1.5": [33.48, -67.27, -35.77],
"1.8333": [15.98, -79.77, -35.77],
"1.9167": [67.65, -129.77, -110.77],
"1.9583": [93.48, -154.77, -148.27],
"2.0833": [93.48, -174.77, -168.27],
"2.3333": [93.48, -169.77, -168.27]
}
},
"arm_right2": {
"rotation": {
"0.0": [0, -52.5, 0],
"1.0": [0, -52.5, 0],
"1.2083": [0, -57.5, 0],
"1.5": [0, -30, 0]
}
},
"finger_right": {
"rotation": [0, 0, -5]
},
"finger_right2": {
"rotation": [0, 0, 37.5]
},
"arm_left": {
"rotation": {
"0.0": [-84.39003, 24.58778, 53.5046],
@@ -547,30 +531,9 @@
"2.375": [-30.37, 0, -5]
}
},
"leg_right": {
"rotation": {
"0.0": [-13.6, 22.38, 10.45],
"0.1667": [-31.1, 22.38, 10.45],
"0.25": [-26.1, 22.38, 10.45],
"0.5": [-3.6, 22.38, 10.45],
"0.7917": [6.4, 22.38, 10.45],
"0.9167": [-31.1, 22.38, 10.45],
"1.2083": [-31.1, 42.38, 10.45],
"1.375": [-30, 0, 0],
"1.6667": [-30, 0, 5],
"1.875": [70, 0, 5],
"2.0417": [40.36, 0, 5],
"2.1667": [-30, 0, 5],
"2.25": [-45, 0, 5],
"2.375": [-35, 0, 5]
}
},
"finger_left3": {
"rotation": [0, 0, 57.5]
},
"finger_right3": {
"rotation": [0, 0, -20]
},
"hammer": {
"rotation": {
"0.0": [-0.78, -6.26, 38.97],
@@ -593,9 +556,6 @@
"skirt_left": {
"rotation": [0, 0, -15]
},
"skirt_right": {
"rotation": [-10, 0, 15]
},
"leg_left2": {
"rotation": {
"0.0": [20, 0, 0],
@@ -611,18 +571,6 @@
"2.0417": [15, 0, 0]
}
},
"leg_right2": {
"rotation": {
"0.0": [15, 0, -10],
"0.1667": [35, 0, -10],
"0.25": [-10, 0, -10],
"0.5": [27.5, 0, 5],
"0.7917": [5, 0, 5],
"0.9167": [35, 0, 5],
"1.375": [35, 0, 0],
"1.6667": [22.5, 0, 0]
}
},
"body": {
"rotation": {
"0.9167": [0, 0, 0],
@@ -851,134 +799,519 @@
},
"eyelid_left": {
"position": {
"0.2083": [0, 0, 0],
"0.25": [0, 0, -0.15],
"0.375": [0, 0, -0.15],
"0.4167": [0, 0, 0],
"0.9167": [0, 0, 0],
"0.9583": [0, 0, -0.15],
"1.75": [0, 0, -0.15],
"1.7917": [0, 0, 0],
"2.0": [0, 0, 0],
"2.0417": [0, 0, -0.15]
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"0.4167": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
},
"0.9583": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"1.7917": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
},
"2.0417": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
}
}
},
"mouth_top": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0.5, 0]
},
"0.9167": {
"pre": [0, 0.5, 0],
"post": [0, 0, 0]
},
"1.2917": {
"pre": [0, 0, 0],
"post": [0, 0.5, 0]
},
"2.0417": {
"pre": [0, 0.5, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_right": {
"position": {
"0.2083": [0, 0, 0],
"0.25": [0, 0, -0.15],
"0.375": [0, 0, -0.15],
"0.4167": [0, 0, 0],
"0.9167": [0, 0, 0],
"0.9583": [0, 0, -0.15],
"1.75": [0, 0, -0.15],
"1.7917": [0, 0, 0],
"2.0": [0, 0, 0],
"2.0417": [0, 0, -0.15]
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"0.4167": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
},
"0.9583": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"1.7917": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
},
"2.0417": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
}
}
},
"mouth_open": {
"position": {
"0.2083": [0, 0, 0],
"0.25": [0, 0, -0.15],
"0.875": [0, 0, -0.15],
"0.9167": [0, 0, 0],
"1.25": [0, 0, 0],
"1.2917": [0, 0, -0.15],
"2.0": [0, 0, -0.15],
"2.0417": [0, 0, 0]
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"0.9167": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
},
"1.2917": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"2.0417": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
}
}
},
"mouth_closed": {
"position": {
"0.2083": [0, 0, 0],
"0.25": [0, 0, 0.1],
"0.875": [0, 0, 0.1],
"0.9167": [0, 0, 0],
"1.25": [0, 0, 0],
"1.2917": [0, 0, 0.1],
"2.0": [0, 0, 0.1],
"2.0417": [0, 0, 0]
}
}
}
},
"animation.tinkatuff.blink": {
"animation_length": 0.16667,
"bones": {
"eyelid_right": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
"arm_right": {
"rotation": {
"0.0": [40.98303, 0.22836, -45.7651],
"0.2083": [5.98, 0.23, -45.77],
"0.2917": [35.98, 0.23, -45.77],
"0.75": [18.48, 5.23, -23.27],
"0.9167": [60.98, -12.27, -35.77],
"1.2083": [30.98, -59.77, -35.77],
"1.3333": [32.05, -62.98, -35.77],
"1.5": [33.48, -67.27, -35.77],
"1.8333": [15.98, -79.77, -35.77],
"1.9167": [67.65, -129.77, -110.77],
"1.9583": [93.48, -154.77, -148.27],
"2.0833": [93.48, -174.77, -168.27],
"2.3333": [93.48, -169.77, -168.27]
}
},
"eyelid_left": {
"arm_right2": {
"rotation": {
"0.0": [0, -52.5, 0],
"1.0": [0, -52.5, 0],
"1.2083": [0, -57.5, 0],
"1.5": [0, -30, 0]
}
},
"finger_right": {
"rotation": [0, 0, -5]
},
"finger_right2": {
"rotation": [0, 0, 37.5]
},
"finger_right3": {
"rotation": [0, 0, -20]
},
"skirt_right": {
"rotation": [-10, 0, 15]
},
"leg_right": {
"rotation": {
"0.0": [-13.6, 22.38, 10.45],
"0.1667": [-31.1, 22.38, 10.45],
"0.25": [-26.1, 22.38, 10.45],
"0.5": [-3.6, 22.38, 10.45],
"0.7917": [6.4, 22.38, 10.45],
"0.9167": [-31.1, 22.38, 10.45],
"1.2083": [-31.1, 42.38, 10.45],
"1.375": [-30, 0, 0],
"1.6667": [-30, 0, 5],
"1.875": [70, 0, 5],
"2.0417": [40.36, 0, 5],
"2.1667": [-30, 0, 5],
"2.25": [-45, 0, 5],
"2.375": [-35, 0, 5]
}
},
"leg_right2": {
"rotation": {
"0.0": [15, 0, -10],
"0.1667": [35, 0, -10],
"0.25": [-10, 0, -10],
"0.5": [27.5, 0, 5],
"0.7917": [5, 0, 5],
"0.9167": [35, 0, 5],
"1.375": [35, 0, 0],
"1.6667": [22.5, 0, 0]
}
},
"brow_left": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"0.4167": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"0.9583": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"1.7917": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"2.0417": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
}
}
},
"brow_right": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"0.4167": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"0.9583": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"1.7917": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"2.0417": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
}
}
},
"mouth_bottom": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, -0.5, 0]
},
"0.9167": {
"pre": [0, -0.5, 0],
"post": [0, 0, 0]
},
"1.2917": {
"pre": [0, 0, 0],
"post": [0, -0.5, 0]
},
"2.0417": {
"pre": [0, -0.5, 0],
"post": [0, 0, 0]
}
}
},
"eye_emote_left": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"0.4167": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"0.9583": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"1.7917": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"2.0417": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
}
}
},
"eye_emote_right": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"0.4167": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"0.9583": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"1.7917": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"2.0417": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
}
}
},
"eyes_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"0.4167": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"0.9583": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"1.7917": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"2.0417": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
}
}
},
"eyes_blink_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"0.4167": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
},
"0.9583": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"1.7917": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
},
"2.0417": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
}
}
},
"mouth_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"0.9167": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
},
"1.2917": {
"pre": [0, 0, 0],
"post": [0, 0, 0.1]
},
"2.0417": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
}
}
},
"mouth_open_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"0.9167": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
},
"1.2917": {
"pre": [0, 0, 0],
"post": [0, 0, -0.1]
},
"2.0417": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
}
}
}
}
},
"animation.tinkatuff.cry": {
"animation_length": 0.91667,
"animation_length": 1.5,
"bones": {
"head": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [-15, 0, 0],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [-15, 0, 0],
"lerp_mode": "catmullrom"
},
"0.9167": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"mouth_closed": {
"position": {
"0.25": [0, 0, 0],
"0.3333": [0, 0, 0.1],
"0.5833": [0, 0, 0.1],
"0.6667": [0, 0, 0]
"0.0": [0, 0, 0],
"0.25": [-15, 0, 0],
"1.25": [-15, 0, 0],
"1.5": [0, 0, 0]
}
},
"mouth_open": {
"position": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [0, 0, -0.1],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [0, 0, -0.1],
"lerp_mode": "catmullrom"
},
"0.9167": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"1.3333": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"mouth_top": {
"position": {
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [0, 0.5, 0]},
"1.3333": {"pre": [0, 0.5, 0], "post": [0, 0, 0]}
}
},
"mouth_bottom": {
"position": {
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [0, -0.5, 0]},
"1.3333": {"pre": [0, -0.5, 0], "post": [0, 0, 0]}
}
},
"mouth_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"1.3333": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"mouth_open_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"1.3333": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
},
"sound_effects": {
"0.1667": {
"0.0": {
"effect": "pokemon.tinkatuff.cry"
}
}
},
"animation.tinkatuff.blink": {
"animation_length": 0.1667,
"bones": {
"eyelid_right": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
}
}
},
"brow_left": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
}
}
},
"brow_right": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
}
}
},
"eye_left": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
}
}
},
"eye_right": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
}
}
},
"eyes_ditto": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {
"pre": [0, 0, 0.1],
"post": [0, 0, 0]
}
}
},
"eyes_blink_ditto": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {
"pre": [0, 0, -0.1],
"post": [0, 0, 0]
}
}
}
}
},
"animation.tinkatuff.ditto_face": {
"loop": true,
"bones": {
"face": {
"position": [0, 0, 0.1],
"scale": 0
},
"face_ditto": {
"position": [0, 0, -0.1]
}
}
}
}
}
@@ -90,7 +90,7 @@
"parent": "chest",
"pivot": [0, 17, -5],
"cubes": [
{"origin": [-2.75, 16, -7.5], "size": [5.5, 5, 5], "uv": [22, 0]},
{"origin": [-2.25, 16, -7.5], "size": [5, 5, 5], "uv": [22, 0]},
{"origin": [0, 18, -2.5], "size": [0, 4, 2], "uv": [30, 37]}
]
},
@@ -486,7 +486,7 @@
"parent": "eye_left",
"pivot": [4.2, 34.1, -10.53],
"cubes": [
{"origin": [4.98, 33.99, -10.53], "size": [3, 1, 1], "inflate": 0.01, "uv": [132, 116]}
{"origin": [4.98, 34.01, -10.53], "size": [3, 1, 1], "inflate": 0.01, "uv": [132, 116]}
]
},
{
@@ -782,7 +782,7 @@
"parent": "eye_right",
"pivot": [-4.2, 34.1, -10.53],
"cubes": [
{"origin": [-7.98, 33.99, -10.53], "size": [3, 1, 1], "inflate": 0.01, "uv": [140, 116]}
{"origin": [-7.98, 34.01, -10.53], "size": [3, 1, 1], "inflate": 0.01, "uv": [140, 116]}
]
},
{
@@ -15,18 +15,58 @@
"name": "tinkatink",
"pivot": [0, 0, 0]
},
{
"name": "locator_root",
"parent": "tinkatink",
"pivot": [0, 0, 0],
"locators": {
"root": [0, 0, 0]
}
},
{
"name": "locator_top",
"parent": "tinkatink",
"pivot": [0, 14, 0],
"locators": {
"top": [0, 14, 0]
}
},
{
"name": "locator_special",
"parent": "tinkatink",
"pivot": [0, 6, -7],
"locators": {
"special": [0, 6, -7]
}
},
{
"name": "body",
"parent": "tinkatink",
"pivot": [0, 3.75, 0]
},
{
"name": "locator_target",
"parent": "body",
"pivot": [0, 6, -6],
"locators": {
"target": [0, 6, -6]
}
},
{
"name": "locator_middle",
"parent": "body",
"pivot": [0, 6, 0],
"locators": {
"middle": [0, 6, 0]
}
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 1.75, -0.25],
"pivot": [0, 2.5, -0.25],
"cubes": [
{"origin": [-2, 1.5, -2], "size": [4, 3, 4], "uv": [0, 12]},
{"origin": [-1, 2, -2.75], "size": [2, 2, 1], "pivot": [0, 3, -2.25], "rotation": [0, 0, 45], "uv": [12, 12]}
{"origin": [-1.5, 2, -1.5], "size": [3, 3, 3], "uv": [30, 6]},
{"origin": [-1, 1.5, -2.5], "size": [2, 2, 1], "pivot": [0, 2.5, -2], "rotation": [0, 0, 45], "uv": [47, 12]}
]
},
{
@@ -34,199 +74,509 @@
"parent": "torso",
"pivot": [0, 4.25, -0.25],
"cubes": [
{"origin": [-3.5, 4.25, -3.25], "size": [7, 6, 6], "uv": [0, 0]}
{"origin": [-4, 4.25, -3.75], "size": [8, 7, 7], "uv": [0, 0]}
]
},
{
"name": "hair3",
"name": "locator_item_hat",
"parent": "head",
"pivot": [0, 10.25, -0.25],
"rotation": [-5, 0, 0],
"cubes": [
{"origin": [-2.5, 10.25, -3.25], "size": [5, 0, 3], "uv": [11, 21]}
]
"pivot": [0, 12.25, -0.25],
"locators": {
"item_hat": [0, 12.25, -0.25]
}
},
{
"name": "hair4",
"parent": "hair3",
"pivot": [0, 10.25, -3.25],
"rotation": [-15, 0, 0],
"cubes": [
{"origin": [-2.5, 8.25, -3.25], "size": [5, 2, 0], "uv": [43, 0]}
]
},
{
"name": "eye_right",
"name": "locator_head",
"parent": "head",
"pivot": [-2.75, 6.5, -2.76],
"rotation": [0, 0, -5],
"pivot": [0, 11.25, -3.25],
"locators": {
"head": [0, 11.25, -3.25]
}
},
{
"name": "locator_mouth",
"parent": "head",
"pivot": [0, 5.7, -3.75],
"locators": {
"mouth": [0, 5.7, -3.75]
}
},
{
"name": "locator_item_face",
"parent": "head",
"pivot": [0, 8.25, -3.75],
"locators": {
"item_face": [0, 8.25, -3.75]
}
},
{
"name": "locator_face",
"parent": "head",
"pivot": [0, 7.25, -3.75],
"locators": {
"face": [0, 7.25, -3.75]
}
},
{
"name": "face_ditto",
"parent": "head",
"pivot": [0, 7, -3.65]
},
{
"name": "eyes_ditto",
"parent": "face_ditto",
"pivot": [0, 7.75, -3.67],
"cubes": [
{"origin": [-2.75, 6, -3.26], "size": [1, 2, 1], "uv": [51, 2]}
{"origin": [-3, 7.25, -3.67], "size": [6, 1, 0], "uv": [51, 23]}
]
},
{
"name": "eyelid_right",
"parent": "eye_right",
"pivot": [-0.5, 3.5, -0.15],
"name": "eyes_blink_ditto",
"parent": "face_ditto",
"pivot": [0, 7.75, -3.57],
"cubes": [
{"origin": [-2.75, 6, -3.16], "size": [1, 2, 1], "inflate": 0.01, "uv": [47, 2]}
{"origin": [-3.5, 7.25, -3.57], "size": [7, 1, 0], "uv": [49, 27]},
{"origin": [-3, 7.75, -3.58], "size": [6, 1, 0], "uv": [51, 21]}
]
},
{
"name": "mouth_ditto",
"parent": "face_ditto",
"pivot": [0, 6, -3.65],
"cubes": [
{"origin": [-2.5, 5.25, -3.66], "size": [5, 1, 0], "uv": [53, 19]},
{"origin": [-3.5, 5.75, -3.66], "size": [7, 1, 0], "uv": [49, 25]}
]
},
{
"name": "mouth_open_ditto",
"parent": "face_ditto",
"pivot": [0, 5.75, -3.56],
"cubes": [
{"origin": [-3.5, 4.75, -3.56], "size": [7, 2, 0], "uv": [49, 29]}
]
},
{
"name": "face",
"parent": "head",
"pivot": [0, 6.75, -3.75]
},
{
"name": "eyes",
"parent": "face",
"pivot": [0, 6.75, -3.26]
},
{
"name": "brow_left",
"parent": "eyes",
"pivot": [2.25, 8.5, -3.25],
"cubes": [
{"origin": [1.75, 8, -3.75], "size": [1, 1, 1], "inflate": 0.01, "pivot": [2.25, 8.5, -3.25], "rotation": [0, 0, 5], "uv": [32, 29]}
]
},
{
"name": "brow_right",
"parent": "eyes",
"pivot": [-2.25, 8.5, -3.25],
"cubes": [
{"origin": [-2.75, 8, -3.75], "size": [1, 1, 1], "inflate": 0.01, "pivot": [-2.25, 8.5, -3.25], "rotation": [0, 0, -5], "uv": [32, 25]}
]
},
{
"name": "eye_left",
"parent": "head",
"pivot": [2.75, 6.5, -2.76],
"rotation": [0, 0, 5],
"parent": "eyes",
"pivot": [2.5, 7.75, -3.26],
"cubes": [
{"origin": [1.75, 6, -3.26], "size": [1, 2, 1], "uv": [26, 7]}
{"origin": [2, 6.75, -3.75], "size": [1, 1, 1], "inflate": 0.01, "uv": [28, 29]}
]
},
{
"name": "locator_eye_left",
"parent": "eye_left",
"pivot": [2.5, 7.7, -3.75],
"locators": {
"eye2": [2.5, 7.7, -3.75]
}
},
{
"name": "eye_emote_left",
"parent": "eye_left",
"pivot": [2.5, 7.75, -3.75],
"cubes": [
{"origin": [2, 7.75, -3.75], "size": [1, 1, 1], "inflate": 0.025, "uv": [24, 29]}
]
},
{
"name": "eye_emote_left2",
"parent": "eye_left",
"pivot": [2.5, 7.75, -3.75],
"cubes": [
{"origin": [2, 7.75, -3.75], "size": [1, 1, 1], "inflate": 0.02, "uv": [20, 29]}
]
},
{
"name": "eye_right",
"parent": "eyes",
"pivot": [-2.5, 7.75, -3.26],
"cubes": [
{"origin": [-3, 6.75, -3.75], "size": [1, 1, 1], "inflate": 0.01, "uv": [28, 25]}
]
},
{
"name": "locator_eye_right",
"parent": "eye_right",
"pivot": [-2.5, 7.7, -3.75],
"locators": {
"eye1": [-2.5, 7.7, -3.75]
}
},
{
"name": "eye_emote_right",
"parent": "eye_right",
"pivot": [-2.5, 7.75, -3.75],
"cubes": [
{"origin": [-3, 7.75, -3.75], "size": [1, 1, 1], "inflate": 0.025, "uv": [24, 25]}
]
},
{
"name": "eye_emote_right2",
"parent": "eye_right",
"pivot": [-2.5, 7.75, -3.75],
"cubes": [
{"origin": [-3, 7.75, -3.75], "size": [1, 1, 1], "inflate": 0.02, "uv": [20, 25]}
]
},
{
"name": "eyelid_left",
"parent": "eye_left",
"pivot": [0.5, 3.5, -0.15],
"parent": "eyes",
"pivot": [2.5, 7.75, -3.16],
"cubes": [
{"origin": [1.75, 6, -3.16], "size": [1, 2, 1], "inflate": 0.01, "uv": [32, 8]}
{"origin": [1.5, 6.75, -3.65], "size": [2, 2, 1], "inflate": 0.03, "uv": [0, 28]}
]
},
{
"name": "hair",
"name": "eyelid_right",
"parent": "eyes",
"pivot": [-2.5, 7.75, -3.16],
"cubes": [
{"origin": [-3.5, 6.75, -3.65], "size": [2, 2, 1], "inflate": 0.03, "uv": [0, 24]}
]
},
{
"name": "eyelid_happy_left",
"parent": "eyes",
"pivot": [2.5, 7.75, -3.16],
"cubes": [
{"origin": [1, 6.75, -3.66], "size": [3, 2, 1], "uv": [12, 28]}
]
},
{
"name": "eyelid_happy_right",
"parent": "eyes",
"pivot": [-2.5, 7.75, -3.16],
"cubes": [
{"origin": [-4, 6.75, -3.66], "size": [3, 2, 1], "uv": [12, 24]}
]
},
{
"name": "eyelid_hurt_left",
"parent": "eyes",
"pivot": [2.5, 7.75, -3.16],
"cubes": [
{"origin": [1.5, 6.75, -3.65], "size": [2, 2, 1], "inflate": 0.03, "uv": [6, 28]}
]
},
{
"name": "eyelid_hurt_right",
"parent": "eyes",
"pivot": [-2.5, 7.75, -3.16],
"cubes": [
{"origin": [-3.5, 6.75, -3.65], "size": [2, 2, 1], "inflate": 0.03, "uv": [6, 24]}
]
},
{
"name": "mouths",
"parent": "face",
"pivot": [0, 4.25, -0.75]
},
{
"name": "mouth_closed",
"parent": "mouths",
"pivot": [0, 5.75, -3.25],
"cubes": [
{"origin": [-1.5, 4.75, -3.76], "size": [3, 1, 1], "inflate": 0.02, "uv": [38, 13]},
{"origin": [-0.5, 5.25, -3.76], "size": [1, 1, 1], "inflate": 0.04, "uv": [46, 16]}
]
},
{
"name": "mouth_lip_top",
"parent": "mouth_closed",
"pivot": [0, 6.25, -3.25],
"cubes": [
{"origin": [-1, 5.75, -3.77], "size": [2, 1, 1], "uv": [39, 16]},
{"origin": [-2, 5.25, -3.76], "size": [4, 1, 1], "uv": [29, 22]}
]
},
{
"name": "mouth_open_cry",
"parent": "mouths",
"pivot": [0.4, 4.25, -1.75],
"cubes": [
{"origin": [-2, 4.75, -3.65], "size": [4, 2, 1], "inflate": 0.01, "uv": [29, 19]}
]
},
{
"name": "mouth_open_happy",
"parent": "mouths",
"pivot": [0.4, 4.25, -1.75],
"cubes": [
{"origin": [-2, 4.75, -3.65], "size": [4, 2, 1], "inflate": 0.01, "uv": [40, 19]},
{"origin": [-1.5, 4.75, -3.65], "size": [3, 1, 1], "inflate": 0.02, "uv": [40, 22]},
{"origin": [-0.5, 5.4, -3.65], "size": [1, 1, 1], "inflate": 0.03, "uv": [42, 7]}
]
},
{
"name": "hair_main",
"parent": "head",
"pivot": [0, 10.25, 0.25],
"pivot": [0, 10.75, -0.75]
},
{
"name": "hair",
"parent": "hair_main",
"pivot": [0, 10.75, -0.75],
"rotation": [12.5, 0, 0],
"cubes": [
{"origin": [0, 9.75, -0.75], "size": [0, 2, 1], "uv": [4, 0]}
{"origin": [-0.5, 10.25, -1.75], "size": [1, 2, 1], "uv": [25, 15]}
]
},
{
"name": "hair2",
"parent": "hair",
"pivot": [0, 11.75, 0.25],
"rotation": [22.5, 0, 0],
"pivot": [1, 12.25, -0.75],
"rotation": [35, 0, 0],
"cubes": [
{"origin": [0, 11.75, -1.75], "size": [0, 3, 2], "inflate": 0.01, "uv": [0, 10]}
{"origin": [-1, 12.25, -2.25], "size": [2, 3, 2], "inflate": 0.01, "uv": [30, 13]}
]
},
{
"name": "mouth_closed",
"parent": "head",
"pivot": [0, 4.25, -0.25],
"name": "hair3",
"parent": "hair_main",
"pivot": [0, 11.25, -0.75],
"rotation": [-2.5, 0, 0],
"cubes": [
{"origin": [-2.5, 4.75, -3.2575], "size": [5, 2, 0], "inflate": 0.001, "uv": [26, 5]}
{"origin": [-2.5, 11.25, -3.75], "size": [5, 0, 3], "uv": [34, 25]}
]
},
{
"name": "mouth_open",
"parent": "head",
"pivot": [-0.1, 4.25, -1.25],
"name": "hair4",
"parent": "hair3",
"pivot": [0, 11.25, -3.75],
"rotation": [-7.5, 0, 0],
"cubes": [
{"origin": [-1.5, 4.75, -3.1575], "size": [3, 2, 0], "uv": [25, 12]}
{"origin": [-3, 9.25, -3.75], "size": [6, 2, 0], "uv": [36, 29]},
{"origin": [-0.5, 9.25, -3.75], "size": [1, 2, 0], "inflate": 0.01, "uv": [43, 10]}
]
},
{
"name": "arm_hammer_left",
"name": "arms",
"parent": "torso",
"pivot": [2, 3.25, 0]
},
{
"name": "hammer",
"parent": "arm_hammer_left",
"pivot": [6.75, 3, -0.5]
},
{
"name": "hammer2",
"parent": "hammer",
"pivot": [6.75, 7.41875, -0.525],
"cubes": [
{"origin": [5.25, 5.25, -2], "size": [3, 6, 3], "uv": [16, 12]},
{"origin": [6.25, 1.75, -1], "size": [1, 4, 1], "uv": [0, 0]},
{"origin": [5.75, 7, -5.65], "size": [2, 0, 2], "pivot": [6.5, 6.4375, -2.575], "rotation": [-90, 0, 0], "uv": [22, 22]},
{"origin": [6.25, 6.925, -5.8], "size": [1, 0, 1], "pivot": [6.5, 6.4375, -2.575], "rotation": [-90, 0, 0], "uv": [23, 21]}
]
"pivot": [0, 3.25, 0]
},
{
"name": "arm_left",
"parent": "torso",
"pivot": [2, 3.25, 0],
"parent": "arms",
"pivot": [1.5, 3.25, 0],
"cubes": [
{"origin": [2, 2.25, -1.5], "size": [4, 2, 3], "uv": [0, 19]}
{"origin": [1.25, 2.25, -1], "size": [2, 2, 2], "uv": [8, 19]}
]
},
{
"name": "finger_left",
"name": "hand_left",
"parent": "arm_left",
"pivot": [6, 3.5, 0],
"pivot": [3.25, 3.25, 0],
"cubes": [
{"origin": [6, 2.5, -0.5], "size": [1, 1, 1], "uv": [26, 10]}
{"origin": [3.25, 2.25, -1.5], "size": [3, 2, 3], "inflate": 0.25, "uv": [12, 14]}
]
},
{
"name": "locator_hand_secondary",
"parent": "hand_left",
"pivot": [6, 3.25, 0],
"rotation": [0, -90, 0],
"locators": {
"hand_secondary": [6, 3.25, 0]
}
},
{
"name": "fingers_left",
"parent": "hand_left",
"pivot": [6.5, 3.85, 0]
},
{
"name": "finger_left",
"parent": "fingers_left",
"pivot": [6.5, 3.85, 0],
"cubes": [
{"origin": [6.5, 2.85, -0.5], "size": [1, 1, 1], "inflate": 0.1, "uv": [20, 21]}
]
},
{
"name": "finger_left2",
"parent": "arm_left",
"pivot": [6, 3.5, -0.5],
"rotation": [0, 12.5, 0],
"parent": "fingers_left",
"pivot": [6.5, 3.85, -0.6],
"rotation": [0, 17.5, 0],
"cubes": [
{"origin": [6, 2.5, -1.5], "size": [1, 1, 1], "uv": [43, 2]}
{"origin": [6.5, 2.85, -1.7], "size": [1, 1, 1], "inflate": 0.1, "uv": [16, 21]}
]
},
{
"name": "finger_left3",
"parent": "arm_left",
"pivot": [6, 3.5, 0.5],
"rotation": [0, -12.5, 0],
"parent": "fingers_left",
"pivot": [6.5, 3.85, 0.6],
"rotation": [0, -17.5, 0],
"cubes": [
{"origin": [6, 2.5, 0.5], "size": [1, 1, 1], "uv": [11, 19]}
{"origin": [6.5, 2.85, 0.7], "size": [1, 1, 1], "inflate": 0.1, "uv": [24, 21]}
]
},
{
"name": "arm_right",
"parent": "torso",
"pivot": [-2, 3.25, 0],
"parent": "arms",
"pivot": [-1.5, 3.25, 0],
"cubes": [
{"origin": [-6, 2.25, -1.5], "size": [4, 2, 3], "uv": [20, 0]}
{"origin": [-3.25, 2.25, -1], "size": [2, 2, 2], "uv": [0, 19]}
]
},
{
"name": "finger_right",
"name": "hand_right",
"parent": "arm_right",
"pivot": [-6, 3.5, 0],
"pivot": [-3.25, 3.25, 0],
"cubes": [
{"origin": [-7, 2.5, -0.5], "size": [1, 1, 1], "uv": [28, 14]}
{"origin": [-6.25, 2.25, -1.5], "size": [3, 2, 3], "inflate": 0.25, "uv": [0, 14]}
]
},
{
"name": "locator_hand_primary",
"parent": "hand_right",
"pivot": [-6, 3.25, 0],
"rotation": [0, 90, 0],
"locators": {
"hand_primary": [-6, 3.25, 0]
}
},
{
"name": "locator_item",
"parent": "hand_right",
"pivot": [-6, 2.25, 0],
"locators": {
"item": [-6, 2.25, 0]
}
},
{
"name": "fingers_right",
"parent": "hand_right",
"pivot": [-6.5, 3.85, 0]
},
{
"name": "finger_right",
"parent": "fingers_right",
"pivot": [-6.5, 3.85, 0],
"cubes": [
{"origin": [-7.5, 2.85, -0.5], "size": [1, 1, 1], "inflate": 0.1, "uv": [20, 19]}
]
},
{
"name": "finger_right2",
"parent": "arm_right",
"pivot": [-6, 3.5, -0.5],
"rotation": [0, -12.5, 0],
"parent": "fingers_right",
"pivot": [-6.5, 3.85, -0.6],
"rotation": [0, -17.5, 0],
"cubes": [
{"origin": [-7, 2.5, -1.5], "size": [1, 1, 1], "uv": [56, 9]}
{"origin": [-7.5, 2.85, -1.7], "size": [1, 1, 1], "inflate": 0.1, "uv": [16, 19]}
]
},
{
"name": "finger_right3",
"parent": "arm_right",
"pivot": [-6, 3.5, 0.5],
"rotation": [0, 12.5, 0],
"parent": "fingers_right",
"pivot": [-6.5, 3.85, 0.6],
"rotation": [0, 17.5, 0],
"cubes": [
{"origin": [-7, 2.5, 0.5], "size": [1, 1, 1], "uv": [52, 9]}
{"origin": [-7.5, 2.85, 0.7], "size": [1, 1, 1], "inflate": 0.1, "uv": [24, 19]}
]
},
{
"name": "arm_hammer_left",
"parent": "arms",
"pivot": [1.5, 3.25, 0]
},
{
"name": "hammer",
"parent": "arm_hammer_left",
"pivot": [7.25, 3, -0.5]
},
{
"name": "hammer2",
"parent": "hammer",
"pivot": [7.5, 7.41875, -0.525],
"cubes": [
{"origin": [7, 1.25, -1], "size": [1, 4, 1], "uv": [54, 12]},
{"origin": [7, 1.25, -1], "size": [1, 4, 1], "inflate": 0.1, "uv": [59, 12]}
]
},
{
"name": "rattle",
"parent": "hammer2",
"pivot": [7.5, 9.75, -2],
"cubes": [
{"origin": [7, 9.25, -2.5], "size": [1, 1, 1], "inflate": 0.01, "pivot": [7.5, 9.75, -2], "rotation": [0, 0, 45], "uv": [60, 1]},
{"origin": [6.5, 7.25, -2.4], "size": [2, 2, 1], "inflate": 0.11, "pivot": [7.5, 8.25, -1.9], "rotation": [0, 0, 45], "uv": [46, 0]},
{"origin": [5.5, 4.75, -2.5], "size": [4, 7, 4], "uv": [48, 0]}
]
},
{
"name": "locator_physical",
"parent": "rattle",
"pivot": [7.5, 11.75, -0.5],
"locators": {
"physical": [7.5, 11.75, -0.5]
}
},
{
"name": "legs",
"parent": "body",
"pivot": [0, 1.5, 0]
},
{
"name": "leg_left",
"parent": "body",
"pivot": [0.75, 1.5, 0],
"parent": "legs",
"pivot": [1.25, 1.5, 0],
"cubes": [
{"origin": [0.25, 0, -2], "size": [2, 2, 4], "inflate": 0.01, "uv": [35, 0]}
{"origin": [-0.25, -0.25, -1.5], "size": [3, 3, 3], "inflate": -0.25, "uv": [35, 0]}
]
},
{
"name": "locator_foot_secondary",
"parent": "leg_left",
"pivot": [1.4, 0.5, 0.1],
"rotation": [90, 0, 0],
"locators": {
"foot_secondary": [1.4, 0.5, 0.1]
}
},
{
"name": "leg_right",
"parent": "body",
"pivot": [-0.75, 1.5, 0],
"parent": "legs",
"pivot": [-1.25, 1.5, 0],
"cubes": [
{"origin": [-2.25, 0, -2], "size": [2, 2, 4], "inflate": 0.01, "uv": [52, 3]}
{"origin": [-2.75, -0.25, -1.5], "size": [3, 3, 3], "inflate": -0.25, "uv": [23, 0]}
]
},
{
"name": "locator_foot_primary",
"parent": "leg_right",
"pivot": [-1.4, 0.5, 0.1],
"rotation": [90, 0, 0],
"locators": {
"foot_primary": [-1.4, 0.5, 0.1]
}
}
]
}
@@ -1,233 +0,0 @@
{
"format_version": "1.12.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.tinkatink_dot",
"texture_width": 64,
"texture_height": 32,
"visible_bounds_width": 2,
"visible_bounds_height": 2.5,
"visible_bounds_offset": [0, 0.75, 0]
},
"bones": [
{
"name": "tinkatink",
"pivot": [0, 0, 0]
},
{
"name": "body",
"parent": "tinkatink",
"pivot": [0, 3.75, 0]
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 1.75, -0.25],
"cubes": [
{"origin": [-2, 1.5, -2], "size": [4, 3, 4], "uv": [0, 12]},
{"origin": [-1, 2, -2.75], "size": [2, 2, 1], "pivot": [0, 3, -2.25], "rotation": [0, 0, 45], "uv": [12, 12]}
]
},
{
"name": "head",
"parent": "torso",
"pivot": [0, 4.25, -0.25],
"cubes": [
{"origin": [-3.5, 4.25, -3.25], "size": [7, 6, 6], "uv": [0, 0]}
]
},
{
"name": "hair3",
"parent": "head",
"pivot": [0, 10.25, -0.25],
"rotation": [-5, 0, 0],
"cubes": [
{"origin": [-2.5, 10.25, -3.25], "size": [5, 0, 3], "uv": [11, 21]}
]
},
{
"name": "hair4",
"parent": "hair3",
"pivot": [0, 10.25, -3.25],
"rotation": [-15, 0, 0],
"cubes": [
{"origin": [-2.5, 8.25, -3.25], "size": [5, 2, 0], "uv": [43, 0]}
]
},
{
"name": "eye_right",
"parent": "head",
"pivot": [-2.75, 6.5, -2.76],
"rotation": [0, 0, -5],
"cubes": [
{"origin": [-2.75, 6, -3.26], "size": [1, 2, 1], "uv": [51, 2]}
]
},
{
"name": "eyelid_right",
"parent": "eye_right",
"pivot": [-0.5, 3.5, -0.15],
"cubes": [
{"origin": [-2.75, 6, -3.16], "size": [1, 2, 1], "inflate": 0.01, "uv": [47, 2]}
]
},
{
"name": "eye_left",
"parent": "head",
"pivot": [2.75, 6.5, -2.76],
"rotation": [0, 0, 5],
"cubes": [
{"origin": [1.75, 6, -3.26], "size": [1, 2, 1], "uv": [26, 7]}
]
},
{
"name": "eyelid_left",
"parent": "eye_left",
"pivot": [0.5, 3.5, -0.15],
"cubes": [
{"origin": [1.75, 6, -3.16], "size": [1, 2, 1], "inflate": 0.01, "uv": [32, 8]}
]
},
{
"name": "hair",
"parent": "head",
"pivot": [0, 10.25, 0.25],
"rotation": [12.5, 0, 0],
"cubes": [
{"origin": [0, 9.75, -0.75], "size": [0, 2, 1], "uv": [4, 0]}
]
},
{
"name": "hair2",
"parent": "hair",
"pivot": [0, 11.75, 0.25],
"rotation": [22.5, 0, 0],
"cubes": [
{"origin": [0, 11.75, -1.75], "size": [0, 3, 2], "inflate": 0.01, "uv": [0, 10]}
]
},
{
"name": "mouth_closed",
"parent": "head",
"pivot": [0, 4.25, -0.25],
"cubes": [
{"origin": [-2.5, 4.75, -3.2575], "size": [5, 2, 0], "inflate": 0.001, "uv": [26, 5]}
]
},
{
"name": "mouth_open",
"parent": "head",
"pivot": [-0.1, 4.25, -1.25],
"cubes": [
{"origin": [-1.5, 4.75, -3.1575], "size": [3, 2, 0], "uv": [25, 12]}
]
},
{
"name": "arm_hammer_left",
"parent": "torso",
"pivot": [2, 3.25, 0]
},
{
"name": "hammer",
"parent": "arm_hammer_left",
"pivot": [6.75, 3, -0.5]
},
{
"name": "hammer2",
"parent": "hammer",
"pivot": [6.75, 7.41875, -0.525],
"cubes": [
{"origin": [5.25, 5.25, -2], "size": [3, 6, 3], "uv": [16, 12]},
{"origin": [6.25, 1.75, -1], "size": [1, 4, 1], "uv": [0, 0]},
{"origin": [5.75, 8.2625, -3.0125], "size": [2, 0, 2], "pivot": [6.75, 8.2625, -2.0125], "rotation": [-90, 0, 45], "uv": [-2, 24]}
]
},
{
"name": "arm_left",
"parent": "torso",
"pivot": [2, 3.25, 0],
"cubes": [
{"origin": [2, 2.25, -1.5], "size": [4, 2, 3], "uv": [0, 19]}
]
},
{
"name": "finger_left",
"parent": "arm_left",
"pivot": [6, 3.5, 0],
"cubes": [
{"origin": [6, 2.5, -0.5], "size": [1, 1, 1], "uv": [26, 10]}
]
},
{
"name": "finger_left2",
"parent": "arm_left",
"pivot": [6, 3.5, -0.5],
"rotation": [0, 12.5, 0],
"cubes": [
{"origin": [6, 2.5, -1.5], "size": [1, 1, 1], "uv": [43, 2]}
]
},
{
"name": "finger_left3",
"parent": "arm_left",
"pivot": [6, 3.5, 0.5],
"rotation": [0, -12.5, 0],
"cubes": [
{"origin": [6, 2.5, 0.5], "size": [1, 1, 1], "uv": [11, 19]}
]
},
{
"name": "arm_right",
"parent": "torso",
"pivot": [-2, 3.25, 0],
"cubes": [
{"origin": [-6, 2.25, -1.5], "size": [4, 2, 3], "uv": [20, 0]}
]
},
{
"name": "finger_right",
"parent": "arm_right",
"pivot": [-6, 3.5, 0],
"cubes": [
{"origin": [-7, 2.5, -0.5], "size": [1, 1, 1], "uv": [28, 14]}
]
},
{
"name": "finger_right2",
"parent": "arm_right",
"pivot": [-6, 3.5, -0.5],
"rotation": [0, -12.5, 0],
"cubes": [
{"origin": [-7, 2.5, -1.5], "size": [1, 1, 1], "uv": [56, 9]}
]
},
{
"name": "finger_right3",
"parent": "arm_right",
"pivot": [-6, 3.5, 0.5],
"rotation": [0, 12.5, 0],
"cubes": [
{"origin": [-7, 2.5, 0.5], "size": [1, 1, 1], "uv": [52, 9]}
]
},
{
"name": "leg_left",
"parent": "body",
"pivot": [0.75, 1.5, 0],
"cubes": [
{"origin": [0.25, 0, -2], "size": [2, 2, 4], "inflate": 0.01, "uv": [35, 0]}
]
},
{
"name": "leg_right",
"parent": "body",
"pivot": [-0.75, 1.5, 0],
"cubes": [
{"origin": [-2.25, 0, -2], "size": [2, 2, 4], "inflate": 0.01, "uv": [52, 3]}
]
}
]
}
]
}
@@ -4,7 +4,7 @@
{
"description": {
"identifier": "geometry.tinkatuff",
"texture_width": 64,
"texture_width": 128,
"texture_height": 64,
"visible_bounds_width": 3,
"visible_bounds_height": 2.5,
@@ -15,289 +15,680 @@
"name": "tinkatuff",
"pivot": [0, 0, 0]
},
{
"name": "locator_root",
"parent": "tinkatuff",
"pivot": [0, 0, 0],
"locators": {
"root": [0, 0, 0]
}
},
{
"name": "locator_top",
"parent": "tinkatuff",
"pivot": [0, 22, 0],
"locators": {
"top": [0, 22, 0]
}
},
{
"name": "locator_special",
"parent": "tinkatuff",
"pivot": [0, 8, -8],
"locators": {
"special": [0, 8, -8]
}
},
{
"name": "body",
"parent": "tinkatuff",
"pivot": [0, 6, 0]
"pivot": [0, 6.25, 0]
},
{
"name": "locator_target",
"parent": "body",
"pivot": [0, 8, -6],
"locators": {
"target": [0, 8, -6]
}
},
{
"name": "locator_middle",
"parent": "body",
"pivot": [0, 9, 0],
"locators": {
"middle": [0, 9, 0]
}
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 4.25, 0],
"pivot": [0, 4.5, 0],
"cubes": [
{"origin": [-2, 7.5, -1.5], "size": [4, 3, 3], "uv": [41, 41]},
{"origin": [-2.5, 3, -2], "size": [5, 5, 4], "uv": [36, 0]}
{"origin": [-2.5, 3.25, -2], "size": [5, 3, 4], "inflate": 0.25, "uv": [0, 14]},
{"origin": [-2.5, 3.25, -2], "size": [5, 3, 4], "inflate": 0.5, "uv": [18, 14]}
]
},
{
"name": "skirt_left",
"name": "chest",
"parent": "torso",
"pivot": [2.5, 3, 0],
"rotation": [0, 0, 45],
"pivot": [0, 6, 0],
"cubes": [
{"origin": [2.5, 3, -1.5], "size": [3, 0, 3], "uv": [6, 15]}
]
},
{
"name": "skirt_right",
"parent": "torso",
"pivot": [-2.5, 3, 0],
"rotation": [0, 0, -45],
"cubes": [
{"origin": [-5.5, 3, -1.5], "size": [3, 0, 3], "uv": [0, 15]}
]
},
{
"name": "arm_left",
"parent": "torso",
"pivot": [2, 8, 0],
"cubes": [
{"origin": [1, 7, -1], "size": [4, 2, 2], "uv": [35, 47]}
]
},
{
"name": "arm_left2",
"parent": "arm_left",
"pivot": [5, 9, 1],
"cubes": [
{"origin": [5, 7, -1.5], "size": [4, 2, 3], "inflate": 0.001, "uv": [44, 35]}
]
},
{
"name": "finger_left",
"parent": "arm_left2",
"pivot": [9, 7.75, -0.5],
"rotation": [0, 12.5, 0],
"cubes": [
{"origin": [9, 7.75, -1.5], "size": [1, 1, 1], "uv": [33, 44]}
]
},
{
"name": "finger_left2",
"parent": "arm_left2",
"pivot": [9, 7.75, 0.5],
"rotation": [0, -12.5, 0],
"cubes": [
{"origin": [9, 7.75, 0.5], "size": [1, 1, 1], "uv": [40, 30]}
]
},
{
"name": "finger_left3",
"parent": "arm_left2",
"pivot": [9, 8, 0],
"cubes": [
{"origin": [9, 7, -0.5], "size": [1, 1, 1], "uv": [36, 30]}
]
},
{
"name": "arm_hammer_right",
"parent": "torso",
"pivot": [-2, 8, 0]
},
{
"name": "arm_hammer_right2",
"parent": "arm_hammer_right",
"pivot": [-5, 9, 1]
},
{
"name": "hammer",
"parent": "arm_hammer_right2",
"pivot": [-9.75, 8, 0]
},
{
"name": "hammer2",
"parent": "hammer",
"pivot": [-9.55, 7.9675, -9.0675],
"cubes": [
{"origin": [-11, 6.5, -20], "size": [3, 3, 6], "uv": [30, 9]},
{"origin": [-10.5, 6.475, -18.25], "size": [2, 0, 2], "uv": [-1, 54]},
{"origin": [-10, 6.4, -18.4], "size": [1, 0, 1], "uv": [-1, 54]},
{"origin": [-11, 6.5, -12.5], "size": [3, 3, 3], "uv": [0, 47]},
{"origin": [-10, 7.5, -14.5], "size": [1, 1, 18], "inflate": 0.001, "uv": [0, 0]},
{"origin": [-15.5, 4.025, -18.525], "size": [12, 11, 0], "pivot": [-9.5, 9.525, -18.525], "rotation": [-90, -180, 0], "uv": [0, 36]},
{"origin": [-15.5, 3.5, -30.5], "size": [0, 8, 5], "pivot": [-9.5, 12.25, -22.775], "rotation": [90, 0, 0], "uv": [34, 31]},
{"origin": [-15.5, 3.5, -30.5], "size": [3, 8, 0], "pivot": [-9.5, 12.25, -22.775], "rotation": [90, 0, 0], "uv": [47, 47]},
{"origin": [-7.5, 2.5, -30.5], "size": [4, 9, 0], "pivot": [-9.5, 12.25, -22.775], "rotation": [90, 0, 0], "uv": [12, 47]},
{"origin": [-3.5, 2.525, -20.025], "size": [0, 9, 5], "pivot": [-3.5, 7.025, -17.525], "rotation": [90, 180, 0], "uv": [24, 31]},
{"origin": [-13.5, 12.5, -29.5], "size": [8, 1, 0], "pivot": [-9.5, 12.25, -22.775], "rotation": [90, 0, 0], "uv": [0, 7]},
{"origin": [-13.5, 7.525, -26.025], "size": [8, 0, 4], "pivot": [-9.5, 7.525, -24.025], "rotation": [90, 180, 0], "uv": [17, 19]}
]
},
{
"name": "arm_right",
"parent": "torso",
"pivot": [-2, 8, 0],
"cubes": [
{"origin": [-5, 7, -1], "size": [4, 2, 2], "uv": [0, 32]}
]
},
{
"name": "arm_right2",
"parent": "arm_right",
"pivot": [-5, 9, 1],
"cubes": [
{"origin": [-9, 7, -1.5], "size": [4, 2, 3], "inflate": 0.001, "uv": [44, 30]}
]
},
{
"name": "finger_right",
"parent": "arm_right2",
"pivot": [-9, 7.75, -0.5],
"rotation": [0, -12.5, 0],
"cubes": [
{"origin": [-10, 7.75, -1.5], "size": [1, 1, 1], "uv": [36, 2]}
]
},
{
"name": "finger_right2",
"parent": "arm_right2",
"pivot": [-9, 7.75, 0.5],
"rotation": [0, 12.5, 0],
"cubes": [
{"origin": [-10, 7.75, 0.5], "size": [1, 1, 1], "uv": [36, 0]}
]
},
{
"name": "finger_right3",
"parent": "arm_right2",
"pivot": [-9, 8, 0],
"cubes": [
{"origin": [-10, 7, -0.5], "size": [1, 1, 1], "uv": [10, 32]}
{"origin": [-2, 5.75, -2], "size": [4, 4, 4], "uv": [24, 0]}
]
},
{
"name": "head",
"parent": "torso",
"pivot": [0, 9, 0.5],
"parent": "chest",
"pivot": [0, 8.75, 0.5],
"cubes": [
{"origin": [-3.5, 9, -3.5], "size": [7, 6, 7], "uv": [0, 19]},
{"origin": [-4, 17.30092, -3.63266], "size": [8, 0, 8], "pivot": [0, 13.80092, 0.36734], "rotation": [-7.5, 0, 0], "uv": [12, 0]},
{"origin": [4, 10.30092, -3.63266], "size": [0, 7, 8], "pivot": [0, 13.80092, 0.36734], "rotation": [-7.5, 0, 0], "uv": [20, 0]},
{"origin": [-4, 10.30092, 4.36734], "size": [8, 7, 0], "pivot": [0, 13.80092, 0.36734], "rotation": [-7.5, 0, 0], "uv": [0, 0]},
{"origin": [-4, 11.30092, -3.63266], "size": [8, 6, 0], "pivot": [0, 13.80092, 0.36734], "rotation": [-7.5, 0, 0], "uv": [42, 9]},
{"origin": [-4, 10.30092, -3.63266], "size": [0, 7, 8], "pivot": [0, 13.80092, 0.36734], "rotation": [-7.5, 0, 0], "uv": [0, 0]}
{"origin": [-4, 8.75, -4], "size": [8, 6, 8], "uv": [0, 0]}
]
},
{
"name": "locator_mouth",
"parent": "head",
"pivot": [0, 9.75, -4],
"locators": {
"mouth": [0, 9.75, -4]
}
},
{
"name": "locator_item_face",
"parent": "head",
"pivot": [0, 12.25, -4],
"locators": {
"item_face": [0, 12.25, -4]
}
},
{
"name": "locator_face",
"parent": "head",
"pivot": [0, 11.75, -4],
"locators": {
"face": [0, 11.75, -4]
}
},
{
"name": "face_ditto",
"parent": "head",
"pivot": [0, 11, -3.9]
},
{
"name": "eyes_ditto",
"parent": "face_ditto",
"pivot": [0, 11.75, -3.92],
"cubes": [
{"origin": [-3, 11.25, -3.92], "size": [6, 1, 0], "uv": [22, 49]}
]
},
{
"name": "eyes_blink_ditto",
"parent": "face_ditto",
"pivot": [0, 11.75, -3.82],
"cubes": [
{"origin": [-3.5, 11.25, -3.82], "size": [7, 1, 0], "uv": [21, 51]},
{"origin": [-3, 11.75, -3.83], "size": [6, 1, 0], "uv": [22, 53]}
]
},
{
"name": "mouth_ditto",
"parent": "face_ditto",
"pivot": [0, 10, -3.9],
"cubes": [
{"origin": [-2.5, 9.25, -3.91], "size": [5, 1, 0], "uv": [23, 57]},
{"origin": [-3.5, 9.75, -3.91], "size": [7, 1, 0], "uv": [21, 55]}
]
},
{
"name": "mouth_open_ditto",
"parent": "face_ditto",
"pivot": [0, 9.75, -3.81],
"cubes": [
{"origin": [-3.5, 8.75, -3.81], "size": [7, 2, 0], "uv": [21, 59]}
]
},
{
"name": "face",
"parent": "head",
"pivot": [0, 11.75, -4.01]
},
{
"name": "eyes",
"parent": "face",
"pivot": [0, 12, -3.51]
},
{
"name": "brow_left",
"parent": "eyes",
"pivot": [2.25, 12.75, -3.5],
"cubes": [
{"origin": [1.75, 12.25, -4], "size": [1, 1, 1], "inflate": 0.01, "uv": [16, 52]}
]
},
{
"name": "brow_right",
"parent": "eyes",
"pivot": [-2.25, 12.75, -3.5],
"cubes": [
{"origin": [-2.75, 12.25, -4], "size": [1, 1, 1], "inflate": 0.01, "uv": [11, 52], "mirror": true}
]
},
{
"name": "eye_left",
"parent": "head",
"pivot": [2.25, 12.25, -3.01],
"rotation": [0, 0, -7.5],
"parent": "eyes",
"pivot": [2.5, 12, -3.51],
"cubes": [
{"origin": [1.75, 11.25, -3.51], "size": [1, 2, 1], "uv": [21, 23]}
{"origin": [2, 11, -4], "size": [1, 1, 1], "inflate": 0.01, "uv": [6, 52]}
]
},
{
"name": "eyelid_left",
"name": "locator_eye_left",
"parent": "eye_left",
"pivot": [2.25, 12.25, -2.91],
"pivot": [2.5, 12, -4],
"locators": {
"eye2": [2.5, 12, -4]
}
},
{
"name": "eye_emote_left",
"parent": "eye_left",
"pivot": [2.5, 12, -4],
"cubes": [
{"origin": [1.75, 11.25, -3.41], "size": [1, 2, 1], "inflate": 0.01, "uv": [26, 15]}
{"origin": [2, 12, -4], "size": [1, 1, 1], "inflate": 0.025, "uv": [6, 49]}
]
},
{
"name": "eye_emote_left2",
"parent": "eye_left",
"pivot": [2.5, 12, -4],
"cubes": [
{"origin": [2, 12, -4], "size": [1, 1, 1], "inflate": 0.02, "uv": [16, 49]}
]
},
{
"name": "eye_right",
"parent": "head",
"pivot": [-2.25, 12.25, -3.01],
"rotation": [0, 0, 7.5],
"parent": "eyes",
"pivot": [-2.5, 12, -3.51],
"cubes": [
{"origin": [-2.75, 11.25, -3.51], "size": [1, 2, 1], "uv": [0, 21]}
{"origin": [-3, 11, -4], "size": [1, 1, 1], "inflate": 0.01, "uv": [1, 52], "mirror": true}
]
},
{
"name": "locator_eye_right",
"parent": "eye_right",
"pivot": [-2.5, 12, -4],
"locators": {
"eye1": [-2.5, 12, -4]
}
},
{
"name": "eye_emote_right",
"parent": "eye_right",
"pivot": [-2.5, 12, -4],
"cubes": [
{"origin": [-3, 12, -4], "size": [1, 1, 1], "inflate": 0.025, "uv": [1, 49], "mirror": true}
]
},
{
"name": "eye_emote_right2",
"parent": "eye_right",
"pivot": [-2.5, 12, -4],
"cubes": [
{"origin": [-3, 12, -4], "size": [1, 1, 1], "inflate": 0.02, "uv": [11, 49], "mirror": true}
]
},
{
"name": "eyelid_left",
"parent": "eyes",
"pivot": [2.5, 12, -3.41],
"cubes": [
{"origin": [1.5, 11, -3.9], "size": [2, 2, 1], "inflate": 0.03, "uv": [8, 45]}
]
},
{
"name": "eyelid_right",
"parent": "eye_right",
"pivot": [-2.25, 12.25, -2.91],
"parent": "eyes",
"pivot": [-2.5, 12, -3.41],
"cubes": [
{"origin": [-2.75, 11.25, -3.41], "size": [1, 2, 1], "inflate": 0.01, "uv": [3, 23]}
{"origin": [-3.5, 11, -3.9], "size": [2, 2, 1], "inflate": 0.03, "uv": [1, 45], "mirror": true}
]
},
{
"name": "eyelid_hurt_left",
"parent": "eyes",
"pivot": [2.5, 12, -3.41],
"cubes": [
{"origin": [1.5, 11, -3.9], "size": [2, 2, 1], "inflate": 0.03, "uv": [22, 45]}
]
},
{
"name": "eyelid_hurt_right",
"parent": "eyes",
"pivot": [-2.5, 12, -3.41],
"cubes": [
{"origin": [-3.5, 11, -3.9], "size": [2, 2, 1], "inflate": 0.03, "uv": [15, 45], "mirror": true}
]
},
{
"name": "eyelid_happy_left",
"parent": "eyes",
"pivot": [2.5, 12, -3.41],
"cubes": [
{"origin": [1, 11, -3.91], "size": [3, 2, 1], "uv": [38, 45]}
]
},
{
"name": "eyelid_happy_right",
"parent": "eyes",
"pivot": [-2.5, 12, -3.41],
"cubes": [
{"origin": [-4, 11, -3.91], "size": [3, 2, 1], "uv": [29, 45], "mirror": true}
]
},
{
"name": "mouths",
"parent": "face",
"pivot": [0, 10.25, -3.91],
"cubes": [
{"origin": [-1.5, 9.75, -4], "size": [3, 1, 1], "inflate": 0.01, "uv": [1, 55]}
]
},
{
"name": "mouth_top",
"parent": "mouths",
"pivot": [0, 11.25, -4.01],
"cubes": [
{"origin": [-0.5, 10.27, -4], "size": [1, 1, 1], "inflate": 0.03, "uv": [10, 55]}
]
},
{
"name": "mouth_bottom",
"parent": "mouths",
"pivot": [0, 10.25, -4.01],
"cubes": [
{"origin": [-0.5, 9.23, -4], "size": [1, 1, 1], "inflate": 0.03, "uv": [10, 59]}
]
},
{
"name": "mouth_open",
"parent": "head",
"pivot": [0, 10.5, -3.41],
"parent": "mouths",
"pivot": [0, 10.25, -3.91],
"cubes": [
{"origin": [-1.5, 9.5, -3.41], "size": [3, 2, 0], "uv": [20, 15]}
{"origin": [-1.5, 9.25, -3.9], "size": [3, 2, 1], "inflate": 0.02, "uv": [1, 58]}
]
},
{
"name": "mouth_closed",
"name": "hair",
"parent": "head",
"pivot": [0, 10.5, -3.51],
"pivot": [0, 17.25, 0.7],
"rotation": [-10, 0, 0],
"cubes": [
{"origin": [-1.5, 9.5, -3.51], "size": [3, 2, 0], "uv": [0, 19]}
{"origin": [4.5, 10.25, -3.8], "size": [0, 3, 9], "pivot": [4.5, 13.25, 0.7], "rotation": [0, 0, 9], "uv": [49, 47]},
{"origin": [-4.5, 10.25, -3.8], "size": [0, 3, 9], "pivot": [-4.5, 13.25, 0.7], "rotation": [0, 0, -9], "uv": [49, 51], "mirror": true},
{"origin": [-4.5, 13.25, -3.8], "size": [9, 4, 9], "uv": [33, 0]},
{"origin": [-2.5, 10.25, -3.8], "size": [5, 3, 0], "pivot": [0, 13.25, -3.8], "rotation": [13.5, 0, 0], "uv": [53, 48]},
{"origin": [0.5, 10.25, 5.2], "size": [4, 3, 0], "pivot": [4.5, 13.25, 5.2], "rotation": [0, 0, 9], "uv": [49, 52]},
{"origin": [-4.5, 10.25, 5.2], "size": [4, 3, 0], "pivot": [-4.5, 13.25, 5.2], "rotation": [0, 0, -9], "uv": [59, 52], "mirror": true}
]
},
{
"name": "locator_head",
"parent": "hair",
"pivot": [0, 16.25, -3.8],
"locators": {
"head": [0, 16.25, -3.8]
}
},
{
"name": "locator_item_hat",
"parent": "hair",
"pivot": [0, 17.25, 0.7],
"locators": {
"item_hat": [0, 17.25, 0.7]
}
},
{
"name": "hair2",
"parent": "hair",
"pivot": [4.5, 14.25, -0.8],
"rotation": [22.5, -90, 0]
},
{
"name": "hair3",
"parent": "hair2",
"pivot": [4.5, 14.25, -0.8],
"cubes": [
{"origin": [2.5, 14.25, -0.8], "size": [4, 7, 0], "uv": [40, 56]}
]
},
{
"name": "ponytail",
"parent": "head",
"pivot": [0, 16.81524, 1.82582],
"rotation": [2.5, 0, 0],
"parent": "hair",
"pivot": [0, 16.25, 1.2],
"rotation": [-20, 0, 0],
"cubes": [
{"origin": [-2, 16.62133, -0.28751], "size": [4, 4, 8], "uv": [20, 24]}
{"origin": [-4, 15.25, 0.2], "size": [8, 7, 7], "uv": [37, 13]}
]
},
{
"name": "ponytail2",
"parent": "ponytail",
"pivot": [0, 16.62133, 3.71249],
"pivot": [0, 18.25, 6.7],
"rotation": [-22.5, 0, 0],
"cubes": [
{"origin": [-2, 9.62133, 3.71249], "size": [4, 7, 4], "inflate": -0.001, "uv": [36, 19]}
{"origin": [-3, 15.75, 5.2], "size": [6, 5, 7], "uv": [39, 27]}
]
},
{
"name": "ponytail3",
"parent": "ponytail2",
"pivot": [0, 11.62133, 7.71249],
"pivot": [0, 17.75, 11.2],
"rotation": [52.5, 0, 0],
"cubes": [
{"origin": [-2, 9.62133, 7.71249], "size": [4, 2, 3], "inflate": -0.002, "uv": [21, 45]}
{"origin": [-1.5, 16.25, 10.7], "size": [3, 3, 5], "uv": [60, 0]}
]
},
{
"name": "hair2",
"parent": "head",
"pivot": [3.25, 16.625, -1.925],
"rotation": [-30, 0, 27.5]
"name": "arms",
"parent": "chest",
"pivot": [0, 7.5, 0]
},
{
"name": "hair3",
"parent": "hair2",
"pivot": [3.25, 16.625, -1.925],
"name": "arm_left",
"parent": "arms",
"pivot": [2, 7.5, 0],
"cubes": [
{"origin": [1.25, 16.625, -1.925], "size": [4, 6, 0], "uv": [48, 15]}
{"origin": [1, 6.5, -1.5], "size": [4, 2, 3], "uv": [14, 28]}
]
},
{
"name": "arm_left2",
"parent": "arm_left",
"pivot": [5, 8.5, 1],
"cubes": [
{"origin": [5, 6, -2], "size": [4, 3, 4], "inflate": 0.001, "uv": [16, 21]}
]
},
{
"name": "locator_hand_secondary",
"parent": "arm_left2",
"pivot": [8.5, 7.45, 0],
"rotation": [0, -90, 0],
"locators": {
"hand_secondary": [8.5, 7.45, 0]
}
},
{
"name": "fingers_left",
"parent": "arm_left2",
"pivot": [9, 7.25, -0.5]
},
{
"name": "finger_left",
"parent": "fingers_left",
"pivot": [9, 7.75, -0.75],
"rotation": [0, 12.5, 0],
"cubes": [
{"origin": [9, 7.75, -1.75], "size": [1, 1, 1], "inflate": 0.25, "uv": [0, 23]}
]
},
{
"name": "finger_left2",
"parent": "fingers_left",
"pivot": [9, 7.75, 0.75],
"rotation": [0, -12.5, 0],
"cubes": [
{"origin": [9, 7.75, 0.75], "size": [1, 1, 1], "inflate": 0.25, "uv": [12, 23]}
]
},
{
"name": "finger_left3",
"parent": "fingers_left",
"pivot": [9, 7.25, 0],
"cubes": [
{"origin": [9, 6.25, -0.5], "size": [1, 1, 1], "inflate": 0.25, "uv": [16, 23]}
]
},
{
"name": "arm_right",
"parent": "arms",
"pivot": [-2, 7.5, 0],
"cubes": [
{"origin": [-5, 6.5, -1.5], "size": [4, 2, 3], "uv": [0, 28], "mirror": true}
]
},
{
"name": "arm_right2",
"parent": "arm_right",
"pivot": [-5, 8.5, 1.5],
"cubes": [
{"origin": [-9, 6, -2], "size": [4, 3, 4], "inflate": 0.001, "uv": [0, 21], "mirror": true}
]
},
{
"name": "locator_hand_primary",
"parent": "arm_right2",
"pivot": [-8.5, 7.45, 0],
"rotation": [0, 90, 0],
"locators": {
"hand_primary": [-8.5, 7.45, 0]
}
},
{
"name": "fingers_right",
"parent": "arm_right2",
"pivot": [-9, 7.25, -0.5]
},
{
"name": "finger_right",
"parent": "fingers_right",
"pivot": [-9, 7.75, -0.75],
"rotation": [0, -12.5, 0],
"cubes": [
{"origin": [-10, 7.75, -1.75], "size": [1, 1, 1], "inflate": 0.25, "uv": [0, 21], "mirror": true}
]
},
{
"name": "finger_right2",
"parent": "fingers_right",
"pivot": [-9, 7.75, 0.75],
"rotation": [0, 12.5, 0],
"cubes": [
{"origin": [-10, 7.75, 0.75], "size": [1, 1, 1], "inflate": 0.25, "uv": [12, 21], "mirror": true}
]
},
{
"name": "finger_right3",
"parent": "fingers_right",
"pivot": [-9, 7.25, 0],
"cubes": [
{"origin": [-10, 6.25, -0.5], "size": [1, 1, 1], "inflate": 0.25, "uv": [16, 21], "mirror": true}
]
},
{
"name": "arm_hammer_right",
"parent": "arms",
"pivot": [-2, 7.5, 0]
},
{
"name": "arm_hammer_right2",
"parent": "arm_hammer_right",
"pivot": [-5, 8.5, 1.5]
},
{
"name": "hammer",
"parent": "arm_hammer_right2",
"pivot": [-10, 7.5, 0]
},
{
"name": "hammer2",
"parent": "hammer",
"pivot": [-10.05, 7.5, -11.25],
"cubes": [
{"origin": [-11, 6.5, -11.85], "size": [2, 2, 16], "inflate": -0.1, "uv": [91, 18]}
]
},
{
"name": "ball",
"parent": "hammer2",
"pivot": [-10, 7.5, -14.75],
"cubes": [
{"origin": [-11.5, 6, -14.75], "size": [3, 3, 3], "uv": [94, 27]},
{"origin": [-11.5, 6, -14.75], "size": [3, 3, 3], "inflate": 0.1, "uv": [112, 27]}
]
},
{
"name": "rattle",
"parent": "hammer2",
"pivot": [-10, 7.5, -15.25],
"cubes": [
{"origin": [-11.5, 6, -22.75], "size": [3, 3, 6], "uv": [84, 37]},
{"origin": [-10.5, 7, -16.75], "size": [1, 1, 2], "uv": [97, 23]},
{"origin": [-10.5, 6, -21.25], "size": [1, 1, 1], "inflate": 0.02, "pivot": [-10, 6.5, -20.75], "rotation": [0, -45, 0], "uv": [97, 40]},
{"origin": [-11, 6, -20.25], "size": [2, 1, 2], "inflate": 0.02, "pivot": [-10, 6.5, -19.25], "rotation": [0, -45, 0], "uv": [81, 38]},
{"origin": [-11, 6, -20.75], "size": [2, 1, 2], "inflate": 0.01, "uv": [114, 23]}
]
},
{
"name": "locator_item",
"parent": "rattle",
"pivot": [-10, 5.3, -19],
"locators": {
"item": {
"offset": [-10, 5.3, -19],
"rotation": [0, 135, 0]
}
}
},
{
"name": "plates",
"parent": "hammer2",
"pivot": [-10, 9.025, -20.275]
},
{
"name": "plate_top",
"parent": "plates",
"pivot": [-3.5, 9.525, -20.275],
"cubes": [
{"origin": [-4, 4.5, -20.26], "size": [6, 8, 0], "pivot": [-4, 10, -20.25], "rotation": [-90, -180, 0], "uv": [115, 46]},
{"origin": [0, -1.5, -20.26], "size": [4, 8, 0], "pivot": [-2, 4, -20.25], "rotation": [-90, -180, 0], "uv": [117, 37]},
{"origin": [8, 4.5, -20.26], "size": [0, 8, 6], "pivot": [2, 10, -20.25], "rotation": [-90, -180, 0], "uv": [115, 49]}
]
},
{
"name": "plate_middle",
"parent": "plates",
"pivot": [-6.5, 9.525, -21.775],
"cubes": [
{"origin": [-10, 4.5, -21.75], "size": [8, 9, 0], "pivot": [-8, 10, -21.75], "rotation": [-90, -180, 0], "uv": [85, 47]},
{"origin": [-10, 4.5, -30.75], "size": [8, 0, 6], "pivot": [-8, 10, -30.75], "rotation": [-90, -180, 0], "uv": [79, 57]}
]
},
{
"name": "plate_bottom",
"parent": "plates",
"pivot": [-16.5, 10.525, -20.775],
"cubes": [
{"origin": [-21, 4.5, -20.74], "size": [5, 8, 0], "pivot": [-16, 10, -20.75], "rotation": [-90, 180, 0], "uv": [103, 46]},
{"origin": [-24, -1.5, -20.74], "size": [4, 8, 0], "pivot": [-18, 4, -20.75], "rotation": [-90, 180, 0], "uv": [104, 37], "mirror": true},
{"origin": [-28, 4.5, -20.74], "size": [0, 8, 6], "pivot": [-22, 10, -20.75], "rotation": [-90, 180, 0], "uv": [102, 49], "mirror": true}
]
},
{
"name": "locator_physical",
"parent": "plate_bottom",
"pivot": [-16, 7, -19],
"locators": {
"physical": [-16, 7, -19]
}
},
{
"name": "bandage",
"parent": "plates",
"pivot": [-8, 10, -22.25],
"cubes": [
{"origin": [-10.75, 10.2, -23.25], "size": [2, 0, 6], "pivot": [-9.75, 13, -20.25], "rotation": [0, 45, 0], "uv": [74, 57]},
{"origin": [-10.75, 10.1, -23.25], "size": [2, 0, 6], "pivot": [-9.75, 13, -20.25], "rotation": [0, -55, 0], "uv": [69, 57]}
]
},
{
"name": "skirt",
"parent": "torso",
"pivot": [0, 3, 0]
},
{
"name": "skirt_left",
"parent": "skirt",
"pivot": [2.7, 3, -0.5],
"rotation": [0, 0, 30],
"cubes": [
{"origin": [2.7, 3, -2], "size": [3, 0, 3], "uv": [65, 60]}
]
},
{
"name": "skirt_right",
"parent": "skirt",
"pivot": [-2.7, 3, -0.5],
"rotation": [0, 0, -30],
"cubes": [
{"origin": [-5.7, 3, -2], "size": [3, 0, 3], "uv": [65, 56], "mirror": true}
]
},
{
"name": "legs",
"parent": "body",
"pivot": [-0.2, 4.5, 0]
},
{
"name": "leg_left",
"parent": "body",
"pivot": [1.25, 4, 0],
"parent": "legs",
"pivot": [1.55, 4, 0],
"cubes": [
{"origin": [0.25, 2, -1], "size": [2, 2, 2], "uv": [28, 50]}
{"origin": [0.05, 1.5, -1.5], "size": [3, 3, 3], "inflate": -0.25, "uv": [12, 33]}
]
},
{
"name": "leg_left2",
"parent": "leg_left",
"pivot": [1.25, 2, -1],
"pivot": [1.55, 1.7, -1.4],
"cubes": [
{"origin": [0.25, 0, -1], "size": [2, 2, 2], "inflate": 0.2, "uv": [50, 0]}
{"origin": [0.05, 0, -1.5], "size": [3, 2, 3], "uv": [12, 39]}
]
},
{
"name": "locator_foot_secondary",
"parent": "leg_left2",
"pivot": [1.6, 0.5, 0],
"rotation": [90, 0, 0],
"locators": {
"foot_secondary": [1.6, 0.5, 0]
}
},
{
"name": "leg_right",
"parent": "body",
"pivot": [-1.25, 4, 0],
"parent": "legs",
"pivot": [-1.55, 4, 0],
"cubes": [
{"origin": [-2.25, 2, -1], "size": [2, 2, 2], "uv": [20, 50]}
{"origin": [-3.05, 1.5, -1.5], "size": [3, 3, 3], "inflate": -0.25, "uv": [0, 33], "mirror": true}
]
},
{
"name": "leg_right2",
"parent": "leg_right",
"pivot": [-1.25, 2, -1],
"pivot": [-1.55, 1.7, -1.4],
"cubes": [
{"origin": [-2.25, 0, -1], "size": [2, 2, 2], "inflate": 0.2, "uv": [12, 32]}
{"origin": [-3.05, 0, -1.5], "size": [3, 2, 3], "uv": [0, 39], "mirror": true}
]
},
{
"name": "locator_foot_primary",
"parent": "leg_right2",
"pivot": [-1.6, 0.5, 0],
"rotation": [90, 0, 0],
"locators": {
"foot_primary": [-1.6, 0.5, 0]
}
}
]
}
@@ -1,305 +0,0 @@
{
"format_version": "1.12.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.tinkatuff_dot",
"texture_width": 64,
"texture_height": 64,
"visible_bounds_width": 3,
"visible_bounds_height": 2.5,
"visible_bounds_offset": [0, 0.75, 0]
},
"bones": [
{
"name": "tinkatuff",
"pivot": [0, 0, 0]
},
{
"name": "body",
"parent": "tinkatuff",
"pivot": [0, 6, 0]
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 4.25, 0],
"cubes": [
{"origin": [-2, 7.5, -1.5], "size": [4, 3, 3], "uv": [41, 41]},
{"origin": [-2.5, 3, -2], "size": [5, 5, 4], "uv": [36, 0]}
]
},
{
"name": "skirt_left",
"parent": "torso",
"pivot": [2.5, 3, 0],
"rotation": [0, 0, 45],
"cubes": [
{"origin": [2.5, 3, -1.5], "size": [3, 0, 3], "uv": [6, 15]}
]
},
{
"name": "skirt_right",
"parent": "torso",
"pivot": [-2.5, 3, 0],
"rotation": [0, 0, -45],
"cubes": [
{"origin": [-5.5, 3, -1.5], "size": [3, 0, 3], "uv": [0, 15]}
]
},
{
"name": "arm_left",
"parent": "torso",
"pivot": [2, 8, 0],
"cubes": [
{"origin": [1, 7, -1], "size": [4, 2, 2], "uv": [35, 47]}
]
},
{
"name": "arm_left2",
"parent": "arm_left",
"pivot": [5, 9, 1],
"cubes": [
{"origin": [5, 7, -1.5], "size": [4, 2, 3], "inflate": 0.001, "uv": [44, 35]}
]
},
{
"name": "finger_left",
"parent": "arm_left2",
"pivot": [9, 7.75, -0.5],
"rotation": [0, 12.5, 0],
"cubes": [
{"origin": [9, 7.75, -1.5], "size": [1, 1, 1], "uv": [33, 44]}
]
},
{
"name": "finger_left2",
"parent": "arm_left2",
"pivot": [9, 7.75, 0.5],
"rotation": [0, -12.5, 0],
"cubes": [
{"origin": [9, 7.75, 0.5], "size": [1, 1, 1], "uv": [40, 30]}
]
},
{
"name": "finger_left3",
"parent": "arm_left2",
"pivot": [9, 8, 0],
"cubes": [
{"origin": [9, 7, -0.5], "size": [1, 1, 1], "uv": [36, 30]}
]
},
{
"name": "arm_hammer_right",
"parent": "torso",
"pivot": [-2, 8, 0]
},
{
"name": "arm_hammer_right2",
"parent": "arm_hammer_right",
"pivot": [-5, 9, 1]
},
{
"name": "hammer",
"parent": "arm_hammer_right2",
"pivot": [-9.75, 8, 0]
},
{
"name": "hammer2",
"parent": "hammer",
"pivot": [-9.55, 7.9675, -9.0675],
"cubes": [
{"origin": [-11, 6.5, -20], "size": [3, 3, 6], "uv": [30, 9]},
{"origin": [-10.5, 6.475, -18], "size": [2, 0, 2], "pivot": [-9.5, 6.475, -17], "rotation": [0, 45, 0], "uv": [-1, 54]},
{"origin": [-11, 6.5, -12.5], "size": [3, 3, 3], "uv": [0, 47]},
{"origin": [-10, 7.5, -14.5], "size": [1, 1, 18], "inflate": 0.001, "uv": [0, 0]},
{"origin": [-15.5, 4.025, -18.525], "size": [12, 11, 0], "pivot": [-9.5, 9.525, -18.525], "rotation": [-90, -180, 0], "uv": [0, 36]},
{"origin": [-15, 6.53, -18.04], "size": [7, 7, 0], "pivot": [-11, 9.53, -18.04], "rotation": [90, -45, -180], "uv": [42, 56]},
{"origin": [-15.5, 3.5, -30.5], "size": [0, 8, 5], "pivot": [-9.5, 12.25, -22.775], "rotation": [90, 0, 0], "uv": [34, 31]},
{"origin": [-15.5, 3.5, -30.5], "size": [3, 8, 0], "pivot": [-9.5, 12.25, -22.775], "rotation": [90, 0, 0], "uv": [47, 47]},
{"origin": [-7.5, 2.5, -30.5], "size": [4, 9, 0], "pivot": [-9.5, 12.25, -22.775], "rotation": [90, 0, 0], "uv": [12, 47]},
{"origin": [-3.5, 2.525, -20.025], "size": [0, 9, 5], "pivot": [-3.5, 7.025, -17.525], "rotation": [90, 180, 0], "uv": [24, 31]},
{"origin": [-13.5, 12.5, -29.5], "size": [8, 1, 0], "pivot": [-9.5, 12.25, -22.775], "rotation": [90, 0, 0], "uv": [0, 7]},
{"origin": [-13.5, 7.525, -26.025], "size": [8, 0, 4], "pivot": [-9.5, 7.525, -24.025], "rotation": [90, 180, 0], "uv": [17, 19]}
]
},
{
"name": "arm_right",
"parent": "torso",
"pivot": [-2, 8, 0],
"cubes": [
{"origin": [-5, 7, -1], "size": [4, 2, 2], "uv": [0, 32]}
]
},
{
"name": "arm_right2",
"parent": "arm_right",
"pivot": [-5, 9, 1],
"cubes": [
{"origin": [-9, 7, -1.5], "size": [4, 2, 3], "inflate": 0.001, "uv": [44, 30]}
]
},
{
"name": "finger_right",
"parent": "arm_right2",
"pivot": [-9, 7.75, -0.5],
"rotation": [0, -12.5, 0],
"cubes": [
{"origin": [-10, 7.75, -1.5], "size": [1, 1, 1], "uv": [36, 2]}
]
},
{
"name": "finger_right2",
"parent": "arm_right2",
"pivot": [-9, 7.75, 0.5],
"rotation": [0, 12.5, 0],
"cubes": [
{"origin": [-10, 7.75, 0.5], "size": [1, 1, 1], "uv": [36, 0]}
]
},
{
"name": "finger_right3",
"parent": "arm_right2",
"pivot": [-9, 8, 0],
"cubes": [
{"origin": [-10, 7, -0.5], "size": [1, 1, 1], "uv": [10, 32]}
]
},
{
"name": "head",
"parent": "torso",
"pivot": [0, 9, 0.5],
"cubes": [
{"origin": [-3.5, 9, -3.5], "size": [7, 6, 7], "uv": [0, 19]},
{"origin": [-4, 17.30092, -3.63266], "size": [8, 0, 8], "pivot": [0, 13.80092, 0.36734], "rotation": [-7.5, 0, 0], "uv": [12, 0]},
{"origin": [4, 10.30092, -3.63266], "size": [0, 7, 8], "pivot": [0, 13.80092, 0.36734], "rotation": [-7.5, 0, 0], "uv": [20, 0]},
{"origin": [-4, 10.30092, 4.36734], "size": [8, 7, 0], "pivot": [0, 13.80092, 0.36734], "rotation": [-7.5, 0, 0], "uv": [0, 0]},
{"origin": [-4, 11.30092, -3.63266], "size": [8, 6, 0], "pivot": [0, 13.80092, 0.36734], "rotation": [-7.5, 0, 0], "uv": [42, 9]},
{"origin": [-4, 10.30092, -3.63266], "size": [0, 7, 8], "pivot": [0, 13.80092, 0.36734], "rotation": [-7.5, 0, 0], "uv": [0, 0]}
]
},
{
"name": "eye_left",
"parent": "head",
"pivot": [2.25, 12.25, -3.01],
"rotation": [0, 0, -7.5],
"cubes": [
{"origin": [1.75, 11.25, -3.51], "size": [1, 2, 1], "uv": [21, 23]}
]
},
{
"name": "eyelid_left",
"parent": "eye_left",
"pivot": [2.25, 12.25, -2.91],
"cubes": [
{"origin": [1.75, 11.25, -3.41], "size": [1, 2, 1], "inflate": 0.01, "uv": [26, 15]}
]
},
{
"name": "eye_right",
"parent": "head",
"pivot": [-2.25, 12.25, -3.01],
"rotation": [0, 0, 7.5],
"cubes": [
{"origin": [-2.75, 11.25, -3.51], "size": [1, 2, 1], "uv": [0, 21]}
]
},
{
"name": "eyelid_right",
"parent": "eye_right",
"pivot": [-2.25, 12.25, -2.91],
"cubes": [
{"origin": [-2.75, 11.25, -3.41], "size": [1, 2, 1], "inflate": 0.01, "uv": [3, 23]}
]
},
{
"name": "mouth_open",
"parent": "head",
"pivot": [0, 10.5, -3.41],
"cubes": [
{"origin": [-1.5, 9.5, -3.41], "size": [3, 2, 0], "uv": [20, 15]}
]
},
{
"name": "mouth_closed",
"parent": "head",
"pivot": [0, 10.5, -3.51],
"cubes": [
{"origin": [-1.5, 9.5, -3.51], "size": [3, 2, 0], "uv": [0, 19]}
]
},
{
"name": "ponytail",
"parent": "head",
"pivot": [0, 16.81524, 1.82582],
"rotation": [2.5, 0, 0],
"cubes": [
{"origin": [-2, 16.62133, -0.28751], "size": [4, 4, 8], "uv": [20, 24]}
]
},
{
"name": "ponytail2",
"parent": "ponytail",
"pivot": [0, 16.62133, 3.71249],
"cubes": [
{"origin": [-2, 9.62133, 3.71249], "size": [4, 7, 4], "inflate": -0.001, "uv": [36, 19]}
]
},
{
"name": "ponytail3",
"parent": "ponytail2",
"pivot": [0, 11.62133, 7.71249],
"cubes": [
{"origin": [-2, 9.62133, 7.71249], "size": [4, 2, 3], "inflate": -0.002, "uv": [21, 45]}
]
},
{
"name": "hair2",
"parent": "head",
"pivot": [3.25, 16.625, -1.925],
"rotation": [-30, 0, 27.5]
},
{
"name": "hair3",
"parent": "hair2",
"pivot": [3.25, 16.625, -1.925],
"cubes": [
{"origin": [1.25, 16.625, -1.925], "size": [4, 6, 0], "uv": [48, 15]}
]
},
{
"name": "leg_left",
"parent": "body",
"pivot": [1.25, 4, 0],
"cubes": [
{"origin": [0.25, 2, -1], "size": [2, 2, 2], "uv": [28, 50]}
]
},
{
"name": "leg_left2",
"parent": "leg_left",
"pivot": [1.25, 2, -1],
"cubes": [
{"origin": [0.25, 0, -1], "size": [2, 2, 2], "inflate": 0.2, "uv": [50, 0]}
]
},
{
"name": "leg_right",
"parent": "body",
"pivot": [-1.25, 4, 0],
"cubes": [
{"origin": [-2.25, 2, -1], "size": [2, 2, 2], "uv": [20, 50]}
]
},
{
"name": "leg_right2",
"parent": "leg_right",
"pivot": [-1.25, 2, -1],
"cubes": [
{"origin": [-2.25, 0, -1], "size": [2, 2, 2], "inflate": 0.2, "uv": [12, 32]}
]
}
]
}
]
}

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